quakeforge/tools/qfcc/source/qfcc.c
Bill Currie 3505de6868 Point the near and far data spaced into the merged data space.
This lets the relocations work on the final data without having to adjust
their locations.
2011-02-12 22:35:44 +09:00

961 lines
23 KiB
C

/*
qfcc.c
QuakeForge Code Compiler (main program)
Copyright (C) 1996-1997 id Software, Inc.
Copyright (C) 2001 Jeff Teunissen <deek@quakeforge.net>
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] = "$Id$";
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_IO_H
#include <io.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <QF/cbuf.h>
#include <QF/crc.h>
#include <QF/dstring.h>
#include <QF/hash.h>
#include <QF/qendian.h>
#include <QF/script.h>
#include <QF/sys.h>
#include <QF/va.h>
#include "qfcc.h"
#include "class.h"
#include "codespace.h"
#include "cpp.h"
#include "debug.h"
#include "def.h"
#include "defspace.h"
#include "diagnostic.h"
#include "emit.h"
#include "expr.h"
#include "function.h"
#include "idstuff.h"
#include "immediate.h"
#include "linker.h"
#include "method.h"
#include "obj_file.h"
#include "opcodes.h"
#include "options.h"
#include "reloc.h"
#include "strpool.h"
#include "struct.h"
#include "symtab.h"
#include "type.h"
options_t options;
const char *sourcedir;
const char *progs_src;
char debugfile[1024];
pr_info_t pr;
ddef_t *globals;
int numglobaldefs;
int num_localdefs;
const char *big_function = 0;
ddef_t *fields;
int numfielddefs;
#ifdef _WIN32
char *
fix_backslash (char *path)
{
char *s;
for (s = path; *s; s++)
if (*s == '\\')
*s = '/';
return path;
}
#endif
static void
InitData (void)
{
if (pr.code) {
codespace_delete (pr.code);
strpool_delete (pr.strings);
}
memset (&pr, 0, sizeof (pr));
pr.source_line = 1;
pr.error_count = 0;
pr.code = codespace_new ();
memset (codespace_newstatement (pr.code), 0, sizeof (dstatement_t));
pr.strings = strpool_new ();
pr.num_functions = 1;
pr.data = new_defspace ();
pr.far_data = new_defspace ();
pr.near_data = new_defspace ();
pr.near_data->data = calloc (65536, sizeof (pr_type_t));
pr.near_data->max_size = 65536;
pr.near_data->grow = 0;
pr.symtab = new_symtab (0, stab_global);
pr.symtab->space = pr.near_data;
pr.entity_data = new_defspace ();
numglobaldefs = 1;
numfielddefs = 1;
}
static int
WriteData (int crc)
{
def_t *def;
ddef_t *dd;
dprograms_t progs;
pr_debug_header_t debug;
QFile *h;
int i;
int num_defs = 0;
for (def = pr.data->defs; def; def = def->next)
num_defs++;
globals = calloc (num_defs + 1, sizeof (ddef_t));
fields = calloc (num_defs + 1, sizeof (ddef_t));
for (def = pr.data->defs; def; def = def->next) {
if (def->local || !def->name)
continue;
if (options.code.progsversion == PROG_ID_VERSION && *def->name == '.'
&& strcmp (def->name, ".imm") != 0
&& strcmp (def->name, ".debug_file") != 0)
continue;
if (def->type->type == ev_func) {
} else if (def->type->type == ev_field
&& strcmp (def->name, ".imm") != 0) {
dd = &fields[numfielddefs++];
def_to_ddef (def, dd, 1);
dd->ofs = D_INT (def);
}
dd = &globals[numglobaldefs++];
def_to_ddef (def, dd, 0);
if (!def->nosave
&& !def->constant
&& def->type->type != ev_func
&& def->type->type != ev_field && def->global)
dd->type |= DEF_SAVEGLOBAL;
}
while (pr.strings->size & 3)
pr.strings->strings[pr.strings->size++] = 0;
if (options.verbosity >= 0) {
if (!big_function)
big_function = "";
printf ("%6i strofs\n", pr.strings->size);
printf ("%6i statements\n", pr.code->size);
printf ("%6i functions\n", pr.num_functions);
printf ("%6i global defs\n", numglobaldefs);
printf ("%6i fielddefs\n", numfielddefs);
printf ("%6i globals\n", pr.data->size);
printf (" %6i near globals\n", pr.near_data->size);
printf (" %6i locals size (%s)\n", num_localdefs, big_function);
printf (" %6i far globals\n", pr.far_data->size);
printf ("%6i entity fields\n", pr.entity_data->size);
}
if (!(h = Qopen (options.output_file, "wb")))
Sys_Error ("%s: %s\n", options.output_file, strerror(errno));
memset (&progs, 0, sizeof (progs));
Qwrite (h, &progs, sizeof (progs));
progs.ofs_strings = Qtell (h);
progs.numstrings = pr.strings->size;
Qwrite (h, pr.strings->strings, pr.strings->size);
progs.ofs_statements = Qtell (h);
progs.numstatements = pr.code->size;
for (i = 0; i < pr.code->size; i++) {
pr.code->code[i].op = LittleShort (pr.code->code[i].op);
pr.code->code[i].a = LittleShort (pr.code->code[i].a);
pr.code->code[i].b = LittleShort (pr.code->code[i].b);
pr.code->code[i].c = LittleShort (pr.code->code[i].c);
}
Qwrite (h, pr.code->code, pr.code->size * sizeof (dstatement_t));
{
dfunction_t *df;
progs.ofs_functions = Qtell (h);
progs.numfunctions = pr.num_functions;
for (i = 0, df = pr.functions + 1; i < pr.num_functions; i++, df++) {
df->first_statement = LittleLong (df->first_statement);
df->parm_start = LittleLong (df->parm_start);
df->s_name = LittleLong (df->s_name);
df->s_file = LittleLong (df->s_file);
df->numparms = LittleLong (df->numparms);
df->locals = LittleLong (df->locals);
}
Qwrite (h, pr.functions, pr.num_functions * sizeof (dfunction_t));
}
progs.ofs_globaldefs = Qtell (h);
progs.numglobaldefs = numglobaldefs;
for (i = 0; i < numglobaldefs; i++) {
globals[i].type = LittleShort (globals[i].type);
globals[i].ofs = LittleShort (globals[i].ofs);
globals[i].s_name = LittleLong (globals[i].s_name);
}
Qwrite (h, globals, numglobaldefs * sizeof (ddef_t));
progs.ofs_fielddefs = Qtell (h);
progs.numfielddefs = numfielddefs;
for (i = 0; i < numfielddefs; i++) {
fields[i].type = LittleShort (fields[i].type);
fields[i].ofs = LittleShort (fields[i].ofs);
fields[i].s_name = LittleLong (fields[i].s_name);
}
Qwrite (h, fields, numfielddefs * sizeof (ddef_t));
progs.ofs_globals = Qtell (h);
progs.numglobals = pr.data->size;
for (i = 0; i < pr.data->size; i++)
pr.data->data[i] = LittleLong (pr.data->data[i]);
Qwrite (h, pr.data->data, pr.data->size * 4);
if (options.verbosity >= -1)
printf ("%6i TOTAL SIZE\n", (int) Qtell (h));
progs.entityfields = pr.entity_data->size;
progs.version = options.code.progsversion;
progs.crc = crc;
// byte swap the header and write it out
for (i = 0; i < (int) sizeof (progs) / 4; i++)
((int *) &progs)[i] = LittleLong (((int *) &progs)[i]);
Qseek (h, 0, SEEK_SET);
Qwrite (h, &progs, sizeof (progs));
Qclose (h);
if (!options.code.debug) {
return 0;
}
if (!(h = Qopen (options.output_file, "rb")))
Sys_Error ("%s: %s\n", options.output_file, strerror(errno));
memset (&debug, 0, sizeof (debug));
debug.version = LittleLong (PROG_DEBUG_VERSION);
CRC_Init (&debug.crc);
while ((i = Qgetc (h)) != EOF)
CRC_ProcessByte (&debug.crc, i);
Qclose (h);
debug.crc = LittleShort (debug.crc);
debug.you_tell_me_and_we_will_both_know = 0;
if (!(h = Qopen (debugfile, "wb")))
Sys_Error ("%s: %s\n", options.output_file, strerror(errno));
Qwrite (h, &debug, sizeof (debug));
debug.auxfunctions = LittleLong (Qtell (h));
debug.num_auxfunctions = LittleLong (pr.num_auxfunctions);
for (i = 0; i < pr.num_auxfunctions; i++) {
pr.auxfunctions[i].function = LittleLong (pr.auxfunctions[i].function);
pr.auxfunctions[i].source_line = LittleLong (pr.auxfunctions[i].source_line);
pr.auxfunctions[i].line_info = LittleLong (pr.auxfunctions[i].line_info);
pr.auxfunctions[i].local_defs = LittleLong (pr.auxfunctions[i].local_defs);
pr.auxfunctions[i].num_locals = LittleLong (pr.auxfunctions[i].num_locals);
}
Qwrite (h, pr.auxfunctions,
pr.num_auxfunctions * sizeof (pr_auxfunction_t));
debug.linenos = LittleLong (Qtell (h));
debug.num_linenos = LittleLong (pr.num_linenos);
for (i = 0; i < pr.num_linenos; i++) {
pr.linenos[i].fa.addr = LittleLong (pr.linenos[i].fa.addr);
pr.linenos[i].line = LittleLong (pr.linenos[i].line);
}
Qwrite (h, pr.linenos, pr.num_linenos * sizeof (pr_lineno_t));
debug.locals = LittleLong (Qtell (h));
debug.num_locals = LittleLong (pr.num_locals);
for (i = 0; i < pr.num_locals; i++) {
pr.locals[i].type = LittleShort (pr.locals[i].type);
pr.locals[i].ofs = LittleShort (pr.locals[i].ofs);
pr.locals[i].s_name = LittleLong (pr.locals[i].s_name);
}
Qwrite (h, pr.locals, pr.num_locals * sizeof (ddef_t));
Qseek (h, 0, SEEK_SET);
Qwrite (h, &debug, sizeof (debug));
Qclose (h);
return 0;
}
static void
begin_compilation (void)
{
pr.func_tail = &pr.func_head;
pr.error_count = 0;
}
static void
setup_param_block (void)
{
static struct_def_t defs[] = {
{".zero", &type_zero},
{".return", &type_param},
{".param_0", &type_param},
{".param_1", &type_param},
{".param_2", &type_param},
{".param_3", &type_param},
{".param_4", &type_param},
{".param_5", &type_param},
{".param_6", &type_param},
{".param_7", &type_param},
};
size_t i;
symbol_t *sym;
for (i = 0; i < sizeof (defs) / sizeof (defs[0]); i++) {
sym = make_symbol (defs[i].name, defs[i].type, pr.symtab->space,
st_global);
symtab_addsymbol (pr.symtab, sym);
}
}
static qboolean
finish_compilation (void)
{
def_t *d;
qboolean errors = false;
function_t *f;
def_t *def;
dfunction_t *df;
int far_base;
for (d = pr.near_data->defs; d; d = d->next) {
if (d->external && d->relocs) {
#if 0 //FIXME
if (strcmp (d->name, ".self") == 0) {
get_def (d->type, ".self", pr.scope, st_global);
} else if (strcmp (d->name, ".this") == 0) {
get_def (d->type, ".this", pr.scope, st_global);
} else {
#endif
errors = true;
error (0, "undefined global %s", d->name);
//FIXME }
}
}
for (d = pr.far_data->defs; d; d = d->next) {
if (d->external && d->relocs) {
errors = true;
error (0, "undefined global %s", d->name);
}
}
if (errors)
return !errors;
pr.functions = calloc (pr.num_functions + 1, sizeof (dfunction_t));
for (df = pr.functions + 1, f = pr.func_head; f; df++, f = f->next) {
df->s_name = f->s_name;
df->s_file = f->s_file;
df->numparms = function_parms (f, df->parm_size);
if (f->symtab && f->symtab->space)
df->locals = f->symtab->space->size;
if (f->builtin) {
df->first_statement = -f->builtin;
continue;
}
if (!f->code)
continue;
df->first_statement = f->code;
if (options.code.local_merging) {
if (f->symtab->space->size > num_localdefs) {
num_localdefs = f->symtab->space->size;
big_function = f->def->name;
}
df->parm_start = pr.near_data->size;
} else {
df->parm_start = defspace_new_loc (pr.near_data,
f->symtab->space->size);
num_localdefs += f->symtab->space->size;
}
for (def = f->symtab->space->defs; def; def = def->next) {
if (!def->local)
continue;
def->offset += df->parm_start;
}
}
if (options.code.local_merging)
defspace_new_loc (pr.near_data, num_localdefs);
if (options.code.progsversion != PROG_ID_VERSION) {
//FIXME better init code
symbol_t *sym = new_symbol (".param_size");
initialize_def (sym, &type_integer, 0, pr.far_data, st_global);
D_INT (sym->s.def) = type_size (&type_param);
}
if (options.code.debug) {
//FIXME better init code
symbol_t *sym = new_symbol (".debug_file");
initialize_def (sym, &type_string, 0, pr.far_data, st_global);
EMIT_STRING (sym->s.def->space, D_STRUCT (string_t, sym->s.def),
debugfile);
}
// merge near and far data
defspace_add_data (pr.data, pr.near_data->data, pr.near_data->size);
far_base = pr.data->size;
defspace_add_data (pr.data, pr.far_data->data, pr.far_data->size);
for (d = pr.far_data->defs; d; d = d->next) {
if (!d->external)
d->offset += far_base;
}
if (pr.near_data->defs) {
pr.data->defs = pr.near_data->defs;
pr.data->def_tail = pr.near_data->def_tail;
pr.near_data->defs = 0;
pr.near_data->def_tail = &pr.near_data->defs;
}
if (pr.far_data->defs) {
*pr.data->def_tail = pr.far_data->defs;
pr.data->def_tail = pr.far_data->def_tail;
pr.far_data->defs = 0;
pr.far_data->def_tail = &pr.far_data->defs;
}
// point near and far data spaces into the merged data. this allows
// relocations to work without having to adjust their location.
pr.near_data->data = pr.data->data;
pr.far_data->data = pr.data->data + far_base;
// check to make sure all functions prototyped have code
if (options.warnings.undefined_function) {
for (d = pr.data->defs; d; d = d->next) {
if (d->type->type == ev_func && d->global) {
// function args ok
//FIXME if (d->used) {
if (!d->initialized) {
warning (0, "function %s was called but not defined\n",
d->name);
}
//FIXME }
}
}
}
for (def = pr.data->defs; def; def = def->next)
relocate_refs (def->relocs, def->offset);
for (df = pr.functions + 1, f = pr.func_head; f; df++, f = f->next) {
relocate_refs (f->refs, f->function_num);
if (!f->code)
continue;
for (def = f->symtab->space->defs; def; def = def->next) {
if (!def->local)
continue;
relocate_refs (def->relocs, def->offset);
}
}
return !errors;
}
const char *
strip_path (const char *filename)
{
const char *p = filename;
int i = options.strip_path;
while (i-- > 0) {
while (*p && *p != '/')
p++;
if (!*p)
break;
filename = ++p;
}
return filename;
}
static void
setup_sym_file (const char *output_file)
{
if (options.code.debug) {
char *s;
strcpy (debugfile, output_file);
s = debugfile + strlen (debugfile);
while (s-- > debugfile) {
if (*s == '.')
break;
if (*s == '/' || *s == '\\') {
s = debugfile + strlen (debugfile);
break;
}
}
strcpy (s, ".sym");
if (options.verbosity >= 1)
printf ("debug file: %s\n", debugfile);
}
}
static int
compile_to_obj (const char *file, const char *obj)
{
int err;
yyin = preprocess_file (file, 0);
if (!yyin)
return !options.preprocess_only;
InitData ();
clear_frame_macros ();
clear_classes ();
clear_immediates ();
clear_selectors ();
chain_initial_types ();
begin_compilation ();
pr.source_file = ReuseString (strip_path (file));
err = yyparse () || pr.error_count;
fclose (yyin);
if (cpp_name && !options.save_temps) {
if (unlink (tempname->str)) {
perror ("unlink");
exit (1);
}
}
if (!err) {
qfo_t *qfo;
class_finish_module ();
qfo = qfo_from_progs (&pr);
err = qfo_write (qfo, obj);
qfo_delete (qfo);
}
return err;
}
static int
separate_compile (void)
{
const char **file;
const char **temp_files;
dstring_t *output_file = dstring_newstr ();
dstring_t *extension = dstring_newstr ();
char *f;
int err = 0;
int i;
if (options.compile && options.output_file && source_files[1]) {
fprintf (stderr,
"%s: cannot use -c and -o together with multiple files\n",
this_program);
return 1;
}
for (file = source_files, i = 0; *file; file++)
i++;
temp_files = calloc (i + 1, sizeof (const char*));
for (file = source_files, i = 0; *file; file++) {
dstring_clearstr (extension);
dstring_clearstr (output_file);
dstring_appendstr (output_file, *file);
f = output_file->str + strlen (output_file->str);
while (f >= output_file->str && *f != '.' && *f != '/')
f--;
if (f >= output_file->str && *f == '.') {
output_file->size -= strlen (f);
dstring_appendstr (extension, f);
*f = 0;
}
if (options.compile && options.output_file) {
dstring_clearstr (output_file);
dstring_appendstr (output_file, options.output_file);
} else {
dstring_appendstr (output_file, ".qfo");
}
if (strncmp (*file, "-l", 2)
&& (!strcmp (extension->str, ".r")
|| !strcmp (extension->str, ".qc")
|| !strcmp (extension->str, ".c"))) {
if (options.verbosity >= 2)
printf ("%s %s\n", *file, output_file->str);
temp_files[i++] = save_string (output_file->str);
err = compile_to_obj (*file, output_file->str) || err;
free ((char *)*file);
*file = strdup (output_file->str);
} else {
if (options.compile)
fprintf (stderr, "%s: %s: ignoring object file since linking "
"not done\n", this_program, *file);
}
}
if (!err && !options.compile) {
qfo_t *qfo;
linker_begin ();
for (file = source_files; *file; file++) {
if (strncmp (*file, "-l", 2)) {
if (strlen (*file) >= 2
&& strcmp (*file + strlen (*file) - 2, ".a") == 0) {
err = linker_add_lib (*file);
} else {
err = linker_add_object_file (*file);
}
} else {
err = linker_add_lib (*file);
}
if (err)
return err;
}
qfo = linker_finish ();
if (qfo) {
if (!options.output_file)
options.output_file = "progs.dat";
if (options.partial_link) {
qfo_write (qfo, options.output_file);
} else {
int crc = 0;
qfo_to_progs (qfo, &pr);
setup_sym_file (options.output_file);
finish_compilation ();
// write progdefs.h
if (options.progdefs_h)
crc = WriteProgdefs ("progdefs.h");
WriteData (crc);
}
} else {
err = 1;
}
if (!options.save_temps)
for (file = temp_files; *file; file++)
unlink (*file);
}
return err;
}
static const char *
load_file (const char *fname)
{
QFile *file;
char *src;
FILE *tmpfile;
tmpfile = preprocess_file (fname, "i1");
if (!tmpfile)
return 0;
file = Qfopen (tmpfile, "rb");
if (!file) {
perror (fname);
return 0;
}
src = malloc (Qfilesize (file) + 1);
src[Qfilesize (file)] = 0;
Qread (file, src, Qfilesize (file));
Qclose (file);
if (cpp_name && (!options.save_temps)) {
if (unlink (tempname->str)) {
perror ("unlink");
exit (1);
}
}
return src;
}
static void
parse_cpp_line (script_t *script, dstring_t *filename)
{
if (Script_TokenAvailable (script, 0)) {
Script_GetToken (script, 0);
// subtract 1 for \n
script->line = atoi (script->token->str) - 1;
if (Script_TokenAvailable (script, 0)) {
Script_GetToken (script, 0);
dstring_copystr (filename, script->token->str);
script->file = filename->str;
}
}
// There shouldn't be anything else, but just to be safe...
while (Script_TokenAvailable (script, 0))
Script_GetToken (script, 0);
}
static int
compile_file (const char *filename)
{
int err;
yyin = preprocess_file (filename, 0);
if (!yyin)
return !options.preprocess_only;
pr.source_file = ReuseString (strip_path (filename));
pr.source_line = 1;
clear_frame_macros ();
err = yyparse () || pr.error_count;
fclose (yyin);
if (cpp_name && (!options.save_temps)) {
if (unlink (tempname->str)) {
perror ("unlink");
exit (1);
}
}
return err;
}
static int
progs_src_compile (void)
{
dstring_t *filename = dstring_newstr ();
dstring_t *qc_filename = dstring_newstr ();
dstring_t *single_name = dstring_newstr ();
const char *src;
int crc = 0;
script_t *script;
FILE *single = 0;
if (options.verbosity >= 1 && strcmp (sourcedir, "")) {
printf ("Source directory: %s\n", sourcedir);
}
if (options.verbosity >= 1 && strcmp (progs_src, "progs.src")) {
printf ("progs.src: %s\n", progs_src);
}
if (*sourcedir)
dsprintf (filename, "%s/%s", sourcedir, progs_src);
else
dsprintf (filename, "%s", progs_src);
if (options.single_cpp) {
intermediate_file (single_name, filename->str, "i2", 1);
if (!options.save_temps) {
#ifdef _WIN32
mktemp (single_name->str);
#else
int tempfd = mkstemp (single_name->str);
single = fdopen (tempfd, "wb");
#endif
}
if (!single)
single = fopen (single_name->str, "wb");
if (!single) {
perror (single_name->str);
exit (1);
}
}
src = load_file (filename->str);
if (!src) {
fprintf (stderr, "couldn't open %s\n", filename->str);
unlink (single_name->str);
return 1;
}
script = Script_New ();
Script_Start (script, filename->str, src);
while (1) {
if (!Script_GetToken (script, 1)) {
fprintf (stderr,
"No destination filename. qfcc --help for info.\n");
return 1;
}
if (strcmp (script->token->str, "#") == 0) {
parse_cpp_line (script, filename);
continue;
}
break;
}
if (!options.output_file)
options.output_file = save_string (script->token->str);
if (options.verbosity >= 1) {
printf ("output file: %s\n", options.output_file);
}
setup_sym_file (options.output_file);
InitData ();
chain_initial_types ();
begin_compilation ();
if (!options.compile)
setup_param_block ();
// compile all the files
while (Script_GetToken (script, 1)) {
if (strcmp (script->token->str, "#") == 0) {
parse_cpp_line (script, filename);
continue;
}
while (1) {
if (*sourcedir)
dsprintf (qc_filename, "%s%c%s", sourcedir, PATH_SEPARATOR,
script->token->str);
else
dsprintf (qc_filename, "%s", script->token->str);
if (options.verbosity >= 2)
printf ("%s:%d: compiling %s\n", script->file, script->line,
qc_filename->str);
if (single) {
fprintf (single, "$frame_reset\n");
fprintf (single, "#line %d \"%s\"\n", script->line,
script->file);
fprintf (single, "#include \"%s\"\n", qc_filename->str);
} else {
if (compile_file (qc_filename->str))
return 1;
}
if (!Script_TokenAvailable (script, 0))
break;
Script_GetToken (script, 0);
}
}
if (single) {
int err;
fclose (single);
err = compile_file (single_name->str);
if (!options.save_temps) {
if (unlink (single_name->str)) {
perror ("unlink");
exit (1);
}
}
if (err)
return 1;
}
if (options.compile) {
qfo_t *qfo = qfo_from_progs (&pr);
qfo_write (qfo, options.output_file);
qfo_delete (qfo);
} else {
class_finish_module ();
if (!finish_compilation ()) {
fprintf (stderr, "compilation errors\n");
return 1;
}
// write progdefs.h
if (options.progdefs_h)
crc = WriteProgdefs ("progdefs.h");
// write data file
if (WriteData (crc))
return 1;
// write files.dat
if (options.files_dat)
if (WriteFiles (sourcedir))
return 1;
}
return 0;
}
/*
main
The nerve center of our little operation
*/
int
main (int argc, char **argv)
{
double start, stop;
int res;
start = Sys_DoubleTime ();
#ifdef _WIN32
if (putenv ("POSIXLY_INCORRECT_GETOPT=1")) {
fprintf (stderr, "Warning: putenv failed\n");
}
#endif
this_program = NORMALIZE (argv[0]);
DecodeArgs (argc, argv);
tempname = dstring_new ();
parse_cpp_name ();
opcode_init ();
InitData ();
init_types ();
clear_immediates ();
if (source_files) {
res = separate_compile ();
} else {
res = progs_src_compile ();
}
if (res)
return res;
stop = Sys_DoubleTime ();
if (options.verbosity >= 0)
printf ("Compilation time: %0.3g seconds.\n", (stop - start));
return 0;
}