/*
// Full copyright information is available in the file ../doc/CREDITS
*/
#define _coldcc_
#include "defs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <ctype.h>
#include "cdc_pcode.h"
#include "cdc_db.h"
#include "textdb.h"
#include "strutil.h"
#include "util.h"
#include "sig.h"
#include "moddef.h"
#define OPT_COMP 0
#define OPT_DECOMP 1
#define OPT_PARTIAL 2
Int c_nowrite = 1;
Int c_opt = OPT_COMP;
Bool print_objs = YES;
Bool print_names = NO;
Bool print_invalid = YES;
Bool print_warn = YES;
#define NEW_DB 1
#define EXISTING_DB 0
/* function prototypes */
INTERNAL void initialize(Int argc, char **argv);
INTERNAL void usage(char * name);
INTERNAL FILE * find_text_db(void);
INTERNAL void compile_db(Int type);
void shutdown_coldcc(void) {
cache_sync();
db_close();
flush_output();
close_files();
fputc(10, stderr);
exit(0);
}
/*
// --------------------------------------------------------------------
*/
/*
// --------------------------------------------------------------------
*/
int main(int argc, char **argv) {
initialize(argc, argv);
if (setjmp(main_jmp) == 0) {
if (c_opt == OPT_DECOMP) {
init_binary_db();
init_core_objects();
fprintf(stderr, "Writing to \"%s\"..\n", c_dir_textdump);
text_dump(print_names);
} else if (c_opt == OPT_COMP) {
fprintf(stderr, "Compiling database...\n");
compile_db(NEW_DB);
} else if (c_opt == OPT_PARTIAL) {
fprintf(stderr, "Opening database for partial compile...\n");
compile_db(EXISTING_DB);
}
}
fputs("Closing binary database...", stderr);
shutdown_coldcc();
/* make compilers happy; we never reach this */
return 0;
}
/*
// --------------------------------------------------------------------
*/
INTERNAL void compile_db(Int newdb) {
FILE * fp;
/* create a new db, this will blast old dbs */
if (newdb)
init_new_db();
else
init_binary_db();
/* get new db */
fp = find_text_db();
/* verify $root/#1 and $sys/#0 exist */
init_core_objects();
if (!fp) {
fprintf(stderr, "Couldn't open text dump file \"%s\".\n",
c_dir_textdump);
exit(1);
} else {
/* text_dump_read(fp); */
compile_cdc_file(fp);
fclose(fp);
}
fprintf(stderr, "Database compiled to \"%s\"\n", c_dir_binary);
}
/*
// --------------------------------------------------------------------
// Finds target the database is, based off input name.
//
// If name is:
//
// "stdin", will read from stdin.
// a directory, will do directory compilation (unsupported)
// a valid file, will use that (textdump)
//
// Will output to global name "output", set by options
*/
INTERNAL FILE * find_text_db(void) {
FILE * fp = NULL;
if (strccmp(c_dir_textdump, "stdin") == 0) {
fputs("Reading from STDIN.\n", stderr);
return stdin;
} else {
struct stat sbuf;
if (stat(c_dir_textdump, &sbuf) == F_FAILURE) {
fprintf(stderr, "** Unable to open target \"%s\".\n",
c_dir_textdump);
exit(1);
}
if (S_ISDIR(sbuf.st_mode)) {
fputs("** Directory based compilation is currently unsupported.\n",
stderr);
fclose(fp);
exit(0);
}
/* just let fopen deal with the other perms */
fp = fopen(c_dir_textdump, "rb");
if (fp == NULL) {
fprintf(stderr, "** bad happened.\n");
exit(1);
}
fprintf(stderr, "Reading from \"%s\".\n", c_dir_textdump);
}
return fp;
}
/*
// --------------------------------------------------------------------
// print all of the natives nicely.
//
// be cute and columnize
*/
void print_natives(void) {
Int mid, x;
char buf[LINE];
if (NATIVE_LAST % 2)
mid = (NATIVE_LAST + 1) / 2;
else
mid = NATIVE_LAST / 2;
fputs("Native Method Configuration:\n\n", stdout);
for (x=0; mid < NATIVE_LAST; x++, mid++) {
sprintf(buf, "$%s.%s()", natives[x].bindobj, natives[x].name);
printf(" %-37s $%s.%s()\n", buf, natives[mid].bindobj,
natives[mid].name);
}
if (NATIVE_LAST % 2) {
x++;
printf(" $%s.%s()\n", natives[x].bindobj, natives[x].name);
}
fputc(10, stdout);
}
/*
// --------------------------------------------------------------------
// Initializes tables, variables and other aspects for use
*/
#define NEWFILE(var, name) { \
free(var); \
var = EMALLOC(char, strlen(name) + 1); \
strcpy(var, name); \
}
INTERNAL void initialize(Int argc, char **argv) {
Bool opt_bool = NO;
char * name = NULL,
* opt = NULL,
* buf;
name = *argv;
use_natives = 0;
argv++;
argc--;
init_defs();
init_match();
init_util();
while (argc) {
if (**argv == '-' || **argv == '+') {
opt = *argv;
opt_bool = (*opt == '+');
opt++;
switch (*opt) {
case 'v':
printf("ColdCC %d.%d-%d\n",
VERSION_MAJOR,
VERSION_MINOR,
VERSION_PATCH);
exit(0);
case 'f':
use_natives = FORCE_NATIVES;
break;
case 'n':
print_natives();
exit(0);
break;
case 'c':
c_opt = OPT_COMP;
break;
case 'd':
c_opt = OPT_DECOMP;
break;
case '#':
print_names = !opt_bool;
break;
case 'o':
print_objs = opt_bool;
break;
case 'p':
c_opt = OPT_PARTIAL;
break;
case 's': {
char * p;
argv += getarg(name, &buf, opt, argv, &argc, usage);
p = buf;
cache_width = atoi(p);
while (*p && isdigit(*p))
p++;
if ((char) LCASE(*p) == 'x') {
p++;
cache_depth = atoi(p);
} else {
usage(name);
printf("\n** Invalid WIDTHxDEPTH: '%s'\n", buf);
exit(0);
}
if (cache_width == 0 && cache_depth == 0) {
usage(name);
puts("\n** The WIDTH and DEPTH cannot both be zero\n");
exit(0);
}
break;
}
case 'W':
print_warn = NO;
break;
case 'w':
fputs("\n** Unsupported option: -w\n", stderr);
c_nowrite = 0;
break;
case 't':
argv += getarg(name,&buf, opt, argv,&argc,usage);
NEWFILE(c_dir_textdump, buf);
break;
case 'b':
argv += getarg(name,&buf, opt, argv, &argc, usage);
NEWFILE(c_dir_binary, buf);
break;
case '-':
case 'h':
usage(name);
exit(0);
default:
usage(name);
fprintf(stderr, "\n** Invalid Option: -%s\n", opt);
exit(1);
}
}
argv++;
argc--;
}
init_sig();
#ifdef DRIVER_DEBUG
init_debug();
#endif
init_codegen();
init_ident();
init_op_table();
init_execute();
init_scratch_file();
init_token();
init_modules(argc, argv);
init_instances();
init_cache();
/* force coldcc to be atomic, specify that we are not running online */
atomic = YES;
coldcc = YES;
}
/*
// --------------------------------------------------------------------
// Simple usage message, rather explanatory
*/
void usage (char * name) {
fprintf(stderr, "\n-- ColdCC %d.%d-%d --\n\n\
Usage: %s [options]\n\
\n\
Options:\n\n\
-f force native methods to override existing methods.\n\
-v version\n\
-h This message.\n\
-d Decompile.\n\
-c Compile (default).\n\
-b binary binary db directory name, default: \"%s\"\n\
-t target target text db, default: \"%s\"\n\
if this is \"stdin\" it will read from stdin\n\
instead. <target> may be a directory or file.\n\
-p Partial compile, compile object(s) and insert\n\
into database accordingly. Can be used with -w\n\
for a ColdC code verification program.\n\
+|-# Print/Do not print object numbers by default\n\
Default option is +#\n\
print object names by default, if they exist.\n\
-s WIDTHxDEPTH Cache size, default 10x30\n\
-n List native method configuration\n\
+|-o Print/Do not print objects as they are processed\n\
\n\
\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, name, c_dir_binary, c_dir_textdump);
}
#undef _coldcc_