#include <stdio.h>
#include <string.h>
#include <math.h>
#include <setjmp.h>
#if defined(sun)
#include <alloca.h>
#endif
#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "config.h"
#include "lex.h"

extern char *prog;
extern char *init_file; 
extern int current_line;

int d_flag = 0;	/* Run with debug */
int t_flag = 0;	/* Disable heart beat and reset */
int e_flag = 0;	/* Load empty, without castles. */
int comp_flag = 0; /* Trace compilations */
long time_to_swap = TIME_TO_SWAP; /* marion - invocation parameter */

#ifdef YYDEBUG
extern int yydebug;
#endif

int port_number = PORTNO;
char *reserved_area;	/* reserved for malloc() */
struct svalue const0, const1;

double consts[5];

extern jmp_buf error_recovery_context;
extern int error_recovery_context_exists;

extern struct object *master_ob;

struct wiz_list *back_bone_uid;
static void start_ip_demon();

int main(argc, argv)
    int argc;
    char **argv;
{
    extern int game_is_being_shut_down;
    extern int current_time;
    int i, new_mudlib = 0;
    char *p;
#ifndef COMPAT_MODE
    struct svalue *ret;
#endif
#ifdef MALLOC_gc
    extern void gc_init();
#endif

#ifdef MALLOC_gc
    gc_init();
#endif
    const0.type = T_NUMBER; const0.u.number = 0;
    const1.type = T_NUMBER; const1.u.number = 1;
    /*
     * Check that the definition of EXTRACT_UCHAR() is correct.
     */
    p = (char *)&i;
    *p = -10;
    if (EXTRACT_UCHAR(p) != 0x100 - 10) {
	fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in config.h.\n");
	exit(1);
    }
#ifdef DRAND48
    srand48(get_current_time());
#else
#ifdef RANDOM
    srandom(get_current_time());
#else
    fprintf(stderr, "No random generator specified!\n");
#endif /* RANDOM */
#endif /* DRAND48 */

#ifdef MALLOC_gcmalloc
    gc_init();
   { extern int dont_gc;
      dont_gc = 0;
   }
#endif

    current_time = get_current_time();;
    if (RESERVED_SIZE > 0)
	reserved_area = malloc(RESERVED_SIZE);
    for (i=0; i < sizeof consts / sizeof consts[0]; i++)
	consts[i] = exp(- i / 900.0);
    init_num_args();
    reset_machine(1);

    /*
     * The flags are parsed twice !
     * The first time, we search for the -m flag, which specifies
     * another mudlib, and the -o flag.
     */
    for (i=1; i < argc; i++) {
	if (argv[i][0] != '-')
	    continue;
	switch(argv[i][1]) {
        case 'D':
       	    if (argv[i][2]) { /* Amylaar : allow flags to be passed down to
       				       the LPC preprocessor */
       	        struct lpc_predef_s *tmp;

       	        tmp = (struct lpc_predef_s *)
       	            alloca(sizeof(struct lpc_predef_s));
       	        if (!tmp) fatal("alloca failed");
       	        tmp->flag = argv[i]+2;
       	        tmp->next = lpc_predefs;
       	        lpc_predefs = tmp;
       	        continue;
   	    }
            fprintf(stderr, "Invalid flag format: %s\n", argv[i]);
            exit(1);
        case 'o': 
            fprintf(stderr, "-o flag is obsolete.  Use COMPAT_FLAG in config.h.\n");
            exit(1);
            break;
	case 'm':
	    if (chdir(argv[i]+2) == -1) {
	        fprintf(stderr, "Bad mudlib directory: %s\n", argv[i]+2);
		exit(1);
	    }
	    new_mudlib = 1;
	    break;
	}
    }
    if (!new_mudlib && chdir(MUD_LIB) == -1) {
        fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB);
	exit(1);
    }

#ifndef NO_IP_DEMON
    start_ip_demon();
#endif

    if (setjmp(error_recovery_context)) {
	clear_state();
	add_message("Anomaly in the fabric of world space.\n");
    } else {
	error_recovery_context_exists = 1;

#ifdef COMPAT_MODE
        master_ob = load_object("obj/master", 0);
#else
        master_ob = load_object("secure/master", 0);
#endif
    }
    error_recovery_context_exists = 0;
    if (master_ob == 0) {
	fprintf(stderr, "The file obj/master must be loadable.\n");
	exit(1);
    }
    /*
     * Make sure master_ob is never made a dangling pointer.
     * Look at apply_master_ob() for more details.
     */
    add_ref(master_ob, "main");
#ifndef COMPAT_MODE
       ret = apply_master_ob("get_root_uid", 0);
       if (ret == 0 || ret->type != T_STRING) {
          fprintf(stderr, "get_root_uid() in secure/master.c does not work.\n");
          exit(1);
       }
       master_ob->user = add_name(ret->u.string);
       master_ob->eff_user = master_ob->user;
       ret = apply_master_ob("get_bb_uid", 0);
       if (ret == 0 || ret->type != T_STRING) {
          fprintf(stderr, "get_bb_uid() in secure/master.c does not work.\n"); 
          exit(1);
       }
       back_bone_uid = add_name(ret->u.string);
#endif
    init_file = INIT_FILE;
    for (i=1; i < argc; i++) {
	int atoi();

	if (atoi(argv[i]))
	    port_number = atoi(argv[i]);
	else if (argv[i][0] != '-') {
	    fprintf(stderr, "Bad argument %s\n", argv[i]);
	    exit(1);
	} else {
	    switch(argv[i][1]) {
            case 'i': 
                i++;
                init_file = argv[i];
                break;
	    case 'f':
		push_constant_string(argv[i]+2);
		(void)apply_master_ob("flag", 1);
		if (game_is_being_shut_down) {
		    fprintf(stderr, "Shutdown by master object.\n");
		    exit(0);
		}
		continue;
	    case 'D':
		continue;
	    case 'e':
		e_flag++; continue;
	    case 'm':
		continue;
	    case 'd':
		d_flag++; continue;
	    case 'c':
		comp_flag++; continue;
	    case 't':
		t_flag++; continue;
#if TIME_TO_SWAP > 0
	    case 's':
		time_to_swap = atoi (&argv[i][2]);
		continue;
#endif
#ifdef YYDEBUG
	    case 'y':
		yydebug = 1; continue;
#endif
	    default:
		fprintf(stderr, "Unknown flag: %s\n", argv[i]);
		exit(1);
	    }
	}
    }
    get_simul_efun(apply_master_ob("get_simul_efun", 0));
    if (game_is_being_shut_down)
       exit(1); 
    load_wiz_file();
    set_inc_list(apply_master_ob("define_include_dirs", 0));
#ifdef COMPAT_MODE
    load_first_objects();
    (void)apply_master_ob("epilog", 0);
#else
    preload_objects(e_flag);
#endif
    backend();
    return 0;
}

char *string_copy(str)
    char *str;
{
    char *p;

    p = xalloc(strlen(str)+1);
    (void)strcpy(p, str);
    return p;
}

/*VARARGS1*/
void debug_message(a, b, c, d, e, f, g, h, i, j)
    char *a;
    int b, c, d, e, f, g, h, i, j;
{
    static FILE *fp = NULL;
    char deb[100];
    char name[100];

    if (fp == NULL) {
  /*
	gethostname(name,sizeof name);
	sprintf(deb,"%s.debug.log",name);
 */
        strcpy(deb, "debug.log");
	fp = fopen(deb, "w");
	if (fp == NULL) {
	    perror(deb);
	    abort();
	}
    }
    (void)fprintf(fp, a, b, c, d, e, f, g, h, i, j);
    (void)fflush(fp);
}

void debug_message_svalue(v)
    struct svalue *v;
{
    if (v == 0) {
	debug_message("<NULL>");
	return;
    }
    switch(v->type) {
    case T_NUMBER:
	debug_message("%d", v->u.number);
	return;
    case T_STRING:
	debug_message("\"%s\"", v->u.string);
	return;
    case T_OBJECT:
	debug_message("OBJ(%s)", v->u.ob->name);
	return;
    case T_LVALUE:
	debug_message("Pointer to ");
	debug_message_svalue(v->u.lvalue);
	return;
    default:
	debug_message("<INVALID>\n");
	return;
    }
}

#ifdef malloc
#undef malloc
#endif

int slow_shut_down_to_do = 0;

char *xalloc(size)
    int size;
{
    char *p;
    static int going_to_exit;

    if (going_to_exit)
	exit(3);
    if (size == 0)
	fatal("Tried to allocate 0 bytes.\n");
    p = malloc(size);
    if (p == 0) {
	if (reserved_area) {
	    free(reserved_area);
	    p = "Temporary out of MEMORY. Freeing reserve.\n";
	    write(1, p, strlen(p));
	    reserved_area = 0;
	    slow_shut_down_to_do = 6;
	    return xalloc(size);	/* Try again */
	}
	going_to_exit = 1;
	p = "Totally out of MEMORY.\n";
	write(1, p, strlen(p));
#if defined(DEBUG) && defined(TRACE_CODE)
	(void)dump_trace(0);
#else
	(void)dump_trace();
#endif
	exit(2);
    }
    return p;
}

#ifndef NO_IP_DEMON
static void start_ip_demon()
{
    extern FILE *f_ip_demon, *f_ip_demon_wr;
    int tochild[2], fromchild[2];
    char *path[100];
    int pid;
    char c;

    if(pipe(tochild) < 0)
        return;
    if(pipe(fromchild) < 0) {
        close(tochild[0]);
        close(tochild[1]);
        return;
    }
    if((pid = fork()) == 0) {
        /* Child */
        char *hname = "hname";
        dup2(tochild[0], 0);
        dup2(fromchild[1], 1);
        close(tochild[0]);
        close(tochild[1]);
        close(fromchild[0]);
        close(fromchild[1]);
        sprintf((char *)path, (char *)"%s/hname", BINDIR);
        execl((char *)path, (char *)hname, (char *)0);
        fprintf(stderr, "exec of hname failed.\n");
        _exit(1);
    }
    if(pid == -1) {
        close(tochild[0]);
        close(tochild[1]);
        close(fromchild[0]);
        close(fromchild[1]);
        return;
    }
    close(tochild[0]);
    close(fromchild[1]);
    f_ip_demon_wr = fdopen(tochild[1], "w");
    f_ip_demon = fdopen(fromchild[0], "r");
    if (f_ip_demon == NULL || f_ip_demon_wr == NULL) {
        close(tochild[1]);
        close(fromchild[0]);
	f_ip_demon = NULL;
    }
    return;
#endif
}