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 unsigned int MAX_REGS;
44 #define MAXSOURCEFILESLIST 8
45 char sourcefileslist[MAXSOURCEFILESLIST][1024];
46 int currentsourcefile;
49 void QCC_PR_ResetErrorScope(void);
56 float *qcc_pr_globals;
57 unsigned int numpr_globals;
62 QCC_dstatement_t *statements;
64 int *statement_linenums;
66 QCC_dfunction_t *functions;
69 QCC_ddef_t *qcc_globals;
75 //typedef char PATHSTRING[MAX_DATA_PATH];
77 PATHSTRING *precache_sounds;
78 int *precache_sounds_block;
79 int *precache_sounds_used;
82 PATHSTRING *precache_textures;
83 int *precache_textures_block;
84 int *precache_textures_block;
87 PATHSTRING *precache_models;
88 int *precache_models_block;
89 int *precache_models_used;
92 PATHSTRING *precache_files;
93 int *precache_files_block;
96 extern int numCompilerConstants;
97 hashtable_t compconstantstable;
98 hashtable_t globalstable;
99 hashtable_t localstable;
103 hashtable_t floatconstdefstable;
104 hashtable_t stringconstdefstable;
105 hashtable_t stringconstdefstable_trans;
106 extern int dotranslate_count;
108 pbool qccwarningdisabled[WARN_MAX];
110 qcc_targetformat_t qcc_targetformat;
114 QCC_type_t *qcc_typeinfo;
124 {"Q302", WARN_NOTREFERENCED},
125 // {"", WARN_NOTREFERENCEDCONST},
126 // {"", WARN_CONFLICTINGRETURNS},
127 {"Q105", WARN_TOOFEWPARAMS},
128 {"Q101", WARN_TOOMANYPARAMS},
129 // {"", WARN_UNEXPECTEDPUNCT},
130 {"Q106", WARN_ASSIGNMENTTOCONSTANT},
131 {"Q203", WARN_MISSINGRETURNVALUE},
132 {"Q204", WARN_WRONGRETURNTYPE},
133 {"Q205", WARN_POINTLESSSTATEMENT},
134 {"Q206", WARN_MISSINGRETURN},
135 {"Q207", WARN_DUPLICATEDEFINITION},
136 {"Q100", WARN_PRECOMPILERMESSAGE},
137 // {"", WARN_STRINGTOOLONG},
138 // {"", WARN_BADTARGET},
139 {"Q120", WARN_BADPRAGMA},
140 // {"", WARN_HANGINGSLASHR},
141 // {"", WARN_NOTDEFINED},
142 // {"", WARN_SWITCHTYPEMISMATCH},
143 // {"", WARN_CONFLICTINGUNIONMEMBER},
144 // {"", WARN_KEYWORDDISABLED},
145 // {"", WARN_ENUMFLAGS_NOTINTEGER},
146 // {"", WARN_ENUMFLAGS_NOTBINARY},
147 // {"", WARN_CASEINSENSATIVEFRAMEMACRO},
148 {"Q111", WARN_DUPLICATELABEL},
149 {"Q201", WARN_ASSIGNMENTINCONDITIONAL},
150 {"F300", WARN_DEADCODE},
154 int QCC_WarningForName(char *name)
157 for (i = 0; warningnames[i].name; i++)
159 if (!stricmp(name, warningnames[i].name))
160 return warningnames[i].index;
165 optimisations_t optimisations[] =
167 //level 0 = no optimisations
168 //level 1 = size optimisations
169 //level 2 = speed optimisations
170 //level 3 = dodgy optimisations.
171 //level 4 = experimental...
173 {&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."},
174 {&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."},
175 {&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."},
176 {&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."},
177 {&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."},
178 {&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."},
179 {&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."},
180 {&opt_locals, "l", 1, FLAG_KILLSDEBUGGERS, "locals", "Strips out local names and definitions. This makes it REALLY hard to decompile"},
181 {&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."},
182 {&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."},
183 {&opt_unreferenced, "u", 1, FLAG_ASDEFAULT, "unreferenced", "Removes the entries of unreferenced variables. Doesn't make a difference in well maintained code."},
184 {&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."},
185 {&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"},
186 {&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)."},
187 {&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."},
188 {&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."},
189 // {&opt_comexprremoval, "cer", 4, 0, "expression_removal", "Eliminate common sub-expressions"}, //this would be too hard...
190 {&opt_stripfunctions, "sf", 4, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games. This can affect FTE_MULTIPROGS."},
191 {&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."},
192 {&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."},
196 #define defaultkeyword FLAG_HIDDENINGUI|FLAG_ASDEFAULT|FLAG_MIDCOMPILE
197 #define nondefaultkeyword FLAG_HIDDENINGUI|0|FLAG_MIDCOMPILE
198 //global to store useage to, flags, codename, human-readable name, help text
199 compiler_flag_t compiler_flag[] = {
201 {&keyword_asm, defaultkeyword, "asm", "Keyword: asm", "Disables the 'asm' keyword. Use the writeasm flag to see an example of the asm."},
202 {&keyword_break, defaultkeyword, "break", "Keyword: break", "Disables the 'break' keyword."},
203 {&keyword_case, defaultkeyword, "case", "Keyword: case", "Disables the 'case' keyword."},
204 {&keyword_class, defaultkeyword, "class", "Keyword: class", "Disables the 'class' keyword."},
205 {&keyword_const, defaultkeyword, "const", "Keyword: const", "Disables the 'const' keyword."},
206 {&keyword_continue, defaultkeyword, "continue", "Keyword: continue", "Disables the 'continue' keyword."},
207 {&keyword_default, defaultkeyword, "default", "Keyword: default", "Disables the 'default' keyword."},
208 {&keyword_entity, defaultkeyword, "entity", "Keyword: entity", "Disables the 'entity' keyword."},
209 {&keyword_enum, defaultkeyword, "enum", "Keyword: enum", "Disables the 'enum' keyword."}, //kinda like in c, but typedef not supported.
210 {&keyword_enumflags, defaultkeyword, "enumflags", "Keyword: enumflags", "Disables the 'enumflags' keyword."}, //like enum, but doubles instead of adds 1.
211 {&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
212 {&keyword_float, defaultkeyword, "float", "Keyword: float", "Disables the 'float' keyword. (Disables the float keyword without 'local' preceeding it)"},
213 {&keyword_for, defaultkeyword, "for", "Keyword: for", "Disables the 'for' keyword. Syntax: for(assignment; while; increment) {codeblock;}"},
214 {&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."},
215 {&keyword_int, defaultkeyword, "int", "Keyword: int", "Disables the 'int' keyword."},
216 {&keyword_integer, defaultkeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."},
217 {&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't strip it.
218 {&keyword_nosave, defaultkeyword, "nosave", "Keyword: nosave", "Disables the 'nosave' keyword."}, //don't write the def to the output.
219 {&keyword_shared, defaultkeyword, "shared", "Keyword: shared", "Disables the 'shared' keyword."}, //mark global to be copied over when progs changes (part of FTE_MULTIPROGS)
220 {&keyword_state, nondefaultkeyword,"state", "Keyword: state", "Disables the 'state' keyword."},
221 {&keyword_optional, defaultkeyword,"optional", "Keyword: optional", "Disables the 'optional' keyword."},
222 {&keyword_string, defaultkeyword, "string", "Keyword: string", "Disables the 'string' keyword."},
223 {&keyword_struct, defaultkeyword, "struct", "Keyword: struct", "Disables the 'struct' keyword."},
224 {&keyword_switch, defaultkeyword, "switch", "Keyword: switch", "Disables the 'switch' keyword."},
225 {&keyword_thinktime, nondefaultkeyword,"thinktime", "Keyword: thinktime", "Disables the 'thinktime' keyword which is used in HexenC"},
226 {&keyword_typedef, defaultkeyword, "typedef", "Keyword: typedef", "Disables the 'typedef' keyword."}, //fixme
227 {&keyword_union, defaultkeyword, "union", "Keyword: union", "Disables the 'union' keyword."}, //you surly know what a union is!
228 {&keyword_var, defaultkeyword, "var", "Keyword: var", "Disables the 'var' keyword."},
229 {&keyword_vector, defaultkeyword, "vector", "Keyword: vector", "Disables the 'vector' keyword."},
233 {&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."},
234 {&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)
235 {&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.
236 {&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)
237 {&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.
238 {&flag_iffloat, FLAG_MIDCOMPILE,"iffloat","if(-0.0) fix","Fixes certain floating point logic."},
239 {&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.
240 {&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
241 {&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.
242 {&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"},
243 {&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))"},
244 {&flag_msvcstyle, FLAG_MIDCOMPILE,"msvcstyle", "MSVC-style errors", "Generates warning and error messages in a format that msvc understands, to facilitate ide integration."},
245 {&flag_filetimes, 0, "filetimes", "Check Filetimes", "Recompiles the progs only if the file times are modified."},
246 {&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."},
247 {&flag_assume_integer, FLAG_MIDCOMPILE,"assumeint", "Assume Integers", "Numerical constants are assumed to be integers, instead of floats."},
248 {&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
249 {&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
250 {&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
255 qcc_targetformat_t target;
258 {QCF_STANDARD, "standard"},
259 {QCF_STANDARD, "q1"},
260 {QCF_STANDARD, "quakec"},
261 {QCF_HEXEN2, "hexen2"},
265 {QCF_KK7, "bigprogs"},
266 {QCF_KK7, "version7"},
269 {QCF_DARKPLACES,"darkplaces"},
270 {QCF_DARKPLACES,"dp"},
271 {QCF_QTEST, "qtest"},
279 Runs qbsp and light on all of the models with a .bsp extension
282 int QCC_CheckParm (char *check);
284 void QCC_BspModels (void)
295 p = QCC_CheckParm ("-bspmodels");
299 QCC_Error (ERR_BADPARMS, "-bspmodels must preceed a game directory");
300 gamedir = myargv[p+1];
302 for (i=0 ; i<nummodels ; i++)
304 m = precache_models[i];
305 if (strcmp(m+strlen(m)-4, ".bsp"))
308 name[strlen(m)-4] = 0;
309 sprintf (cmd, "qbsp %s/%s ; light -extra %s/%s", gamedir, name, gamedir, name);
310 result = system (cmd); // do something with the result
313 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);
318 // CopyString returns an offset from the string heap
319 int QCC_CopyString (char *str)
329 if (opt_noduplicatestrings)
331 for (s = strings; s < strings+strofs; s++)
334 optres_noduplicatestrings += strlen(str);
340 strcpy (strings+strofs, str);
341 strofs += strlen(str)+1;
345 int QCC_CopyDupBackString (char *str)
350 for (s = strings+strofs-1; s>strings ; s--)
355 strcpy (strings+strofs, str);
356 strofs += strlen(str)+1;
360 void QCC_PrintStrings (void)
364 for (i=0 ; i<strofs ; i += l)
366 l = strlen(strings+i) + 1;
368 for (j=0 ; j<l ; j++)
370 if (strings[i+j] == '\n')
376 putchar (strings[i+j]);
383 /*void QCC_PrintFunctions (void)
388 for (i=0 ; i<numfunctions ; i++)
391 printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
392 for (j=0 ; j<d->numparms ; j++)
393 printf ("%i ",d->parm_size[j]);
398 void QCC_PrintFields (void)
403 for (i=0 ; i<numfielddefs ; i++)
406 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
410 void QCC_PrintGlobals (void)
415 for (i=0 ; i<numglobaldefs ; i++)
418 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
422 int encode(int len, int method, char *in, int handle);
423 int WriteSourceFiles(int h, dprograms_t *progs, pbool sourceaswell)
425 includeddatafile_t *idf;
426 qcc_cachedsourcefile_t *f;
431 for (f = qcc_sourcefile; f ; f=f->next)
433 if (f->type == FT_CODE && !sourceaswell)
436 SafeWrite(h, f->filename, strlen(f->filename)+1);
437 i = PRLittleLong(f->size);
438 SafeWrite(h, &i, sizeof(int));
440 i = PRLittleLong(encrpytmode);
441 SafeWrite(h, &i, sizeof(int));
444 for (i = 0; i < f->size; i++)
447 SafeWrite(h, f->file, f->size);
450 for (f = qcc_sourcefile,num=0; f ; f=f->next)
452 if (f->type == FT_CODE && !sourceaswell)
459 idf = qccHunkAlloc(sizeof(includeddatafile_t)*num);
460 for (f = qcc_sourcefile,num=0; f ; f=f->next)
462 if (f->type == FT_CODE && !sourceaswell)
465 strcpy(idf[num].filename, f->filename);
466 idf[num].size = f->size;
468 idf[num].compmethod = 2;
470 idf[num].compmethod = 1;
472 idf[num].ofs = SafeSeek(h, 0, SEEK_CUR);
473 idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h);
477 ofs = SafeSeek(h, 0, SEEK_CUR);
478 SafeWrite(h, &num, sizeof(int));
479 SafeWrite(h, idf, sizeof(includeddatafile_t)*num);
481 qcc_sourcefile = NULL;
486 void QCC_InitData (void)
488 static char parmname[12][MAX_PARMS];
489 static temp_t ret_temp;
492 qcc_sourcefile = NULL;
500 memset(&ret_temp, 0, sizeof(ret_temp));
502 def_ret.ofs = OFS_RETURN;
503 def_ret.name = "return";
504 def_ret.temp = &ret_temp;
505 def_ret.constant = false;
507 ret_temp.ofs = def_ret.ofs;
508 ret_temp.scope = NULL;
510 ret_temp.next = NULL;
511 for (i=0 ; i<MAX_PARMS ; i++)
513 def_parms[i].temp = NULL;
514 def_parms[i].type = NULL;
515 def_parms[i].ofs = OFS_PARM0 + 3*i;
516 def_parms[i].name = parmname[i];
517 sprintf(parmname[i], "parm%i", i);
521 int WriteBodylessFuncs (int handle)
525 for (d=pr.def_head.next ; d ; d=d->next)
527 if (d->type->type == ev_function && !d->scope)// function parms are ok
529 if (!(d->initialized & 1) && d->references>0)
531 SafeWrite(handle, d->name, strlen(d->name)+1);
540 //marshalled locals remaps all the functions to use the range MAX_REGS onwards for the offset to their locals.
541 //this function remaps all the locals back into the function.
542 void QCC_UnmarshalLocals(void)
552 for (def = pr.def_head.next ; def ; def = def->next)
554 if (def->ofs >= MAX_REGS) //unmap defs.
556 def->ofs = def->ofs + ofs - MAX_REGS;
562 for (i = 0; i < numfunctions; i++)
564 if (functions[i].parm_start == MAX_REGS)
565 functions[i].parm_start = ofs;
568 QCC_RemapOffsets(0, numstatements, MAX_REGS, MAX_REGS + maxo-numpr_globals + 3, ofs);
570 numpr_globals = maxo+3;
571 if (numpr_globals > MAX_REGS)
572 QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals are in use to unmarshal all locals");
575 printf("Total of %i marshalled globals\n", maxo-ofs);
578 CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
579 pbool QCC_WriteData (int crc)
581 char element[MAX_NAME];
582 QCC_def_t *def, *comp_x, *comp_y, *comp_z;
587 pbool debugtarget = false;
589 int outputsttype = PST_DEFAULT;
590 pbool warnedunref = false;
592 if (numstatements==1 && numfunctions==1 && numglobaldefs==1 && numfielddefs==1)
594 printf("nothing to write\n");
598 progs.blockscompressed=0;
600 if (numstatements > MAX_STATEMENTS)
601 QCC_Error(ERR_TOOMANYSTATEMENTS, "Too many statements - %i\nAdd \"MAX_STATEMENTS\" \"%i\" to qcc.cfg", numstatements, (numstatements+32768)&~32767);
603 if (strofs > MAX_STRINGS)
604 QCC_Error(ERR_TOOMANYSTRINGS, "Too many strings - %i\nAdd \"MAX_STRINGS\" \"%i\" to qcc.cfg", strofs, (strofs+32768)&~32767);
606 QCC_UnmarshalLocals();
608 switch (qcc_targetformat)
613 printf("Warning: There are some functions without bodies.\n");
615 if (numpr_globals > 65530 )
617 printf("Forcing target to FTE32 due to numpr_globals\n");
618 outputsttype = PST_FTE32;
620 else if (qcc_targetformat == QCF_HEXEN2)
622 printf("Progs execution requires a Hexen2 compatible engine\n");
627 if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on original executors?
628 printf("An enhanced executor will be required (FTE/QF/KK)\n");
630 printf("Progs should run on any Quake executor\n");
634 qcc_targetformat = QCF_FTE;
638 if (qcc_targetformat == QCF_FTEDEBUG)
641 if (numpr_globals > 65530)
643 printf("Using 32 bit target due to numpr_globals\n");
644 outputsttype = PST_FTE32;
647 if (qcc_targetformat == QCF_DARKPLACES)
651 //compression of blocks?
652 if (compressoutput) progs.blockscompressed |=1; //statements
653 if (compressoutput) progs.blockscompressed |=2; //defs
654 if (compressoutput) progs.blockscompressed |=4; //fields
655 if (compressoutput) progs.blockscompressed |=8; //functions
656 if (compressoutput) progs.blockscompressed |=16; //strings
657 if (compressoutput) progs.blockscompressed |=32; //globals
658 if (compressoutput) progs.blockscompressed |=64; //line numbers
659 if (compressoutput) progs.blockscompressed |=128; //types
660 //include a type block?
662 if (types && sizeof(char *) != sizeof(string_t))
664 //qcc_typeinfo_t has a char* inside it, which changes size
665 printf("AMD64 builds cannot write typeinfo structures\n");
671 if (qcc_targetformat == QCF_DARKPLACES)
672 printf("DarkPlaces or FTE will be required\n");
674 printf("An FTE executor will be required\n");
679 printf("Warning: There are some functions without bodies.\n");
680 if (numpr_globals > 65530)
681 printf("Warning: Saving is not supported. Ensure all engine read fields and globals are defined early on.\n");
683 printf("A KK compatible executor will be required (FTE/KK)\n");
684 outputsttype = PST_KKQWSV;
687 printf("Compiled QTest progs will most likely not work at all. YOU'VE BEEN WARNED!\n");
688 outputsttype = PST_QTEST;
691 Sys_Error("invalid progs type chosen!");
694 //part of how compilation works. This def is always present, and never used.
695 def = QCC_PR_GetDef(NULL, "end_sys_globals", NULL, false, 0, false);
699 def = QCC_PR_GetDef(NULL, "end_sys_fields", NULL, false, 0, false);
703 for (def = pr.def_head.next ; def ; def = def->next)
705 if ((def->type->type == ev_struct || def->type->type == ev_union || def->arraysize) && def->deftail)
709 while (d != def->deftail)
713 d->references += def->references;
714 def->references += h;
717 if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector))
718 { //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x
719 sprintf(element, "%s_x", def->name);
720 comp_x = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
721 sprintf(element, "%s_y", def->name);
722 comp_y = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
723 sprintf(element, "%s_z", def->name);
724 comp_z = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
727 if (comp_x && comp_y && comp_z)
729 h += comp_x->references;
730 h += comp_y->references;
731 h += comp_z->references;
733 if (!def->references)
734 if (!comp_x->references || !comp_y->references || !comp_z->references) //one of these vars is useless...
743 comp_x->references = h;
745 comp_y->references = h;
747 comp_z->references = h;
750 if (def->references<=0)
752 int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED;
753 if (QCC_PR_Warning(wt, strings + def->s_file, def->s_line, "%s no references", def->name))
757 QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "You can use the noref prefix or pragma to silence this message.");
762 if (opt_unreferenced && def->type->type != ev_field)
764 optres_unreferenced++;
769 if (def->type->type == ev_function)
771 if (opt_function_names && functions[G_FUNCTION(def->ofs)].first_statement<0)
773 optres_function_names++;
776 if (!def->timescalled)
778 if (def->references<=1)
779 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);
781 // QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called", def->name);
783 if (opt_stripfunctions && def->timescalled >= def->references-1) //make sure it's not copied into a different var.
784 { //if it ever does self.think then it could be needed for saves.
785 optres_stripfunctions++; //if it's only ever called explicitly, the engine doesn't need to know.
789 // df = &functions[numfunctions];
793 else if (def->type->type == ev_field && def->constant)
795 if (numfielddefs >= MAX_FIELDS)
796 QCC_PR_ParseError(0, "Too many fields. Limit is %u\n", MAX_FIELDS);
797 dd = &fields[numfielddefs];
799 dd->type = def->type->aux_type->type;
800 dd->s_name = QCC_CopyString (def->name);
801 dd->ofs = G_INT(def->ofs);
803 else if ((def->scope||def->constant) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
805 if (opt_constant_names)
807 if (def->type->type == ev_string)
808 optres_constant_names_strings += strlen(def->name);
810 optres_constant_names += strlen(def->name);
815 // if (!def->saved && def->type->type != ev_string)
817 dd = &qcc_globals[numglobaldefs];
821 dd->type = def->type-qcc_typeinfo;
823 dd->type = def->type->type;
824 #ifdef DEF_SAVEGLOBAL
825 if ( def->saved && ((!def->initialized || def->type->type == ev_function)
826 // && def->type->type != ev_function
827 && def->type->type != ev_field
828 && def->scope == NULL))
830 dd->type |= DEF_SAVEGLOBAL;
834 dd->type |= DEF_SHARED;
836 if (opt_locals && (def->scope || !strcmp(def->name, "IMMEDIATE")))
839 optres_locals += strlen(def->name);
842 dd->s_name = QCC_CopyString (def->name);
846 for (i = 0; i < numglobaldefs; i++)
848 dd = &qcc_globals[i];
849 if (!(dd->type & DEF_SAVEGLOBAL)) //only warn about saved ones.
852 for (h = 0; h < numglobaldefs; h++)
856 if (dd->ofs == qcc_globals[h].ofs)
858 if ((dd->type&~DEF_SAVEGLOBAL) != (qcc_globals[h].type&~DEF_SAVEGLOBAL))
860 if (!(((dd->type&~DEF_SAVEGLOBAL) == ev_vector && (qcc_globals[h].type&~DEF_SAVEGLOBAL) == ev_float) ||
861 ((dd->type&~DEF_SAVEGLOBAL) == ev_struct || (dd->type&~DEF_SAVEGLOBAL) == ev_union)))
862 QCC_PR_Warning(0, NULL, 0, "Mismatched union global types (%s and %s)", strings+dd->s_name, strings+qcc_globals[h].s_name);
864 //remove the saveglobal flag on the duplicate globals.
865 qcc_globals[h].type &= ~DEF_SAVEGLOBAL;
869 for (i = 1; i < numfielddefs; i++)
873 if (dd->type == ev_vector) //just ignore vectors.
876 for (h = 1; h < numfielddefs; h++)
880 if (dd->ofs == fields[h].ofs)
882 if (dd->type != fields[h].type)
884 if (fields[h].type != ev_vector)
886 QCC_PR_Warning(0, NULL, 0, "Mismatched union field types (%s and %s)", strings+dd->s_name, strings+fields[h].s_name);
893 if (numglobaldefs > MAX_GLOBALS)
894 QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals - %i\nAdd \"MAX_GLOBALS\" \"%i\" to qcc.cfg", numglobaldefs, (numglobaldefs+32768)&~32767);
897 for (i = 0; i < nummodels; i++)
899 if (!precache_models_used[i])
900 QCC_PR_Warning(WARN_EXTRAPRECACHE, NULL, 0, "Model %s was precached but not directly used", precache_models[i]);
901 else if (!precache_models_block[i])
902 QCC_PR_Warning(WARN_NOTPRECACHED, NULL, 0, "Model %s was used but not precached", precache_models[i]);
908 strofs = (strofs+3)&~3;
912 printf ("%6i strofs (of %i)\n", strofs, MAX_STRINGS);
913 printf ("%6i numstatements (of %i)\n", numstatements, MAX_STATEMENTS);
914 printf ("%6i numfunctions (of %i)\n", numfunctions, MAX_FUNCTIONS);
915 printf ("%6i numglobaldefs (of %i)\n", numglobaldefs, MAX_GLOBALS);
916 printf ("%6i numfielddefs (%i unique) (of %i)\n", numfielddefs, pr.size_fields, MAX_FIELDS);
917 printf ("%6i numpr_globals (of %i)\n", numpr_globals, MAX_REGS);
921 strcpy(destfile, "progs.dat");
923 printf("Writing %s\n", destfile);
924 h = SafeOpenWrite (destfile, 2*1024*1024);
925 SafeWrite (h, &progs, sizeof(progs));
926 SafeWrite (h, "\r\n\r\n", 4);
927 SafeWrite (h, QCC_copyright, strlen(QCC_copyright)+1);
928 SafeWrite (h, "\r\n\r\n", 4);
929 while(SafeSeek (h, 0, SEEK_CUR) & 3)//this is a lame way to do it
931 SafeWrite (h, "\0", 1);
934 progs.ofs_strings = SafeSeek (h, 0, SEEK_CUR);
935 progs.numstrings = strofs;
937 if (progs.blockscompressed&16)
939 SafeWrite (h, &len, sizeof(int)); //save for later
940 len = QC_encode(progfuncs, strofs*sizeof(char), 2, (char *)strings, h); //write
941 i = SafeSeek (h, 0, SEEK_CUR);
942 SafeSeek(h, progs.ofs_strings, SEEK_SET);//seek back
943 len = PRLittleLong(len);
944 SafeWrite (h, &len, sizeof(int)); //write size.
945 SafeSeek(h, i, SEEK_SET);
948 SafeWrite (h, strings, strofs);
950 progs.ofs_statements = SafeSeek (h, 0, SEEK_CUR);
951 progs.numstatements = numstatements;
953 if (qcc_targetformat == QCF_HEXEN2)
955 for (i=0 ; i<numstatements ; i++)
957 if (statements[i].op >= OP_CALL1 && statements[i].op <= OP_CALL8)
958 QCC_Error(ERR_BADTARGETSWITCH, "Target switching produced incompatible instructions");
959 else if (statements[i].op >= OP_CALL1H && statements[i].op <= OP_CALL8H)
960 statements[i].op = statements[i].op - OP_CALL1H + OP_CALL1;
964 for (i=0 ; i<numstatements ; i++)
970 for (i=0 ; i<numstatements ; i++)
972 statements[i].op = PRLittleLong/*PRLittleShort*/(statements[i].op);
973 statements[i].a = PRLittleLong/*PRLittleShort*/(statements[i].a);
974 statements[i].b = PRLittleLong/*PRLittleShort*/(statements[i].b);
975 statements[i].c = PRLittleLong/*PRLittleShort*/(statements[i].c);
978 if (progs.blockscompressed&1)
980 SafeWrite (h, &len, sizeof(int)); //save for later
981 len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement32_t), 2, (char *)statements, h); //write
982 i = SafeSeek (h, 0, SEEK_CUR);
983 SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
984 len = PRLittleLong(len);
985 SafeWrite (h, &len, sizeof(int)); //write size.
986 SafeSeek(h, i, SEEK_SET);
989 SafeWrite (h, statements, numstatements*sizeof(QCC_dstatement32_t));
992 #define qtst ((qtest_statement_t*) statements)
993 for (i=0 ; i<numstatements ; i++) // scale down from 16-byte internal to 12-byte qtest
995 QCC_dstatement_t stmt = statements[i];
996 qtst[i].line = 0; // no line support
997 qtst[i].op = PRLittleShort((unsigned short)stmt.op);
999 qtst[i].a = PRLittleShort((short)stmt.a);
1001 qtst[i].a = (unsigned short)PRLittleShort((unsigned short)stmt.a);
1003 qtst[i].b = PRLittleShort((short)stmt.b);
1005 qtst[i].b = (unsigned short)PRLittleShort((unsigned short)stmt.b);
1007 qtst[i].c = PRLittleShort((short)stmt.c);
1009 qtst[i].c = (unsigned short)PRLittleShort((unsigned short)stmt.c);
1013 SafeWrite (h, qtst, numstatements*sizeof(qtest_statement_t));
1017 #define statements16 ((QCC_dstatement16_t*) statements)
1018 for (i=0 ; i<numstatements ; i++) //resize as we go - scaling down
1020 statements16[i].op = PRLittleShort((unsigned short)statements[i].op);
1021 if (statements[i].a < 0)
1022 statements16[i].a = PRLittleShort((short)statements[i].a);
1024 statements16[i].a = (unsigned short)PRLittleShort((unsigned short)statements[i].a);
1025 if (statements[i].b < 0)
1026 statements16[i].b = PRLittleShort((short)statements[i].b);
1028 statements16[i].b = (unsigned short)PRLittleShort((unsigned short)statements[i].b);
1029 if (statements[i].c < 0)
1030 statements16[i].c = PRLittleShort((short)statements[i].c);
1032 statements16[i].c = (unsigned short)PRLittleShort((unsigned short)statements[i].c);
1035 if (progs.blockscompressed&1)
1037 SafeWrite (h, &len, sizeof(int)); //save for later
1038 len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement16_t), 2, (char *)statements16, h); //write
1039 i = SafeSeek (h, 0, SEEK_CUR);
1040 SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
1041 len = PRLittleLong(len);
1042 SafeWrite (h, &len, sizeof(int)); //write size.
1043 SafeSeek(h, i, SEEK_SET);
1046 SafeWrite (h, statements16, numstatements*sizeof(QCC_dstatement16_t));
1049 Sys_Error("structtype error");
1052 progs.ofs_functions = SafeSeek (h, 0, SEEK_CUR);
1053 progs.numfunctions = numfunctions;
1055 switch (outputsttype)
1059 // this sucks but the structures are just too different
1060 qtest_function_t *qtestfuncs = (qtest_function_t *)qccHunkAlloc(sizeof(qtest_function_t)*numfunctions);
1062 for (i=0 ; i<numfunctions ; i++)
1066 qtestfuncs[i].unused1 = 0;
1067 qtestfuncs[i].profile = 0;
1068 qtestfuncs[i].first_statement = PRLittleLong (functions[i].first_statement);
1069 qtestfuncs[i].parm_start = PRLittleLong (functions[i].parm_start);
1070 qtestfuncs[i].s_name = PRLittleLong (functions[i].s_name);
1071 qtestfuncs[i].s_file = PRLittleLong (functions[i].s_file);
1072 qtestfuncs[i].numparms = PRLittleLong ((functions[i].numparms>MAX_PARMS)?MAX_PARMS:functions[i].numparms);
1073 qtestfuncs[i].locals = PRLittleLong (functions[i].locals);
1074 for (j = 0; j < MAX_PARMS; j++)
1075 qtestfuncs[i].parm_size[j] = PRLittleLong((int)functions[i].parm_size[j]);
1078 SafeWrite (h, qtestfuncs, numfunctions*sizeof(qtest_function_t));
1084 for (i=0 ; i<numfunctions ; i++)
1086 functions[i].first_statement = PRLittleLong (functions[i].first_statement);
1087 functions[i].parm_start = PRLittleLong (functions[i].parm_start);
1088 functions[i].s_name = PRLittleLong (functions[i].s_name);
1089 functions[i].s_file = PRLittleLong (functions[i].s_file);
1090 functions[i].numparms = PRLittleLong ((functions[i].numparms>MAX_PARMS)?MAX_PARMS:functions[i].numparms);
1091 functions[i].locals = PRLittleLong (functions[i].locals);
1094 if (progs.blockscompressed&8)
1096 SafeWrite (h, &len, sizeof(int)); //save for later
1097 len = QC_encode(progfuncs, numfunctions*sizeof(QCC_dfunction_t), 2, (char *)functions, h); //write
1098 i = SafeSeek (h, 0, SEEK_CUR);
1099 SafeSeek(h, progs.ofs_functions, SEEK_SET);//seek back
1100 len = PRLittleLong(len);
1101 SafeWrite (h, &len, sizeof(int)); //write size.
1102 SafeSeek(h, i, SEEK_SET);
1105 SafeWrite (h, functions, numfunctions*sizeof(QCC_dfunction_t));
1108 Sys_Error("structtype error");
1111 switch(outputsttype)
1114 // qtest needs a struct remap but should be able to get away with a simple swap here
1115 for (i=0 ; i<numglobaldefs ; i++)
1117 qtest_def_t qtdef = ((qtest_def_t *)qcc_globals)[i];
1118 qcc_globals[i].type = qtdef.type;
1119 qcc_globals[i].ofs = qtdef.ofs;
1120 qcc_globals[i].s_name = qtdef.s_name;
1122 for (i=0 ; i<numfielddefs ; i++)
1124 qtest_def_t qtdef = ((qtest_def_t *)fields)[i];
1125 fields[i].type = qtdef.type;
1126 fields[i].ofs = qtdef.ofs;
1127 fields[i].s_name = qtdef.s_name;
1129 // passthrough.. reuse FTE32 code
1131 progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR);
1132 progs.numglobaldefs = numglobaldefs;
1133 for (i=0 ; i<numglobaldefs ; i++)
1135 qcc_globals[i].type = PRLittleLong/*PRLittleShort*/ (qcc_globals[i].type);
1136 qcc_globals[i].ofs = PRLittleLong/*PRLittleShort*/ (qcc_globals[i].ofs);
1137 qcc_globals[i].s_name = PRLittleLong (qcc_globals[i].s_name);
1140 if (progs.blockscompressed&2)
1142 SafeWrite (h, &len, sizeof(int)); //save for later
1143 len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef_t), 2, (char *)qcc_globals, h); //write
1144 i = SafeSeek (h, 0, SEEK_CUR);
1145 SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
1146 len = PRLittleLong(len);
1147 SafeWrite (h, &len, sizeof(int)); //write size.
1148 SafeSeek(h, i, SEEK_SET);
1151 SafeWrite (h, qcc_globals, numglobaldefs*sizeof(QCC_ddef_t));
1153 progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
1154 progs.numfielddefs = numfielddefs;
1156 for (i=0 ; i<numfielddefs ; i++)
1158 fields[i].type = PRLittleLong/*PRLittleShort*/ (fields[i].type);
1159 fields[i].ofs = PRLittleLong/*PRLittleShort*/ (fields[i].ofs);
1160 fields[i].s_name = PRLittleLong (fields[i].s_name);
1163 if (progs.blockscompressed&4)
1165 SafeWrite (h, &len, sizeof(int)); //save for later
1166 len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef_t), 2, (char *)fields, h); //write
1167 i = SafeSeek (h, 0, SEEK_CUR);
1168 SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
1169 len = PRLittleLong(len);
1170 SafeWrite (h, &len, sizeof(int)); //write size.
1171 SafeSeek(h, i, SEEK_SET);
1174 SafeWrite (h, fields, numfielddefs*sizeof(QCC_ddef_t));
1178 #define qcc_globals16 ((QCC_ddef16_t*)qcc_globals)
1179 #define fields16 ((QCC_ddef16_t*)fields)
1180 progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR);
1181 progs.numglobaldefs = numglobaldefs;
1182 for (i=0 ; i<numglobaldefs ; i++)
1184 qcc_globals16[i].type = (unsigned short)PRLittleShort ((unsigned short)qcc_globals[i].type);
1185 qcc_globals16[i].ofs = (unsigned short)PRLittleShort ((unsigned short)qcc_globals[i].ofs);
1186 qcc_globals16[i].s_name = PRLittleLong (qcc_globals[i].s_name);
1189 if (progs.blockscompressed&2)
1191 SafeWrite (h, &len, sizeof(int)); //save for later
1192 len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef16_t), 2, (char *)qcc_globals16, h); //write
1193 i = SafeSeek (h, 0, SEEK_CUR);
1194 SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
1195 len = PRLittleLong(len);
1196 SafeWrite (h, &len, sizeof(int)); //write size.
1197 SafeSeek(h, i, SEEK_SET);
1200 SafeWrite (h, qcc_globals16, numglobaldefs*sizeof(QCC_ddef16_t));
1202 progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
1203 progs.numfielddefs = numfielddefs;
1205 for (i=0 ; i<numfielddefs ; i++)
1207 fields16[i].type = (unsigned short)PRLittleShort ((unsigned short)fields[i].type);
1208 fields16[i].ofs = (unsigned short)PRLittleShort ((unsigned short)fields[i].ofs);
1209 fields16[i].s_name = PRLittleLong (fields[i].s_name);
1212 if (progs.blockscompressed&4)
1214 SafeWrite (h, &len, sizeof(int)); //save for later
1215 len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef16_t), 2, (char *)fields16, h); //write
1216 i = SafeSeek (h, 0, SEEK_CUR);
1217 SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
1218 len = PRLittleLong(len);
1219 SafeWrite (h, &len, sizeof(int)); //write size.
1220 SafeSeek(h, i, SEEK_SET);
1223 SafeWrite (h, fields16, numfielddefs*sizeof(QCC_ddef16_t));
1226 Sys_Error("structtype error");
1229 progs.ofs_globals = SafeSeek (h, 0, SEEK_CUR);
1230 progs.numglobals = numpr_globals;
1232 for (i=0 ; (unsigned)i<numpr_globals ; i++)
1233 ((int *)qcc_pr_globals)[i] = PRLittleLong (((int *)qcc_pr_globals)[i]);
1235 if (progs.blockscompressed&32)
1237 SafeWrite (h, &len, sizeof(int)); //save for later
1238 len = QC_encode(progfuncs, numpr_globals*4, 2, (char *)qcc_pr_globals, h); //write
1239 i = SafeSeek (h, 0, SEEK_CUR);
1240 SafeSeek(h, progs.ofs_globals, SEEK_SET);//seek back
1241 len = PRLittleLong(len);
1242 SafeWrite (h, &len, sizeof(int)); //write size.
1243 SafeSeek(h, i, SEEK_SET);
1246 SafeWrite (h, qcc_pr_globals, numpr_globals*4);
1249 for (i=0 ; i<numtypeinfos ; i++)
1251 if (qcc_typeinfo[i].aux_type)
1252 qcc_typeinfo[i].aux_type = (QCC_type_t*)(qcc_typeinfo[i].aux_type - qcc_typeinfo);
1253 if (qcc_typeinfo[i].next)
1254 qcc_typeinfo[i].next = (QCC_type_t*)(qcc_typeinfo[i].next - qcc_typeinfo);
1255 qcc_typeinfo[i].name = (char*)QCC_CopyDupBackString(qcc_typeinfo[i].name);
1259 progs.ofslinenums = 0;
1260 progs.secondaryversion = 0;
1261 progs.ofsbodylessfuncs = 0;
1262 progs.numbodylessfuncs = 0;
1263 progs.ofs_types = 0;
1266 switch(qcc_targetformat)
1269 progs.version = PROG_QTESTVERSION;
1272 progs.version = PROG_KKQWSVVERSION;
1275 case QCF_HEXEN2: //urgh
1276 progs.version = PROG_VERSION;
1278 case QCF_DARKPLACES:
1281 progs.version = PROG_EXTENDEDVERSION;
1283 if (outputsttype == PST_FTE32)
1284 progs.secondaryversion = PROG_SECONDARYVERSION32;
1286 progs.secondaryversion = PROG_SECONDARYVERSION16;
1288 progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR);
1289 progs.numbodylessfuncs = WriteBodylessFuncs(h);
1293 progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR);
1294 if (progs.blockscompressed&64)
1296 SafeWrite (h, &len, sizeof(int)); //save for later
1297 len = QC_encode(progfuncs, numstatements*sizeof(int), 2, (char *)statement_linenums, h); //write
1298 i = SafeSeek (h, 0, SEEK_CUR);
1299 SafeSeek(h, progs.ofslinenums, SEEK_SET);//seek back
1300 len = PRLittleLong(len);
1301 SafeWrite (h, &len, sizeof(int)); //write size.
1302 SafeSeek(h, i, SEEK_SET);
1305 SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1308 progs.ofslinenums = 0;
1312 progs.ofs_types = SafeSeek (h, 0, SEEK_CUR);
1313 if (progs.blockscompressed&128)
1315 SafeWrite (h, &len, sizeof(int)); //save for later
1316 len = QC_encode(progfuncs, sizeof(QCC_type_t)*numtypeinfos, 2, (char *)qcc_typeinfo, h); //write
1317 i = SafeSeek (h, 0, SEEK_CUR);
1318 SafeSeek(h, progs.ofs_types, SEEK_SET);//seek back#
1319 len = PRLittleLong(len);
1320 SafeWrite (h, &len, sizeof(int)); //write size.
1321 SafeSeek(h, i, SEEK_SET);
1324 SafeWrite (h, qcc_typeinfo, sizeof(QCC_type_t)*numtypeinfos);
1325 progs.numtypes = numtypeinfos;
1329 progs.ofs_types = 0;
1333 progs.ofsfiles = WriteSourceFiles(h, &progs, debugtarget);
1338 printf ("%6i TOTAL SIZE\n", (int)SafeSeek (h, 0, SEEK_CUR));
1340 progs.entityfields = pr.size_fields;
1344 // qbyte swap the header and write it out
1346 for (i=0 ; i<sizeof(progs)/4 ; i++)
1347 ((int *)&progs)[i] = PRLittleLong ( ((int *)&progs)[i] );
1350 SafeSeek (h, 0, SEEK_SET);
1351 SafeWrite (h, &progs, sizeof(progs));
1358 printf("Not writing linenumbers file due to conflicting optimisation\n");
1362 unsigned int lnotype = *(unsigned int*)"LNOF";
1363 unsigned int version = 1;
1364 StripExtension(destfile);
1365 strcat(destfile, ".lno");
1367 printf("Writing %s for debugging\n", destfile);
1368 h = SafeOpenWrite (destfile, 2*1024*1024);
1369 SafeWrite (h, &lnotype, sizeof(int));
1370 SafeWrite (h, &version, sizeof(int));
1371 SafeWrite (h, &numglobaldefs, sizeof(int));
1372 SafeWrite (h, &numpr_globals, sizeof(int));
1373 SafeWrite (h, &numfielddefs, sizeof(int));
1374 SafeWrite (h, &numstatements, sizeof(int));
1375 SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1389 Returns a string suitable for printing (no newlines, max 60 chars length)
1392 char *QCC_PR_String (char *string)
1394 static char buf[80];
1399 while (string && *string)
1401 if (s == buf + sizeof(buf) - 2)
1403 if (*string == '\n')
1408 else if (*string == '"')
1431 QCC_def_t *QCC_PR_DefForFieldOfs (gofs_t ofs)
1435 for (d=pr.def_head.next ; d ; d=d->next)
1437 if (d->type->type != ev_field)
1439 if (*((unsigned int *)&qcc_pr_globals[d->ofs]) == ofs)
1442 QCC_Error (ERR_NOTDEFINED, "PR_DefForFieldOfs: couldn't find %i",ofs);
1450 Returns a string describing *data in a type specific manner
1453 char *QCC_PR_ValueString (etype_t type, void *val)
1455 static char line[256];
1462 sprintf (line, "%s", QCC_PR_String(strings + *(int *)val));
1465 sprintf (line, "entity %i", *(int *)val);
1468 f = functions + *(int *)val;
1470 sprintf (line, "undefined function");
1472 sprintf (line, "%s()", strings + f->s_name);
1475 def = QCC_PR_DefForFieldOfs ( *(int *)val );
1476 sprintf (line, ".%s", def->name);
1479 sprintf (line, "void");
1482 sprintf (line, "%5.1f", *(float *)val);
1485 sprintf (line, "%i", *(int *)val);
1488 sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]);
1491 sprintf (line, "pointer");
1494 sprintf (line, "bad type %i", type);
1505 Returns a string with a description and the contents of a global,
1506 padded to 20 field width
1509 /*char *QCC_PR_GlobalStringNoContents (gofs_t ofs)
1514 static char line[128];
1516 val = (void *)&qcc_pr_globals[ofs];
1517 def = pr_global_defs[ofs];
1519 // Error ("PR_GlobalString: no def for %i", ofs);
1520 sprintf (line,"%i(?""?""?)", ofs);
1522 sprintf (line,"%i(%s)", ofs, def->name);
1532 char *QCC_PR_GlobalString (gofs_t ofs)
1538 static char line[128];
1540 val = (void *)&qcc_pr_globals[ofs];
1541 def = pr_global_defs[ofs];
1543 return QCC_PR_GlobalStringNoContents(ofs);
1544 if (def->initialized && def->type->type != ev_function)
1546 s = QCC_PR_ValueString (def->type->type, &qcc_pr_globals[ofs]);
1547 sprintf (line,"%i(%s)", ofs, s);
1550 sprintf (line,"%i(%s)", ofs, def->name);
1565 /*void QCC_PR_PrintOfs (gofs_t ofs)
1567 printf ("%s\n",QCC_PR_GlobalString(ofs));
1575 /*void QCC_PR_PrintStatement (QCC_dstatement_t *s)
1579 printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname);
1580 i = strlen(pr_opcodes[s->op].opname);
1584 if (s->op == OP_IF || s->op == OP_IFNOT)
1585 printf ("%sbranch %i",QCC_PR_GlobalString(s->a),s->b);
1586 else if (s->op == OP_GOTO)
1588 printf ("branch %i",s->a);
1590 else if ( (unsigned)(s->op - OP_STORE_F) < 6)
1592 printf ("%s",QCC_PR_GlobalString(s->a));
1593 printf ("%s", QCC_PR_GlobalStringNoContents(s->b));
1598 printf ("%s",QCC_PR_GlobalString(s->a));
1600 printf ("%s",QCC_PR_GlobalString(s->b));
1602 printf ("%s", QCC_PR_GlobalStringNoContents(s->c));
1613 /*void QCC_PR_PrintDefs (void)
1617 for (d=pr.def_head.next ; d ; d=d->next)
1618 QCC_PR_PrintOfs (d->ofs);
1621 QCC_type_t *QCC_PR_NewType (char *name, int basictype, pbool typedefed)
1623 if (numtypeinfos>= maxtypeinfos)
1624 QCC_Error(ERR_TOOMANYTYPES, "Too many types");
1625 memset(&qcc_typeinfo[numtypeinfos], 0, sizeof(QCC_type_t));
1626 qcc_typeinfo[numtypeinfos].type = basictype;
1627 qcc_typeinfo[numtypeinfos].name = name;
1628 qcc_typeinfo[numtypeinfos].num_parms = 0;
1629 qcc_typeinfo[numtypeinfos].param = NULL;
1630 qcc_typeinfo[numtypeinfos].size = type_size[basictype];
1631 qcc_typeinfo[numtypeinfos].arraysize = 0;
1632 qcc_typeinfo[numtypeinfos].typedefed = typedefed;
1637 return &qcc_typeinfo[numtypeinfos-1];
1644 called before compiling a batch of files, clears the pr struct
1647 void QCC_PR_BeginCompilation (void *memory, int memsize)
1649 extern int recursivefunctiontype;
1650 extern struct freeoffset_s *freeofs;
1655 pr.max_memory = memsize;
1657 pr.def_tail = &pr.def_head;
1659 QCC_PR_ResetErrorScope();
1662 /* numpr_globals = RESERVED_OFS;
1664 for (i=0 ; i<RESERVED_OFS ; i++)
1665 pr_global_defs[i] = &def_void;
1668 type_void = QCC_PR_NewType("void", ev_void, true);
1669 type_string = QCC_PR_NewType("string", ev_string, true);
1670 type_float = QCC_PR_NewType("float", ev_float, true);
1671 type_vector = QCC_PR_NewType("vector", ev_vector, true);
1672 type_entity = QCC_PR_NewType("entity", ev_entity, true);
1673 type_field = QCC_PR_NewType("__field", ev_field, false);
1674 type_function = QCC_PR_NewType("__function", ev_function, false);
1675 type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false);
1676 type_integer = QCC_PR_NewType("__integer", ev_integer, true);
1677 type_variant = QCC_PR_NewType("variant", ev_variant, true);
1678 type_variant = QCC_PR_NewType("__variant", ev_variant, true);
1680 type_floatfield = QCC_PR_NewType("fieldfloat", ev_field, false);
1681 type_floatfield->aux_type = type_float;
1682 type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float, false);
1684 type_intpointer = QCC_PR_NewType("__intpointer", ev_pointer, false);
1685 type_intpointer->aux_type = type_integer;
1686 type_floatpointer = QCC_PR_NewType("__floatpointer", ev_pointer, false);
1687 type_floatpointer->aux_type = type_float;
1689 type_function->aux_type = type_void;
1691 //type_field->aux_type = type_float;
1693 type_integer = QCC_PR_NewType("integer", ev_integer, keyword_integer?true:false);
1694 type_integer = QCC_PR_NewType("int", ev_integer, keyword_integer?true:false);
1699 { //this tends to confuse the brains out of decompilers. :)
1701 QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 0, false)->references++;
1702 for (i = 0; i < MAX_PARMS; i++)
1704 sprintf(name, "PARM%i", i);
1705 QCC_PR_GetDef(type_vector, name, NULL, true, 0, false)->references++;
1710 numpr_globals = RESERVED_OFS;
1711 // for (i=0 ; i<RESERVED_OFS ; i++)
1712 // pr_global_defs[i] = NULL;
1715 // link the function type in so state forward declarations match proper type
1717 // type_function->next = NULL;
1719 pr_warning_count = 0;
1720 recursivefunctiontype = 0;
1727 PR_FinishCompilation
1729 called after all files are compiled to check for errors
1730 Returns false if errors were detected.
1733 int QCC_PR_FinishCompilation (void)
1740 // check to make sure all functions prototyped have code
1741 for (d=pr.def_head.next ; d ; d=d->next)
1743 if (d->type->type == ev_function && !d->scope)// function parms are ok
1745 // f = G_FUNCTION(d->ofs);
1746 // if (!f || (!f->code && !f->builtin) )
1747 if (d->initialized==0)
1750 if (!strncmp(d->name, "ArrayGet*", 9))
1752 QCC_PR_EmitArrayGetFunction(d, d->name+9);
1755 else if (!strncmp(d->name, "ArraySet*", 9))
1757 QCC_PR_EmitArraySetFunction(d, d->name+9);
1760 else if (!strncmp(d->name, "Class*", 6))
1762 QCC_PR_EmitClassFromFunction(d, d->name+6);
1767 QCC_PR_ParseWarning(ERR_NOFUNC, "function %s was not defined",d->name);
1768 QCC_PR_ParsePrintDef(ERR_NOFUNC, d);
1769 bodylessfuncs = true;
1775 else if (d->initialized==2)
1776 bodylessfuncs = true;
1784 //=============================================================================
1786 // FIXME: byte swap?
1788 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
1789 // and the initial and final xor values shown below... in other words, the
1790 // CCITT standard CRC used by XMODEM
1793 #define CRC_INIT_VALUE 0xffff
1794 #define CRC_XOR_VALUE 0x0000
1796 static unsigned short QCC_crctable[256] =
1798 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1799 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1800 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1801 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1802 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1803 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1804 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1805 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1806 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1807 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1808 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1809 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1810 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1811 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1812 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1813 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1814 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1815 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1816 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1817 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1818 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1819 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1820 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1821 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1822 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1823 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1824 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1825 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1826 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1827 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1828 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1829 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1832 void QCC_CRC_Init(unsigned short *crcvalue)
1834 *crcvalue = CRC_INIT_VALUE;
1837 void QCC_CRC_ProcessByte(unsigned short *crcvalue, qbyte data)
1839 *crcvalue = (*crcvalue << 8) ^ QCC_crctable[(*crcvalue >> 8) ^ data];
1842 unsigned short QCC_CRC_Value(unsigned short crcvalue)
1844 return crcvalue ^ CRC_XOR_VALUE;
1846 //=============================================================================
1853 Writes the global and entity structures out
1854 Returns a crc of the header, to be stored in the progs file for comparison
1859 char *Sva(char *msg, ...)
1862 static char buf[1024];
1865 QC_vsnprintf (buf,sizeof(buf)-1, msg, l);
1872 #define PROGDEFS_MAX_SIZE 16384
1873 //write (to file buf) and add to the crc
1874 static void Add(char *p, unsigned short *crc, char *file)
1877 int i = strlen(file);
1878 if (i + strlen(p)+1 >= PROGDEFS_MAX_SIZE)
1882 QCC_CRC_ProcessByte(crc, *s);
1887 #define ADD(p) Add(p, &crc, file)
1888 //#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';}
1890 static void Add3(char *p, unsigned short *crc, char *file)
1894 QCC_CRC_ProcessByte(crc, *s);
1896 #define ADD3(p) Add3(p, &crc, file)
1898 unsigned short QCC_PR_WriteProgdefs (char *filename)
1900 #define ADD2(p) strncat(file, p, PROGDEFS_MAX_SIZE-1 - strlen(file)) //no crc (later changes)
1901 char file[PROGDEFS_MAX_SIZE];
1910 QCC_CRC_Init (&crc);
1912 // print global vars until the first field is defined
1915 //ADD2: dump but don't crc
1916 //ADD3: crc but don't dump
1919 if (qcc_targetformat == QCF_HEXEN2)
1920 ADD3("generated by hcc, do not modify");
1922 ADD3("file generated by qcc, do not modify");
1923 ADD2("File generated by FTEQCC, relevent for engine modding only, the generated crc must be the same as your engine expects.");
1924 ADD(" */\n\ntypedef struct");
1925 ADD2(" globalvars_s");
1928 "\tint ofs_return[3];\n" //makes it easier with the get globals func
1929 "\tint ofs_parm0[3];\n"
1930 "\tint ofs_parm1[3];\n"
1931 "\tint ofs_parm2[3];\n"
1932 "\tint ofs_parm3[3];\n"
1933 "\tint ofs_parm4[3];\n"
1934 "\tint ofs_parm5[3];\n"
1935 "\tint ofs_parm6[3];\n"
1936 "\tint ofs_parm7[3];\n");
1937 ADD3(qcva("\tint\tpad[%i];\n", RESERVED_OFS));
1938 for (d=pr.def_head.next ; d ; d=d->next)
1941 if (!strcmp (d->name, "end_sys_globals"))
1943 if (d->ofs<RESERVED_OFS)
1946 switch (d->type->type)
1949 ADD(qcva("\tfloat\t%s;\n",d->name));
1952 ADD(qcva("\tvec3_t\t%s;\n",d->name));
1954 d=d->deftail; // skip the elements
1957 ADD(qcva("\tstring_t\t%s;\n",d->name));
1960 ADD(qcva("\tfunc_t\t%s;\n",d->name));
1963 ADD(qcva("\tint\t%s;\n",d->name));
1966 ADD(qcva("\tint\t%s;\n",d->name));
1969 ADD(qcva("\tint\t%s;\n",d->name));
1973 ADD("} globalvars_t;\n\n");
1976 ADD("typedef struct");
1979 for (d=pr.def_head.next ; d ; d=d->next)
1981 if (!strcmp (d->name, "end_sys_fields"))
1984 if (d->type->type != ev_field)
1987 switch (d->type->aux_type->type)
1990 ADD(qcva("\tfloat\t%s;\n",d->name));
1993 ADD(qcva("\tvec3_t\t%s;\n",d->name));
1995 d=d->deftail; // skip the elements
1998 ADD(qcva("\tstring_t\t%s;\n",d->name));
2001 ADD(qcva("\tfunc_t\t%s;\n",d->name));
2004 ADD(qcva("\tint\t%s;\n",d->name));
2007 ADD(qcva("\tint\t%s;\n",d->name));
2010 ADD(qcva("\tint\t%s;\n",d->name));
2014 ADD("} entvars_t;\n\n");
2017 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");
2019 for (d=pr.def_head.next ; d ; d=d->next)
2021 if (!strcmp (d->name, "end_sys_fields"))
2024 if (d->type->type != ev_field)
2028 ADD2(qcva("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
2031 ADD2("\n};\n#endif\n\n");
2034 ADD2(qcva("#define PROGHEADER_CRC %i\n", crc));
2036 if (QCC_CheckParm("-progdefs"))
2038 printf ("writing %s\n", filename);
2039 f = SafeOpenWrite(filename, 16384);
2040 SafeWrite(f, file, strlen(file));
2050 case 12923: //#pragma sourcefile usage
2054 printf("Recognised progs as QuakeWorld\n");
2058 printf("Recognised progs as NetQuake server gamecode\n");
2063 printf("Recognised progs as Quake pre-release...\n");
2068 printf("Recognised progs as original Hexen2\n");
2072 printf("Recognised progs as Hexen2 Mission Pack\n");
2076 printf("Recognised progs as Hexen2 (demo)\n");
2079 case 22390: //EXT_CSQC_1
2081 printf("Recognised progs as an EXT_CSQC_1 module\n");
2084 case 32199: //outdated ext_csqc
2085 printf("Recognised progs as outdated CSQC module\n");
2088 printf("Recognised progs as outdated CSQC module\n");
2092 printf("Recognised progs as a DP/FTE Menu module\n");
2096 printf("Warning: please update your tenebrae system defs.\n");
2099 printf("Warning: progs CRC not recognised from quake nor clones\n");
2108 /*void QCC_PrintFunction (char *name)
2111 QCC_dstatement_t *ds;
2112 QCC_dfunction_t *df;
2114 for (i=0 ; i<numfunctions ; i++)
2115 if (!strcmp (name, strings + functions[i].s_name))
2117 if (i==numfunctions)
2118 QCC_Error (ERR_NOFUNC, "No function named \"%s\"", name);
2121 printf ("Statements for function %s:\n", name);
2122 ds = statements + df->first_statement;
2125 QCC_PR_PrintStatement (ds);
2132 void QCC_PrintOfs(unsigned int ofs)
2136 QCC_dstatement_t *ds;
2137 QCC_dfunction_t *df;
2139 for (i=0 ; i<numfunctions ; i++)
2142 ds = statements + df->first_statement;
2148 if (ds->a == ofs || ds->b == ofs || ds->c == ofs)
2150 QCC_PR_PrintStatement (ds);
2157 QCC_PrintFunction(strings + functions[i].s_name);
2165 ==============================================================================
2167 DIRECTORY COPYING / PACKFILE CREATION
2169 ==============================================================================
2175 int filepos, filelen;
2185 packfile_t pfiles[4096], *pf;
2195 void QCC_CreatePath (char *path)
2200 for (ofs = path+1 ; *ofs ; ofs++)
2203 { // create the directory
2221 Copy a file into the pak file
2224 void QCC_PackFile (char *src, char *name)
2236 if ( (qbyte *)pf - (qbyte *)pfiles > sizeof(pfiles) )
2237 QCC_Error (ERR_TOOMANYPAKFILES, "Too many files in pak file");
2240 f = FS_ReadToMem(src, NULL, &remaining);
2243 printf ("%64s : %7s\n", name, "");
2244 // QCC_Error("Failed to open file %s", src);
2248 pf->filepos = PRLittleLong (SafeSeek (packhandle, 0, SEEK_CUR));
2249 pf->filelen = PRLittleLong (remaining);
2250 strcpy (pf->name, name);
2251 printf ("%64s : %7i\n", pf->name, remaining);
2253 packbytes += remaining;
2255 SafeWrite (packhandle, f, remaining);
2259 in = SafeOpenRead (src);
2260 remaining = filelength (in);
2262 pf->filepos = PRLittleLong (lseek (packhandle, 0, SEEK_CUR));
2263 pf->filelen = PRLittleLong (remaining);
2264 strcpy (pf->name, name);
2265 printf ("%64s : %7i\n", pf->name, remaining);
2267 packbytes += remaining;
2271 if (remaining < sizeof(buf))
2274 count = sizeof(buf);
2275 SafeRead (in, buf, count);
2276 SafeWrite (packhandle, buf, count);
2290 Copies a file, creating any directories needed
2293 void QCC_CopyFile (char *src, char *dest)
2297 int remaining, count;
2300 print ("%s to %s\n", src, dest);
2302 in = SafeOpenRead (src);
2303 remaining = filelength (in);
2305 QCC_CreatePath (dest);
2306 out = SafeOpenWrite (dest, remaining+10);
2310 if (remaining < sizeof(buf))
2313 count = sizeof(buf);
2314 SafeRead (in, buf, count);
2315 SafeWrite (out, buf, count);
2331 void _QCC_CopyFiles (int blocknum, int copytype, char *srcdir, char *destdir)
2336 packheader_t header;
2338 char srcfile[1024], destfile[1024];
2345 packhandle = SafeOpenWrite (destdir, 1024*1024);
2346 SafeWrite (packhandle, &header, sizeof(header));
2349 for (i=0 ; i<numsounds ; i++)
2351 if (precache_sounds_block[i] != blocknum)
2353 sprintf (srcfile,"%s%s",srcdir, precache_sounds[i]);
2354 sprintf (destfile,"%s%s",destdir, precache_sounds[i]);
2356 QCC_CopyFile (srcfile, destfile);
2358 QCC_PackFile (srcfile, precache_sounds[i]);
2360 for (i=0 ; i<nummodels ; i++)
2362 if (precache_models_block[i] != blocknum)
2364 sprintf (srcfile,"%s%s",srcdir, precache_models[i]);
2365 sprintf (destfile,"%s%s",destdir, precache_models[i]);
2367 QCC_CopyFile (srcfile, destfile);
2369 QCC_PackFile (srcfile, precache_models[i]);
2371 for (i=0 ; i<numtextures ; i++)
2373 if (precache_textures_block[i] != blocknum)
2377 sprintf (name, "%s", precache_textures[i]);
2378 sprintf (srcfile,"%s%s",srcdir, name);
2379 sprintf (destfile,"%s%s",destdir, name);
2381 QCC_CopyFile (srcfile, destfile);
2383 QCC_PackFile (srcfile, name);
2386 sprintf (name, "%s.bmp", precache_textures[i]);
2387 sprintf (srcfile,"%s%s",srcdir, name);
2388 sprintf (destfile,"%s%s",destdir, name);
2390 QCC_CopyFile (srcfile, destfile);
2392 QCC_PackFile (srcfile, name);
2395 sprintf (name, "%s.tga", precache_textures[i]);
2396 sprintf (srcfile,"%s%s",srcdir, name);
2397 sprintf (destfile,"%s%s",destdir, name);
2399 QCC_CopyFile (srcfile, destfile);
2401 QCC_PackFile (srcfile, name);
2404 for (i=0 ; i<numfiles ; i++)
2406 if (precache_files_block[i] != blocknum)
2408 sprintf (srcfile,"%s%s",srcdir, precache_files[i]);
2409 sprintf (destfile,"%s%s",destdir, precache_files[i]);
2411 QCC_CopyFile (srcfile, destfile);
2413 QCC_PackFile (srcfile, precache_files[i]);
2422 dirlen = (qbyte *)pf - (qbyte *)pfiles;
2423 header.dirofs = PRLittleLong(SafeSeek (packhandle, 0, SEEK_CUR));
2424 header.dirlen = PRLittleLong(dirlen);
2426 SafeWrite (packhandle, pfiles, dirlen);
2428 SafeSeek (packhandle, 0, SEEK_SET);
2429 SafeWrite (packhandle, &header, sizeof(header));
2430 SafeClose (packhandle);
2432 // do a crc of the file
2433 QCC_CRC_Init (&crc);
2434 for (i=0 ; i<dirlen ; i++)
2435 QCC_CRC_ProcessByte (&crc, ((qbyte *)pfiles)[i]);
2438 printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
2442 void QCC_CopyFiles (void)
2445 char srcdir[1024], destdir[1024];
2451 printf ("%3i unique precache_sounds\n", numsounds);
2453 printf ("%3i unique precache_models\n", nummodels);
2454 if (numtextures > 0)
2455 printf ("%3i unique precache_textures\n", numtextures);
2457 printf ("%3i unique precache_files\n", numfiles);
2460 p = QCC_CheckParm ("-copy");
2461 if (p && p < myargc-2)
2462 { // create a new directory tree
2464 strcpy (srcdir, myargv[p+1]);
2465 strcpy (destdir, myargv[p+2]);
2466 if (srcdir[strlen(srcdir)-1] != '/')
2467 strcat (srcdir, "/");
2468 if (destdir[strlen(destdir)-1] != '/')
2469 strcat (destdir, "/");
2471 _QCC_CopyFiles(0, 1, srcdir, destdir);
2475 for ( p = 0; p < 5; p++)
2477 s = QCC_Packname[p];
2482 _QCC_CopyFiles(p+1, 2, srcdir, destdir);
2488 p = QCC_CheckParm ("-pak2");
2489 if (p && p <myargc-2)
2492 p = QCC_CheckParm ("-pak");
2493 if (p && p < myargc-2)
2494 { // create a pak file
2495 strcpy (srcdir, myargv[p+1]);
2496 strcpy (destdir, myargv[p+2]);
2497 if (srcdir[strlen(srcdir)-1] != '/')
2498 strcat (srcdir, "/");
2499 DefaultExtension (destdir, ".pak");
2504 _QCC_CopyFiles(blocknum, copytype, srcdir, destdir);
2509 //============================================================================
2512 void QCC_PR_CommandLinePrecompilerOptions (void)
2514 CompilerConstant_t *cnst;
2518 for (i = 1;i<myargc;i++)
2521 if ( !strncmp(myargv[i], "-D", 2) )
2523 name = myargv[i] + 2;
2524 val = strchr(name, '=');
2530 cnst = QCC_PR_DefineName(name);
2533 cnst->value = qccHunkAlloc(strlen(val)+1);
2534 memcpy(cnst->value, val, strlen(val)+1);
2539 else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) )
2542 if (myargv[i][2] >= '0' && myargv[i][2] <= '3')
2545 else if (!strnicmp(myargv[i]+2, "no-", 3))
2549 for (p = 0; optimisations[p].enabled; p++)
2551 if ((*optimisations[p].abbrev && !stricmp(myargv[i]+5, optimisations[p].abbrev)) || !stricmp(myargv[i]+5, optimisations[p].fullname))
2553 *optimisations[p].enabled = false;
2562 for (p = 0; optimisations[p].enabled; p++)
2563 if ((*optimisations[p].abbrev && !stricmp(myargv[i]+2, optimisations[p].abbrev)) || !stricmp(myargv[i]+2, optimisations[p].fullname))
2565 *optimisations[p].enabled = true;
2569 if (!optimisations[p].enabled)
2570 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised optimisation parameter (%s)", myargv[i]);
2573 else if ( !strnicmp(myargv[i], "-K", 2) || !strnicmp(myargv[i], "/K", 2) )
2576 if (!strnicmp(myargv[i]+2, "no-", 3))
2578 for (p = 0; compiler_flag[p].enabled; p++)
2579 if (!stricmp(myargv[i]+5, compiler_flag[p].abbrev))
2581 *compiler_flag[p].enabled = false;
2587 for (p = 0; compiler_flag[p].enabled; p++)
2588 if (!stricmp(myargv[i]+2, compiler_flag[p].abbrev))
2590 *compiler_flag[p].enabled = true;
2595 if (!compiler_flag[p].enabled)
2596 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised keyword parameter (%s)", myargv[i]);
2598 else if ( !strnicmp(myargv[i], "-F", 2) || !strnicmp(myargv[i], "/F", 2) )
2601 if (!strnicmp(myargv[i]+2, "no-", 3))
2603 for (p = 0; compiler_flag[p].enabled; p++)
2604 if (!stricmp(myargv[i]+5, compiler_flag[p].abbrev))
2606 *compiler_flag[p].enabled = false;
2612 for (p = 0; compiler_flag[p].enabled; p++)
2613 if (!stricmp(myargv[i]+2, compiler_flag[p].abbrev))
2615 *compiler_flag[p].enabled = true;
2620 if (!compiler_flag[p].enabled)
2621 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised flag parameter (%s)", myargv[i]);
2625 else if ( !strncmp(myargv[i], "-T", 2) || !strncmp(myargv[i], "/T", 2) )
2628 for (p = 0; targets[p].name; p++)
2629 if (!stricmp(myargv[i]+2, targets[p].name))
2631 qcc_targetformat = targets[p].target;
2635 if (!targets[p].name)
2636 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised target parameter (%s)", myargv[i]);
2639 else if ( !strnicmp(myargv[i], "-W", 2) || !strnicmp(myargv[i], "/W", 2) )
2641 if (!stricmp(myargv[i]+2, "all"))
2642 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2643 else if (!stricmp(myargv[i]+2, "none"))
2644 memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled));
2645 else if(!stricmp(myargv[i]+2, "error"))
2647 else if (!stricmp(myargv[i]+2, "no-mundane"))
2648 { //disable mundane performance/efficiency/blah warnings that don't affect code.
2649 qccwarningdisabled[WARN_SAMENAMEASGLOBAL] = true;
2650 qccwarningdisabled[WARN_DUPLICATEDEFINITION] = true;
2651 qccwarningdisabled[WARN_CONSTANTCOMPARISON] = true;
2652 qccwarningdisabled[WARN_ASSIGNMENTINCONDITIONAL] = true;
2653 qccwarningdisabled[WARN_DEADCODE] = true;
2654 qccwarningdisabled[WARN_NOTREFERENCEDCONST] = true;
2655 qccwarningdisabled[WARN_NOTREFERENCED] = true;
2656 qccwarningdisabled[WARN_POINTLESSSTATEMENT] = true;
2657 qccwarningdisabled[WARN_ASSIGNMENTTOCONSTANTFUNC] = true;
2658 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.
2659 qccwarningdisabled[WARN_IDENTICALPRECOMPILER] = true;
2660 qccwarningdisabled[WARN_UNDEFNOTDEFINED] = true;
2661 qccwarningdisabled[WARN_FIXEDRETURNVALUECONFLICT] = true;
2662 qccwarningdisabled[WARN_EXTRAPRECACHE] = true;
2663 qccwarningdisabled[WARN_CORRECTEDRETURNTYPE] = true;
2668 if (!strnicmp(myargv[i]+2, "no-", 3))
2670 for (p = 0; warningnames[p].name; p++)
2671 if (!strcmp(myargv[i]+5, warningnames[p].name))
2673 qccwarningdisabled[warningnames[p].index] = true;
2679 for (p = 0; warningnames[p].name; p++)
2680 if (!stricmp(myargv[i]+2, warningnames[p].name))
2682 qccwarningdisabled[warningnames[p].index] = false;
2687 if (!warningnames[p].name)
2688 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised warning parameter (%s)", myargv[i]);
2702 char qccmfilename[1024];
2703 char qccmprogsdat[1024];
2704 char qccmsourcedir[1024];
2706 void QCC_FinishCompile(void);
2709 void SetEndian(void);
2713 void QCC_SetDefaultProperties (void)
2718 Hash_InitTable(&compconstantstable, MAX_CONSTANTS, qccHunkAlloc(Hash_BytesForBuckets(MAX_CONSTANTS)));
2723 QCC_PR_DefineName("FTEQCC");
2725 if (QCC_CheckParm("/Oz"))
2727 qcc_targetformat = QCF_FTE;
2728 QCC_PR_DefineName("OP_COMP_STATEMENTS");
2729 QCC_PR_DefineName("OP_COMP_DEFS");
2730 QCC_PR_DefineName("OP_COMP_FIELDS");
2731 QCC_PR_DefineName("OP_COMP_FUNCTIONS");
2732 QCC_PR_DefineName("OP_COMP_STRINGS");
2733 QCC_PR_DefineName("OP_COMP_GLOBALS");
2734 QCC_PR_DefineName("OP_COMP_LINES");
2735 QCC_PR_DefineName("OP_COMP_TYPES");
2738 if (QCC_CheckParm("/O0") || QCC_CheckParm("-O0"))
2740 else if (QCC_CheckParm("/O1") || QCC_CheckParm("-O1"))
2742 else if (QCC_CheckParm("/O2") || QCC_CheckParm("-O2"))
2744 else if (QCC_CheckParm("/O3") || QCC_CheckParm("-O3"))
2751 for (i = 0; optimisations[i].enabled; i++)
2753 if (optimisations[i].flags & FLAG_ASDEFAULT)
2754 *optimisations[i].enabled = true;
2756 *optimisations[i].enabled = false;
2761 for (i = 0; optimisations[i].enabled; i++)
2763 if (level >= optimisations[i].optimisationlevel)
2764 *optimisations[i].enabled = true;
2766 *optimisations[i].enabled = false;
2770 if (QCC_CheckParm ("-h2"))
2771 qcc_targetformat = QCF_HEXEN2;
2772 else if (QCC_CheckParm ("-fte"))
2773 qcc_targetformat = QCF_FTE;
2774 else if (QCC_CheckParm ("-dp"))
2775 qcc_targetformat = QCF_DARKPLACES;
2777 qcc_targetformat = QCF_STANDARD;
2780 //enable all warnings
2781 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2783 //play with default warnings.
2784 qccwarningdisabled[WARN_NOTREFERENCEDCONST] = true;
2785 qccwarningdisabled[WARN_MACROINSTRING] = true;
2786 // qccwarningdisabled[WARN_ASSIGNMENTTOCONSTANT] = true;
2787 qccwarningdisabled[WARN_FIXEDRETURNVALUECONFLICT] = true;
2788 qccwarningdisabled[WARN_EXTRAPRECACHE] = true;
2789 qccwarningdisabled[WARN_DEADCODE] = true;
2790 qccwarningdisabled[WARN_INEFFICIENTPLUSPLUS] = true;
2791 qccwarningdisabled[WARN_FTE_SPECIFIC] = true;
2792 qccwarningdisabled[WARN_EXTENSION_USED] = true;
2793 qccwarningdisabled[WARN_IFSTRING_USED] = true;
2794 qccwarningdisabled[WARN_CORRECTEDRETURNTYPE] = true;
2798 if (QCC_CheckParm("-nowarn") || QCC_CheckParm("-Wnone"))
2799 memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled));
2800 if (QCC_CheckParm("-Wall"))
2801 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2803 if (QCC_CheckParm("-h2"))
2804 qccwarningdisabled[WARN_CASEINSENSATIVEFRAMEMACRO] = true;
2806 //Check the command line
2807 QCC_PR_CommandLinePrecompilerOptions();
2810 if (qcc_targetformat == QCF_HEXEN2) //force on the thinktime keyword if hexen2 progs.
2811 keyword_thinktime = true;
2813 if (QCC_CheckParm("/Debug")) //disable any debug optimisations
2815 for (i = 0; optimisations[i].enabled; i++)
2817 if (optimisations[i].flags & FLAG_KILLSDEBUGGERS)
2818 *optimisations[i].enabled = false;
2823 //builds a list of files, pretends that they came from a progs.src
2824 int QCC_FindQCFiles()
2831 int numfiles = 0, i, j;
2832 char *filelist[256], *temp;
2835 qccmsrc = qccHunkAlloc(8192);
2836 strcat(qccmsrc, "progs.dat\n");//"#pragma PROGS_DAT progs.dat\n");
2839 h = FindFirstFile("*.qc", &fd);
2840 if (h == INVALID_HANDLE_VALUE)
2845 filelist[numfiles] = qccHunkAlloc (strlen(fd.cFileName)+1);
2846 strcpy(filelist[numfiles], fd.cFileName);
2848 } while(FindNextFile(h, &fd)!=0);
2851 printf("-Facc is not supported on this platform. Please make a progs.src file instead\n");
2854 //Sort alphabetically.
2857 for (i = 0; i < numfiles-1; i++)
2859 for (j = i+1; j < numfiles; j++)
2861 if (stricmp(filelist[i], filelist[j]) > 0)
2864 filelist[j] = filelist[i];
2869 for (i = 0; i < numfiles; i++)
2871 strcat(qccmsrc, filelist[i]);
2872 strcat(qccmsrc, "\n");
2873 // strcat(qccmsrc, "#include \"");
2874 // strcat(qccmsrc, filelist[i]);
2875 // strcat(qccmsrc, "\"\n");
2881 int qcc_compileactive = false;
2882 extern int accglobalsblock;
2883 char *originalqccmsrc; //for autoprototype.
2884 void QCC_main (int argc, char **argv) //as part of the quake engine
2886 extern int pr_bracelevel;
2891 char destfile2[1024], *s2;
2900 qcc_compileactive = true;
2902 pHash_Get = &Hash_Get;
2903 pHash_GetNext = &Hash_GetNext;
2904 pHash_Add = &Hash_Add;
2907 MAX_STRINGS = 1000000;
2908 MAX_GLOBALS = 1<<17;
2910 MAX_STATEMENTS = 0x80000;
2911 MAX_FUNCTIONS = 16384;
2912 maxtypeinfos = 16384;
2913 MAX_CONSTANTS = 2048;
2917 p = externs->FileSize("qcc.cfg");
2919 p = externs->FileSize("src/qcc.cfg");
2922 s = qccHunkAlloc(p+1);
2923 s = externs->ReadFile("qcc.cfg", s, p);
2927 s = QCC_COM_Parse(s);
2928 if (!strcmp(qcc_token, "MAX_REGS"))
2930 s = QCC_COM_Parse(s);
2931 MAX_REGS = atoi(qcc_token);
2932 } else if (!strcmp(qcc_token, "MAX_STRINGS")) {
2933 s = QCC_COM_Parse(s);
2934 MAX_STRINGS = atoi(qcc_token);
2935 } else if (!strcmp(qcc_token, "MAX_GLOBALS")) {
2936 s = QCC_COM_Parse(s);
2937 MAX_GLOBALS = atoi(qcc_token);
2938 } else if (!strcmp(qcc_token, "MAX_FIELDS")) {
2939 s = QCC_COM_Parse(s);
2940 MAX_FIELDS = atoi(qcc_token);
2941 } else if (!strcmp(qcc_token, "MAX_STATEMENTS")) {
2942 s = QCC_COM_Parse(s);
2943 MAX_STATEMENTS = atoi(qcc_token);
2944 } else if (!strcmp(qcc_token, "MAX_FUNCTIONS")) {
2945 s = QCC_COM_Parse(s);
2946 MAX_FUNCTIONS = atoi(qcc_token);
2947 } else if (!strcmp(qcc_token, "MAX_TYPES")) {
2948 s = QCC_COM_Parse(s);
2949 maxtypeinfos = atoi(qcc_token);
2950 } else if (!strcmp(qcc_token, "MAX_TEMPS")) {
2951 s = QCC_COM_Parse(s);
2952 max_temps = atoi(qcc_token);
2953 } else if (!strcmp(qcc_token, "CONSTANTS")) {
2954 s = QCC_COM_Parse(s);
2955 MAX_CONSTANTS = atoi(qcc_token);
2960 printf("Bad token in qcc.cfg file\n");
2963 /* don't try to be clever
2966 s = qccHunkAlloc(8192);
2967 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",
2968 MAX_REGS, MAX_STRINGS, MAX_GLOBALS, MAX_FIELDS, MAX_STATEMENTS, MAX_FUNCTIONS, maxtypeinfos);
2969 externs->WriteFile("qcc.cfg", s, strlen(s));
2973 strcpy(QCC_copyright, "This file was created with ForeThought's modified QuakeC compiler\nThanks to ID Software");
2974 for (p = 0; p < 5; p++)
2975 strcpy(QCC_Packname[p], "");
2977 for (p = 0; compiler_flag[p].enabled; p++)
2979 *compiler_flag[p].enabled = compiler_flag[p].flags & FLAG_ASDEFAULT;
2983 QCC_SetDefaultProperties();
2985 optres_shortenifnots = 0;
2986 optres_overlaptemps = 0;
2987 optres_noduplicatestrings = 0;
2988 optres_constantarithmatic = 0;
2989 optres_nonvec_parms = 0;
2990 optres_constant_names = 0;
2991 optres_constant_names_strings = 0;
2992 optres_precache_file = 0;
2993 optres_filenames = 0;
2994 optres_assignments = 0;
2995 optres_unreferenced = 0;
2996 optres_function_names = 0;
2998 optres_dupconstdefs = 0;
2999 optres_return_only = 0;
3000 optres_compound_jumps = 0;
3001 // optres_comexprremoval = 0;
3002 optres_stripfunctions = 0;
3003 optres_locals_marshalling = 0;
3004 optres_logicops = 0;
3009 accglobalsblock = 0;
3016 strings = (void *)qccHunkAlloc(sizeof(char) * MAX_STRINGS);
3019 statements = (void *)qccHunkAlloc(sizeof(QCC_dstatement_t) * MAX_STATEMENTS);
3021 statement_linenums = (void *)qccHunkAlloc(sizeof(int) * MAX_STATEMENTS);
3023 functions = (void *)qccHunkAlloc(sizeof(QCC_dfunction_t) * MAX_FUNCTIONS);
3028 qcc_pr_globals = (void *)qccHunkAlloc(sizeof(float) * MAX_REGS);
3031 Hash_InitTable(&globalstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2)));
3032 Hash_InitTable(&localstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2)));
3033 Hash_InitTable(&floatconstdefstable, MAX_REGS/2+1, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2+1)));
3034 Hash_InitTable(&stringconstdefstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2)));
3035 Hash_InitTable(&stringconstdefstable_trans, 1000, qccHunkAlloc(Hash_BytesForBuckets(1000)));
3036 dotranslate_count = 0;
3038 // pr_global_defs = (QCC_def_t **)qccHunkAlloc(sizeof(QCC_def_t *) * MAX_REGS);
3040 qcc_globals = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_GLOBALS);
3043 fields = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_FIELDS);
3046 memset(pr_immediate_string, 0, sizeof(pr_immediate_string));
3048 precache_sounds = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_SOUNDS);
3049 precache_sounds_block = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS);
3050 precache_sounds_used = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS);
3053 precache_textures = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_TEXTURES);
3054 precache_textures_block = (void *)qccHunkAlloc(sizeof(int)*MAX_TEXTURES);
3057 precache_models = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_MODELS);
3058 precache_models_block = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS);
3059 precache_models_used = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS);
3062 precache_files = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_FILES);
3063 precache_files_block = (void *)qccHunkAlloc(sizeof(int)*MAX_FILES);
3066 qcc_typeinfo = (void *)qccHunkAlloc(sizeof(QCC_type_t)*maxtypeinfos);
3069 qcc_tempofs = qccHunkAlloc(sizeof(int) * max_temps);
3074 memset(&pr, 0, sizeof(pr));
3075 #ifdef MAX_EXTRA_PARMS
3076 memset(&extra_parms, 0, sizeof(extra_parms));
3079 if ( QCC_CheckParm ("/?") || QCC_CheckParm ("?") || QCC_CheckParm ("-?") || QCC_CheckParm ("-help") || QCC_CheckParm ("--help"))
3081 printf ("qcc looks for progs.src in the current directory.\n");
3082 printf ("to look in a different directory: qcc -src <directory>\n");
3083 // printf ("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
3084 // printf ("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
3085 // printf ("to bsp all bmodels: qcc -bspmodels <gamedir>\n");
3086 printf ("-Fwasm <funcname> causes FTEQCC to dump all asm to qc.asm\n");
3087 printf ("-O0 to disable optimisations\n");
3088 printf ("-O1 to optimise for size\n");
3089 printf ("-O2 to optimise more - some behaviours may change\n");
3090 printf ("-O3 to optimise lots - experimental or non-future-proof\n");
3091 printf ("-Oname to enable an optimisation\n");
3092 printf ("-Ono-name to disable optimisations\n");
3093 printf ("-Kkeyword to activate keyword\n");
3094 printf ("-Kno-keyword to disable keyword\n");
3095 printf ("-Wall to give a stupid number of warnings\n");
3096 printf ("-Ttarget to set a output format\n");
3097 printf ("-Fautoproto to enable automatic prototyping\n");
3098 printf ("-Fsubscope to make locals specific to their subscope\n");
3100 qcc_compileactive = false;
3104 if (flag_caseinsensative)
3106 printf("Compiling without case sensativity\n");
3107 pHash_Get = &Hash_GetInsensative;
3108 pHash_GetNext = &Hash_GetNextInsensative;
3109 pHash_Add = &Hash_AddInsensative;
3113 if (opt_locals_marshalling)
3114 printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nLocals marshalling might be buggy. Use with caution\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
3116 p = QCC_CheckParm ("-src");
3117 if (p && p < argc-1 )
3119 strcpy (qccmsourcedir, argv[p+1]);
3120 strcat (qccmsourcedir, "/");
3121 printf ("Source directory: %s\n", qccmsourcedir);
3124 *qccmsourcedir = '\0';
3128 QCC_PR_BeginCompilation ((void *)qccHunkAlloc (0x100000), 0x100000);
3132 if (!QCC_FindQCFiles())
3133 QCC_Error (ERR_COULDNTOPENFILE, "Couldn't open file for asm output.");
3137 if (!numsourcefiles)
3139 p = QCC_CheckParm ("-qc");
3140 if (!p || p >= argc-1 || argv[p+1][0] == '-')
3141 p = QCC_CheckParm ("-srcfile");
3142 if (p && p < argc-1 )
3143 sprintf (qccmprogsdat, "%s", argv[p+1]);
3145 { //look for a preprogs.src... :o)
3146 sprintf (qccmprogsdat, "preprogs.src");
3147 if (externs->FileSize(qccmprogsdat) <= 0)
3148 sprintf (qccmprogsdat, "progs.src");
3152 strcpy(sourcefileslist[numsourcefiles++], qccmprogsdat);
3153 currentsourcefile = 0;
3155 else if (currentsourcefile == numsourcefiles)
3158 qcc_compileactive = false;
3160 currentsourcefile = 0;
3164 if (currentsourcefile)
3165 printf("-------------------------------------\n");
3167 sprintf (qccmprogsdat, "%s%s", qccmsourcedir, sourcefileslist[currentsourcefile++]);
3168 printf ("Source file: %s\n", qccmprogsdat);
3170 if (QCC_LoadFile (qccmprogsdat, (void *)&qccmsrc) == -1)
3179 asmfile = fopen("qc.asm", "wb");
3181 QCC_Error (ERR_INTERNAL, "Couldn't open file for asm output.");
3185 newstylesource = false;
3186 while(*qccmsrc && *qccmsrc < ' ')
3188 pr_file_p = QCC_COM_Parse(qccmsrc);
3190 if (QCC_CheckParm ("-qc"))
3192 strcpy(destfile, qccmprogsdat);
3193 StripExtension(destfile);
3194 strcat(destfile, ".qco");
3196 p = QCC_CheckParm ("-o");
3197 if (!p || p >= argc-1 || argv[p+1][0] == '-')
3198 if (p && p < argc-1 )
3199 sprintf (destfile, "%s%s", qccmsourcedir, argv[p+1]);
3203 if (*qcc_token == '#')
3205 void StartNewStyleCompile(void);
3207 newstylesource = true;
3208 StartNewStyleCompile();
3212 pr_file_p = qccmsrc;
3213 QCC_PR_LexWhitespace();
3214 qccmsrc = pr_file_p;
3217 pr_file_p = qccmsrc;
3218 QCC_PR_SimpleGetToken ();
3219 strcpy(qcc_token, pr_token);
3220 qccmsrc = pr_file_p;
3223 QCC_Error (ERR_NOOUTPUT, "No destination filename. qcc -help for info.");
3224 strcpy (destfile, qcc_token);
3228 s2 = strcpy(destfile2, destfile);
3229 if (!strncmp(s2, "./", 2))
3233 while(!strncmp(s2, "../", 3))
3239 strcpy(qccmfilename, qccmsourcedir);
3240 for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--)
3242 if (*s == '/' || *s == '\\')
3248 sprintf(destfile, "%s", s2);
3252 memmove(destfile+3, destfile, strlen(destfile)+1);
3263 pbool modified = false;
3265 if (stat(destfile, &os) != -1)
3267 while ((pr_file_p=QCC_COM_Parse(pr_file_p)))
3269 if (stat(qcc_token, &s) == -1 || s.st_mtime > os.st_mtime)
3271 printf("%s changed\n", qcc_token);
3278 printf("No changes\n");
3279 qcc_compileactive = false;
3284 pr_file_p = qccmsrc;
3289 printf ("outputfile: %s\n", destfile);
3293 currentchunk = NULL;
3295 originalqccmsrc = qccmsrc;
3298 void new_QCC_ContinueCompile(void);
3299 //called between exe frames - won't loose net connection (is the theory)...
3300 void QCC_ContinueCompile(void)
3303 currentchunk = NULL;
3304 if (!qcc_compileactive)
3310 new_QCC_ContinueCompile();
3314 qccmsrc = QCC_COM_Parse(qccmsrc);
3319 qccmsrc = originalqccmsrc;
3320 QCC_SetDefaultProperties();
3321 autoprototype = false;
3324 QCC_FinishCompile();
3329 QCC_main(myargc, myargv);
3334 strcpy (qccmfilename, qccmsourcedir);
3337 if (!strncmp(s, "..\\", 3) || !strncmp(s, "../", 3))
3339 s2 = qccmfilename + strlen(qccmfilename)-2;
3340 while (s2>=qccmfilename)
3342 if (*s2 == '/' || *s2 == '\\')
3349 if (s2>=qccmfilename)
3355 if (!strncmp(s, ".\\", 2) || !strncmp(s, "./", 2))
3363 strcat (qccmfilename, s);
3365 printf ("prototyping %s\n", qccmfilename);
3368 printf ("compiling %s\n", qccmfilename);
3370 QCC_LoadFile (qccmfilename, (void *)&qccmsrc2);
3372 if (!QCC_PR_CompileFile (qccmsrc2, qccmfilename) )
3373 QCC_Error (ERR_PARSEERRORS, "Errors have occured\n");
3375 void QCC_FinishCompile(void)
3377 pbool donesomething;
3380 currentchunk = NULL;
3382 if (setjmp(pr_parse_abort))
3383 QCC_Error(ERR_INTERNAL, "");
3385 if (!QCC_PR_FinishCompilation ())
3387 QCC_Error (ERR_PARSEERRORS, "compilation errors");
3390 /* p = QCC_CheckParm ("-asm");
3393 for (p++ ; p<myargc ; p++)
3395 if (myargv[p][0] == '-')
3397 QCC_PrintFunction (myargv[p]);
3401 /*p = QCC_CheckParm ("-ofs");
3404 for (p++ ; p<myargc ; p++)
3406 if (myargv[p][0] == '-')
3408 QCC_PrintOfs (atoi(myargv[p]));
3412 if (pr_werror && pr_warning_count != 0)
3413 QCC_Error (ERR_PARSEERRORS, "compilation errors");
3416 crc = QCC_PR_WriteProgdefs ("progdefs.h");
3419 donesomething = QCC_WriteData (crc);
3421 // regenerate bmodels if -bspmodels
3424 // report / copy the data files
3431 printf ("Compile Complete\n\n");
3433 if (optres_shortenifnots)
3434 printf("optres_shortenifnots %i\n", optres_shortenifnots);
3435 if (optres_overlaptemps)
3436 printf("optres_overlaptemps %i\n", optres_overlaptemps);
3437 if (optres_noduplicatestrings)
3438 printf("optres_noduplicatestrings %i\n", optres_noduplicatestrings);
3439 if (optres_constantarithmatic)
3440 printf("optres_constantarithmatic %i\n", optres_constantarithmatic);
3441 if (optres_nonvec_parms)
3442 printf("optres_nonvec_parms %i\n", optres_nonvec_parms);
3443 if (optres_constant_names)
3444 printf("optres_constant_names %i\n", optres_constant_names);
3445 if (optres_constant_names_strings)
3446 printf("optres_constant_names_strings %i\n", optres_constant_names_strings);
3447 if (optres_precache_file)
3448 printf("optres_precache_file %i\n", optres_precache_file);
3449 if (optres_filenames)
3450 printf("optres_filenames %i\n", optres_filenames);
3451 if (optres_assignments)
3452 printf("optres_assignments %i\n", optres_assignments);
3453 if (optres_unreferenced)
3454 printf("optres_unreferenced %i\n", optres_unreferenced);
3456 printf("optres_locals %i\n", optres_locals);
3457 if (optres_function_names)
3458 printf("optres_function_names %i\n", optres_function_names);
3459 if (optres_dupconstdefs)
3460 printf("optres_dupconstdefs %i\n", optres_dupconstdefs);
3461 if (optres_return_only)
3462 printf("optres_return_only %i\n", optres_return_only);
3463 if (optres_compound_jumps)
3464 printf("optres_compound_jumps %i\n", optres_compound_jumps);
3465 // if (optres_comexprremoval)
3466 // printf("optres_comexprremoval %i\n", optres_comexprremoval);
3467 if (optres_stripfunctions)
3468 printf("optres_stripfunctions %i\n", optres_stripfunctions);
3469 if (optres_locals_marshalling)
3470 printf("optres_locals_marshalling %i\n", optres_locals_marshalling);
3471 if (optres_logicops)
3472 printf("optres_logicops %i\n", optres_logicops);
3476 printf("optres_test1 %i\n", optres_test1);
3478 printf("optres_test2 %i\n", optres_test2);
3480 printf("numtemps %i\n", numtemps);
3482 if (!flag_msvcstyle)
3483 printf("%i warnings\n", pr_warning_count);
3486 qcc_compileactive = false;
3493 extern char *compilingfile;
3494 extern QCC_string_t s_file, s_file2;
3495 extern char *pr_file_p;
3496 extern int pr_source_line;
3497 extern QCC_def_t *pr_scope;
3498 void QCC_PR_ParseDefs (char *classname);
3504 void StartNewStyleCompile(void)
3506 if (setjmp(pr_parse_abort))
3508 if (++pr_error_count > MAX_ERRORS)
3510 if (setjmp(pr_parse_abort))
3513 QCC_PR_SkipToSemicolon ();
3514 if (pr_token_type == tt_eof)
3519 QCC_PR_ClearGrabMacros (); // clear the frame macros
3521 compilingfile = qccmprogsdat;
3523 pr_file_p = qccmsrc;
3524 s_file = s_file2 = QCC_CopyString (compilingfile);
3528 QCC_PR_NewLine (false);
3530 QCC_PR_Lex (); // read first token
3532 void new_QCC_ContinueCompile(void)
3534 if (setjmp(pr_parse_abort))
3536 // if (pr_error_count != 0)
3538 QCC_Error (ERR_PARSEERRORS, "Errors have occured");
3541 QCC_PR_SkipToSemicolon ();
3542 if (pr_token_type == tt_eof)
3546 if (pr_token_type == tt_eof)
3549 QCC_Error (ERR_PARSEERRORS, "Errors have occured");
3550 QCC_FinishCompile();
3555 QCC_main(myargc, myargv);
3559 pr_scope = NULL; // outside all functions
3561 QCC_PR_ParseDefs (NULL);
3564 /*void new_QCC_ContinueCompile(void)
3567 if (!qcc_compileactive)
3571 // compile all the files
3573 qccmsrc = QCC_COM_Parse(qccmsrc);
3576 QCC_FinishCompile();
3581 strcpy (qccmfilename, qccmsourcedir);
3584 if (!strncmp(s, "..\\", 3))
3586 s2 = qccmfilename + strlen(qccmfilename)-2;
3587 while (s2>=qccmfilename)
3589 if (*s2 == '/' || *s2 == '\\')
3599 if (!strncmp(s, ".\\", 2))
3607 // strcat (qccmfilename, s);
3608 // printf ("compiling %s\n", qccmfilename);
3609 // QCC_LoadFile (qccmfilename, (void *)&qccmsrc2);
3611 // if (!new_QCC_PR_CompileFile (qccmsrc2, qccmfilename) )
3612 // QCC_Error ("Errors have occured\n");
3618 QCC_Error ("PR_CompileFile: Didn't clear");
3620 QCC_PR_ClearGrabMacros (); // clear the frame macros
3622 compilingfile = filename;
3624 pr_file_p = qccmsrc2;
3625 s_file = QCC_CopyString (filename);
3631 QCC_PR_Lex (); // read first token
3633 while (pr_token_type != tt_eof)
3635 if (setjmp(pr_parse_abort))
3637 if (++pr_error_count > MAX_ERRORS)
3639 QCC_PR_SkipToSemicolon ();
3640 if (pr_token_type == tt_eof)
3644 pr_scope = NULL; // outside all functions
3646 QCC_PR_ParseDefs ();
3649 return (pr_error_count == 0);