#include "qcc.h" char sourcedir[1024]; char destfile[1024]; float pr_globals[MAX_REGS]; int numpr_globals; char strings[MAX_STRINGS]; int strofs; dstatement_t statements[MAX_STATEMENTS]; int numstatements; int statement_linenums[MAX_STATEMENTS]; dfunction_t functions[MAX_FUNCTIONS]; int numfunctions; ddef_t globals[MAX_GLOBALS]; int numglobaldefs; ddef_t fields[MAX_FIELDS]; int numfielddefs; char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH]; int precache_sounds_block[MAX_SOUNDS]; int numsounds; char precache_models[MAX_MODELS][MAX_DATA_PATH]; int precache_models_block[MAX_SOUNDS]; int nummodels; char precache_files[MAX_FILES][MAX_DATA_PATH]; int precache_files_block[MAX_SOUNDS]; int numfiles; /* ============ WriteFiles Generates files.dat, which contains all of the data files actually used by the game, to be processed by qfiles.exe ============ */ void WriteFiles (void) { FILE *f; int i; char filename[1024]; sprintf (filename, "%sfiles.dat", sourcedir); f = fopen (filename, "w"); if (!f) Error ("Couldn't open %s", filename); fprintf (f, "%i\n", numsounds); for (i=0 ; is_file, strings + d->s_name, d->first_statement, d->parm_start); for (j=0 ; jnumparms ; j++) printf ("%i ",d->parm_size[j]); printf (")\n"); } } void PrintFields (void) { int i; ddef_t *d; for (i=0 ; iofs, d->type, strings + d->s_name); } } void PrintGlobals (void) { int i; ddef_t *d; for (i=0 ; iofs, d->type, strings + d->s_name); } } void InitData (void) { int i; numstatements = 1; strofs = 1; numfunctions = 1; numglobaldefs = 1; numfielddefs = 1; def_ret.ofs = OFS_RETURN; for (i=0 ; inext) { if (def->type->type == ev_function) { // df = &functions[numfunctions]; // numfunctions++; } else if (def->type->type == ev_field) { dd = &fields[numfielddefs]; numfielddefs++; dd->type = def->type->aux_type->type; dd->s_name = CopyString (def->name); dd->ofs = G_INT(def->ofs); } dd = &globals[numglobaldefs]; numglobaldefs++; dd->type = def->type->type; if ( !def->initialized && def->type->type != ev_function && def->type->type != ev_field && def->scope == NULL) dd->type |= DEF_SAVEGLOBGAL; dd->s_name = CopyString (def->name); dd->ofs = def->ofs; } //PrintStrings (); //PrintFunctions (); //PrintFields (); //PrintGlobals (); strofs = (strofs+3)&~3; printf ("%6i strofs\n", strofs); printf ("%6i numstatements\n", numstatements); printf ("%6i numfunctions\n", numfunctions); printf ("%6i numglobaldefs\n", numglobaldefs); printf ("%6i numfielddefs\n", numfielddefs); printf ("%6i numpr_globals\n", numpr_globals); h = SafeOpenWrite (destfile); SafeWrite (h, &progs, sizeof(progs)); progs.ofs_strings = ftell (h); progs.numstrings = strofs; SafeWrite (h, strings, strofs); progs.ofs_statements = ftell (h); progs.numstatements = numstatements; for (i=0 ; i 60) { *s++ = '.'; *s++ = '.'; *s++ = '.'; break; } } *s++ = '"'; *s++ = 0; return buf; } def_t *PR_DefForFieldOfs (gofs_t ofs) { def_t *d; for (d=pr.def_head.next ; d ; d=d->next) { if (d->type->type != ev_field) continue; if (*((int *)&pr_globals[d->ofs]) == ofs) return d; } Error ("PR_DefForFieldOfs: couldn't find %i",ofs); return NULL; } /* ============ PR_ValueString Returns a string describing *data in a type specific manner ============= */ char *PR_ValueString (etype_t type, void *val) { static char line[256]; def_t *def; dfunction_t *f; switch (type) { case ev_string: sprintf (line, "%s", PR_String(strings + *(int *)val)); break; case ev_entity: sprintf (line, "entity %i", *(int *)val); break; case ev_function: f = functions + *(int *)val; if (!f) sprintf (line, "undefined function"); else sprintf (line, "%s()", strings + f->s_name); break; case ev_field: def = PR_DefForFieldOfs ( *(int *)val ); sprintf (line, ".%s", def->name); break; case ev_void: sprintf (line, "void"); break; case ev_float: sprintf (line, "%5.1f", *(float *)val); break; case ev_vector: sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); break; case ev_pointer: sprintf (line, "pointer"); break; default: sprintf (line, "bad type %i", type); break; } return line; } /* ============ PR_GlobalString Returns a string with a description and the contents of a global, padded to 20 field width ============ */ char *PR_GlobalStringNoContents (gofs_t ofs) { int i; def_t *def; void *val; static char line[128]; val = (void *)&pr_globals[ofs]; def = pr_global_defs[ofs]; if (!def) // Error ("PR_GlobalString: no def for %i", ofs); sprintf (line,"%i(???)", ofs); else sprintf (line,"%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) strcat (line," "); strcat (line," "); return line; } char *PR_GlobalString (gofs_t ofs) { char *s; int i; def_t *def; void *val; static char line[128]; val = (void *)&pr_globals[ofs]; def = pr_global_defs[ofs]; if (!def) return PR_GlobalStringNoContents(ofs); if (def->initialized && def->type->type != ev_function) { s = PR_ValueString (def->type->type, &pr_globals[ofs]); sprintf (line,"%i(%s)", ofs, s); } else sprintf (line,"%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) strcat (line," "); strcat (line," "); return line; } /* ============ PR_PrintOfs ============ */ void PR_PrintOfs (gofs_t ofs) { printf ("%s\n",PR_GlobalString(ofs)); } /* ================= PR_PrintStatement ================= */ void PR_PrintStatement (dstatement_t *s) { int i; printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname); i = strlen(pr_opcodes[s->op].opname); for ( ; i<10 ; i++) printf (" "); if (s->op == OP_IF || s->op == OP_IFNOT) printf ("%sbranch %i",PR_GlobalString(s->a),s->b); else if (s->op == OP_GOTO) { printf ("branch %i",s->a); } else if ( (unsigned)(s->op - OP_STORE_F) < 6) { printf ("%s",PR_GlobalString(s->a)); printf ("%s", PR_GlobalStringNoContents(s->b)); } else { if (s->a) printf ("%s",PR_GlobalString(s->a)); if (s->b) printf ("%s",PR_GlobalString(s->b)); if (s->c) printf ("%s", PR_GlobalStringNoContents(s->c)); } printf ("\n"); } /* ============ PR_PrintDefs ============ */ void PR_PrintDefs (void) { def_t *d; for (d=pr.def_head.next ; d ; d=d->next) PR_PrintOfs (d->ofs); } /* ============== PR_BeginCompilation called before compiling a batch of files, clears the pr struct ============== */ void PR_BeginCompilation (void *memory, int memsize) { int i; pr.memory = memory; pr.max_memory = memsize; numpr_globals = RESERVED_OFS; pr.def_tail = &pr.def_head; for (i=0 ; inext) { if (d->type->type == ev_function && !d->scope)// function parms are ok { // f = G_FUNCTION(d->ofs); // if (!f || (!f->code && !f->builtin) ) if (!d->initialized) { printf ("function %s was not defined\n",d->name); errors = true; } } } return !errors; } //============================================================================= /* ============ PR_WriteProgdefs Writes the global and entity structures out Returns a crc of the header, to be stored in the progs file for comparison at load time. ============ */ int PR_WriteProgdefs (char *filename) { def_t *d; FILE *f; unsigned short crc; int c; printf ("writing %s\n", filename); f = fopen (filename, "w"); // print global vars until the first field is defined fprintf (f,"\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[%i];\n", RESERVED_OFS); for (d=pr.def_head.next ; d ; d=d->next) { if (!strcmp (d->name, "end_sys_globals")) break; switch (d->type->type) { case ev_float: fprintf (f, "\tfloat\t%s;\n",d->name); break; case ev_vector: fprintf (f, "\tvec3_t\t%s;\n",d->name); d=d->next->next->next; // skip the elements break; case ev_string: fprintf (f,"\tstring_t\t%s;\n",d->name); break; case ev_function: fprintf (f,"\tfunc_t\t%s;\n",d->name); break; case ev_entity: fprintf (f,"\tint\t%s;\n",d->name); break; default: fprintf (f,"\tint\t%s;\n",d->name); break; } } fprintf (f,"} globalvars_t;\n\n"); // print all fields fprintf (f,"typedef struct\n{\n"); for (d=pr.def_head.next ; d ; d=d->next) { if (!strcmp (d->name, "end_sys_fields")) break; if (d->type->type != ev_field) continue; switch (d->type->aux_type->type) { case ev_float: fprintf (f,"\tfloat\t%s;\n",d->name); break; case ev_vector: fprintf (f,"\tvec3_t\t%s;\n",d->name); d=d->next->next->next; // skip the elements break; case ev_string: fprintf (f,"\tstring_t\t%s;\n",d->name); break; case ev_function: fprintf (f,"\tfunc_t\t%s;\n",d->name); break; case ev_entity: fprintf (f,"\tint\t%s;\n",d->name); break; default: fprintf (f,"\tint\t%s;\n",d->name); break; } } fprintf (f,"} entvars_t;\n\n"); fclose (f); // do a crc of the file CRC_Init (&crc); f = fopen (filename, "r+"); while ((c = fgetc(f)) != EOF) CRC_ProcessByte (&crc, (byte)c); fprintf (f,"#define PROGHEADER_CRC %i\n", crc); fclose (f); return crc; } void PrintFunction (char *name) { int i; dstatement_t *ds; dfunction_t *df; for (i=0 ; ifirst_statement; while (1) { PR_PrintStatement (ds); if (!ds->op) break; ds++; } } //============================================================================ /* ============ main ============ */ void main (int argc, char **argv) { char *src; char *src2; char filename[1024]; int p, crc; double start, stop; start = I_FloatTime (); myargc = argc; myargv = argv; if ( CheckParm ("-?") || CheckParm ("-help")) { printf ("qcc looks for progs.src in the current directory.\n"); printf ("to look in a different directory: qcc -src \n"); printf ("to build a clean data tree: qcc -copy \n"); printf ("to build a clean pak file: qcc -pak \n"); printf ("to bsp all bmodels: qcc -bspmodels \n"); return; } p = CheckParm ("-src"); if (p && p < argc-1 ) { strcpy (sourcedir, argv[p+1]); strcat (sourcedir, "/"); printf ("Source directory: %s\n", sourcedir); } else strcpy (sourcedir, ""); InitData (); sprintf (filename, "%sprogs.src", sourcedir); LoadFile (filename, (void *)&src); src = COM_Parse (src); if (!src) Error ("No destination filename. qcc -help for info.\n"); strcpy (destfile, com_token); printf ("outputfile: %s\n", destfile); pr_dumpasm = false; PR_BeginCompilation (malloc (0x100000), 0x100000); // compile all the files do { src = COM_Parse(src); if (!src) break; sprintf (filename, "%s%s", sourcedir, com_token); printf ("compiling %s\n", filename); LoadFile (filename, (void *)&src2); if (!PR_CompileFile (src2, filename) ) exit (1); } while (1); if (!PR_FinishCompilation ()) Error ("compilation errors"); p = CheckParm ("-asm"); if (p) { for (p++ ; p