#include "global.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <ctype.h>
#if defined(sun)
#include <alloca.h>
#endif
#ifdef STDC_HEADERS
#include <stdarg.h>
#endif
#include "simulate.h"
#include "interpret.h"
#include "object.h"
#include "exec.h"
#include "lex.h"
#include "main.h"
#include "array.h"
#include "stralloc.h"
#include "backend.h"
#include "simul_efun.h"
#ifdef LACIP
#include "lacip/op.h"
#endif
#ifdef GETRUSAGE_THROUGH_PROCFS
#include <sys/procfs.h>
#include <sys/fcntl.h>
int proc_fd;
void open_proc_fd()
{
char proc_name[20];
sprintf(proc_name, "/proc/%05ld", (long)getpid());
proc_fd = open(proc_name, O_RDONLY);
if(proc_fd < 0)
{
fprintf(stderr, "Couldn't open %s\n", proc_name);
}
}
#endif
extern char *prog;
extern int current_line;
extern int lasdebug;
int d_flag = 0; /* Run with debug */
int t_flag = 0; /* Disable heart beat and reset */
int comp_flag = 0; /* Trace compilations */
int T_flag = 0;
#ifdef WARN
int W_flag = 0;
#endif
int batch_mode=0; /* he he */
void init_stdin_handler();
extern int stdin_closed,stdinisatty,stdin_is_sock;
#ifdef YYDEBUG
extern int yydebug;
#endif
char *reserved_area=NULL; /* reserved for malloc() */
struct svalue const_empty_string;
char *hostname;
double consts[NUM_CONSTS];
extern jmp_buf error_recovery_context;
extern int error_recovery_context_exists;
extern struct object *master_ob;
extern int eval_cost;
unsigned long signals;
RETSIGTYPE sig_lpc(int s)
{
signal(s,sig_lpc);
signals|=1<<s;
}
RETSIGTYPE sig_child(int s)
{
wait(&s);
signal(s,sig_child);
}
/* don't forget to change LF_MAX in exec.h */
char *initial_lfun_list[]=
{
"catch_tell",
"heart_beat",
"init",
"exit",
} ;
extern void init_stacks();
extern void init_sockets();
int main(int argc,char ** argv,char **env)
{
struct svalue *ret;
extern int game_is_being_shut_down;
extern int current_time;
int i, new_mudlib = 0;
char *p;
#ifdef GETRUSAGE_THROUGH_PROCFS
open_proc_fd();
#endif
#ifdef MALLOC_gc
gc_init();
#endif
SET_STR(&const_empty_string,make_shared_string(""));
lfuns=(char **)xalloc(sizeof(char **)*NELEM(initial_lfun_list));
for(i=0;i<NELEM(initial_lfun_list);i++)
lfuns[i]=make_shared_string(initial_lfun_list[i]);
num_lfuns=i;
init_stacks();
p=(char *)malloc(100);
gethostname(p,100);
p[100-1]=0;
hostname=make_shared_string(p);
free(p);
#ifdef debugmalloc
malloc_debug(2);
#endif
/*
* 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 machine.h.\n");
exit(1);
}
my_srand(get_current_time());
current_time = get_current_time();
for (i=0; i < NELEM(consts); i++)
consts[i] = exp(- i / 900.0);
init_num_args();
reset_machine(1);
/*
* The flags are parsed twice !
* The first time, we only search for the -m flag, which specifies
* another mudlib, and the D-flags, so that they will be available
* when compiling master.c.
*/
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 *) malloc(sizeof(struct lpc_predef_s));
if (!tmp) fatal("malloc failed");
tmp->flag = argv[i]+2;
tmp->next = lpc_predefs;
lpc_predefs = tmp;
continue;
}
fprintf(stderr, "Illegal flag syntax: %s\n", argv[i]);
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;
case 'I':
stdin_is_sock=1;
break;
case 'C':
batch_mode=1;
i=argc; /* the rest of the flags are 'mud only' */
}
}
if(!batch_mode)
{
if (!new_mudlib && chdir(MUD_LIB) == -1)
{
fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB);
exit(1);
}
}
if (RESERVED_SIZE > 0 && !batch_mode)
reserved_area = malloc(RESERVED_SIZE);
if(stdin_is_sock)
{
stdin_closed=1;
stdinisatty=0;
}else{
init_stdin_handler();
}
if (setjmp(error_recovery_context))
{
clear_state();
fprintf(stderr,"Fatal failiure when loading master object!\n");
}else{
error_recovery_context_exists = 1;
assert_master_ob_loaded();
}
if((ret=apply_master_ob("get_cached_functions",0)))
{
if(!IS_ZERO(ret))
{
if(ret->type==T_POINTER)
{
int t;
lfuns=(char **)realloc((char *)lfuns,sizeof(char **)*(ret->u.vec->size+num_lfuns));
if(!lfuns)
{
fprintf(stderr,"Couldn't allocate space for cached functions.\n");
exit(10);
}
for(i=0;i<ret->u.vec->size;i++)
{
if(ret->u.vec->item[i].type!=T_STRING)
{
fprintf(stderr,"get_cached_function() returned an array containing non-strings.\n");
exit(10);
}
for(t=0;t<num_lfuns;t++)
if(lfuns[t]==strptr(ret->u.vec->item+i))
break;
if(t==num_lfuns)
{
lfuns[num_lfuns]=copy_shared_string(strptr(ret->u.vec->item+i));
num_lfuns++;
}
}
}else{
fprintf(stderr,"Warning: get_cached_functions() in master.c doesn't return an array or zero.\n");
}
}
}
error_recovery_context_exists = 0;
if(batch_mode)
{
push_new_shared_string(BINDIR);
push_new_shared_string(MUD_LIB);
set_inc_list(apply_master_ob("define_include_dirs", 2));
}else{
set_inc_list(apply_master_ob("define_include_dirs", 0));
}
init_sockets(); /* initialize efun sockets */
signal(SIGCHLD, sig_child);
signal(SIGINT, sig_lpc);
signal(SIGQUIT, sig_lpc);
signal(SIGTERM, sig_lpc);
signal(SIGUSR1, sig_lpc);
signal(SIGUSR2, sig_lpc);
signal(SIGPIPE, SIG_IGN);
#if 0
#ifndef DEBUG
if(-1!=find_function("signal",master_ob->prog))
{
signal(SIGSEGV, sig_lpc);
signal(SIGFPE, sig_lpc);
signal(SIGBUS, sig_lpc);
}
#endif
#endif
for (i=1; i < argc; i++)
{
if (argv[i][0] != '-')
{
fprintf(stderr, "Bad argument %s\n", argv[i]);
exit(1);
} else {
/*
* Look at flags. -m and -o has already been tested.
*/
switch(argv[i][1])
{
case 'f':
eval_cost=0;
push_new_shared_string(argv[i]+2);
APPLY_MASTER_OB((void),"flag", 1);
if (game_is_being_shut_down) {
fprintf(stderr, "Shutdown by master object.\n");
exit(0);
}
continue;
case 'C':
{
struct vector *fo,*env_fo;
int e;
batch_mode=1;
eval_cost=0;
push_new_shared_string(argv[i]+2);
i++;
fo=allocate_array_no_init(argc-i,0);
for(e=0;i<argc;i++,e++)
{
SET_STR(fo->item+e,make_shared_string(argv[i]));
}
for(e=0;env[e];e++);
env_fo=allocate_array_no_init(e,0);
for(e=0;env[e];e++)
{
SET_STR(env_fo->item+e,make_shared_string(env[e]));
}
push_vector(fo);
push_vector(env_fo);
fo->ref--;
env_fo->ref--;
(void)apply_master_ob("batch", 3);
if (game_is_being_shut_down) {
exit(0);
}
i=argc; /* the rest of the flags are 'mud only' */
}
case 'I':
push_number(batch_mode);
(void)apply_master_ob("stdin_is_sock",1);
continue;
case 'D':
continue;
case 'N':
continue;
case 'm':
continue;
#define OPTION(flag,variable) case flag: if(isdigit(argv[i][2])) variable=atoi(argv[i]+2); else variable++; break
OPTION('l',lasdebug);
OPTION('d',d_flag);
OPTION('c',comp_flag);
OPTION('t',t_flag);
OPTION('T',T_flag);
#ifdef WARN
OPTION('W',W_flag);
#endif
#ifdef YYDEBUG
OPTION('y',yydebug);
#endif
default:
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
exit(1);
}
}
}
if (game_is_being_shut_down)
exit(1);
#ifdef OPCPROF
check_cost_for_instr(-1);
#endif
backend();
return 0;
}
char *string_copy(char *str)
{
char *p;
p = xalloc(strlen(str)+1);
(void)strcpy(p, str);
return p;
}
void debug_message_va(char *a,va_list args)
{
static FILE *fp = NULL;
char deb[100];
/* nej tack, jag k|r */
if(batch_mode)
return;
if (fp == NULL)
{
sprintf(deb,"%s.debug.log",hostname);
fp = fopen(deb, "w");
if (fp == NULL)
{
perror(deb);
abort();
}
}
(void)VFPRINTF(fp, a, args);
(void)fflush(fp);
}
void debug_message(char *a, ...)
{
va_list args;
va_start(args,a);
debug_message_va(a,args);
va_end(args);
}
#ifdef WARN
void warn(int w_level,char *a, ...)
{
va_list args;
if(W_flag<w_level) return;
va_start(args,a);
VFPRINTF(stderr,a,args);
va_end(args);
}
#else
void warn(int w, char *a, ...) {}
#endif
void debug_message_svalue(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\"", strptr(v));
return;
case T_OBJECT:
debug_message("OBJ(%s)", v->u.ob->prog->name);
return;
case T_LVALUE:
debug_message("LVALUE");
return;
default:
debug_message("<INVALID>");
return;
}
}
#ifdef malloc
#undef malloc
#endif
int slow_shut_down_to_do = 0;
char *xalloc(int size)
{
extern void do_gc(int);
char *p;
static int going_to_exit;
if (going_to_exit) exit(3);
if (size == 0) fatal("Tried to allocate 0 bytes.\n");
if((p = malloc(size))) return p;
do_gc(10000);
if((p = malloc(size))) return p;
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++;
if((p = malloc(size))) return p;
}
going_to_exit = 1;
p = "Totally out of MEMORY.\n";
write(1, p, strlen(p));
(void)dump_trace(0);
exit(2);
return 0;
}