#include <time.h>
#include <sys/time.h>
#include <sys/types.h> /* for umask et al */
#include <sys/stat.h> /* for umask et al */
#ifndef __WIN32__
#include <sys/resource.h>
#endif
#include <signal.h>
#include <errno.h>
#include "proto.h"
#include "interpret.h"
#include "apply.h"
#include "stack.h"
#include "consts.h"
#include "class.h"
#ifdef USE_GC
#include "../gc.h"
#endif
/*#define SSIGSTACK */
#ifdef SSIGSTACK
struct sigstack sstack;
#define SIG_STACK 10000
#endif
extern int current_time;
extern void free_all_objects();
extern void free_all_classes();
static Val *catch_value;
/* catch_value is for * catch/throw */
static FILE * debugfp;
int d_flag = 0; /* Run with debug */
int t_flag = 0; /* Disable heart beat and reset */
int e_flag = 0; /* Load empty, without castles. */
#ifdef YYDEBUG
extern int yydebug;
#endif
#ifndef FIND_LEAKS
// #define RESERVED_AREA 40000
#endif
#ifdef RESERVED_AREA
static char *reserved_area;
#endif
int port_number = PORTNUM;
int e_port_number = EPORTNUM;
int port_number2 = PORTNUM2;
int e_port_number2 = EPORTNUM2;
double consts[5];
#ifdef C_PROFILE
extern etext(), eprol();
#endif
/* #define DEBUG_XALLOC */
#ifdef DEBUG_XALLOC
static void initxsizes();
#endif
int Wiz_Mud = 0;
int CoreFile = 0;
int shutdown_size = 14900000; /* player mud */
int profile_it = 0;
char *profbuf = 0;
char mud_lib[256];
char *zero;
/*
* Name: initialise()
* Purpose: initialise key tables etc throughout the engine
*/
void initialise()
{
int i;
#ifdef DEBUG_XALLOC
initxsizes();
#endif
#ifdef USE_GC
// GC_enable_incremental();
#endif
printf("stats\n");
init_stats();
printf("strings\n");
init_strings();
printf("optable\n");
install_optable();
printf("lexer\n");
init_lex_space();
printf("class_table\n");
init_class_table();
printf("Otable\n");
init_Otable();
printf("Cheap\n");
init_Cheap();
#if 0
/* Fix up core dump limits */
if (CoreFile)
{
struct rlimit x;
x.rlim_cur = 16000000;
x.rlim_max = x.rlim_cur;
setrlimit(RLIMIT_CORE, &x);
}
else
{
struct rlimit x;
x.rlim_cur = 0;
x.rlim_max = x.rlim_cur;
setrlimit(RLIMIT_CORE, &x);
}
#endif
#ifdef C_PROFILE
if (profile_it)
{
profbuflen = (char *) etext - (char *) eprol;
profbuf = (char *) malloc(profbuflen);
profil((char *) profbuf, profbuflen, (char *) eprol, 0x10000);
}
#endif
/* Random stuff */
#ifdef HAVE_SRANDOM
srandom(time(0));
#else
fprintf(stderr, "No random generator specified!\n");
#endif /* SRANDOM */
current_time = time(0);
install_oc();
for (i = 0; i < sizeof consts / sizeof consts[0]; i++)
consts[i] = 0; /*exp (-i / 900.0); */
#ifdef RESERVED_AREA
reserved_area = malloc(RESERVED_AREA);
#endif
/* Key constants */
printf("str_consts\n");
init_str_consts();
printf("Sinit_stack()\n");
Sinit_stack();
Sset_external_handler(call_efun);
Sset_program_handler(locate_program);
zero = (char *) malloc(sizeof(char *));
catch_value = Const(0);
/* Signal stack stuff */
#ifdef SSIGSTACK
sstack.ss_sp = malloc(SIG_STACK) + SIG_STACK - 4;
sstack.ss_onstack = 0;
sigstack(&sstack, (struct sigstack *) 0);
#endif
}
void open_error_log()
{
umask(UMASK);
printf("Opening error stream\n");
debugfp = fopen(DEBUG_LOG, "a");
if (debugfp)
{
force_no_su(C(DEBUG_LOG));
Serror_stream(debugfp);
}
else
{
printf("Unable to open error stream (%s)\n", DEBUG_LOG);
}
}
/*
* Name: unroot
* Purpose: Change our uid away from root (less security risk)
* Notes: needs to be done after establishing a socket on port 23
* Assumes we're a setuid process (root) and we're run by a non-root user
* The file should be 6775, owned by root, group mud
*/
void unroot()
{
#ifndef __WIN32__
int uid, euid;
int gid, egid;
uid = getuid();
euid = geteuid();
gid = getgid();
egid = getegid();
/* give up our root privileges */
setuid(uid);
#endif
}
/*
* free_all
* Cleans up all objects.
*/
void free_all_objects()
{
#if 0
Obj *o = obj_list;
printf("Freeing all objects.\n");
while (o)
{
if (!o->destructed)
destruct_object(o);
o = o->next_all;
}
#endif
}
int main(int argc, char **argv)
{
int i;
int k;
#ifdef FIND_LEAKS
void apa();
#endif
/* initialise some key global values */
strcpy(mud_lib, MUD_LIB);
/* parse command line parameters */
for (i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-e") == 0)
e_flag++;
else if (strcmp(argv[i], "-t") == 0)
t_flag++;
else if (strcmp(argv[i], "-m") == 0)
{
i++;
strcpy(mud_lib, argv[i]);
}
else if (strcmp(argv[i], "-w") == 0)
{
Wiz_Mud++;
/* shutdown_size = 6900000; */
}
else if (strcmp(argv[i], "-c") == 0)
{
/* produce coredumps on crash */
CoreFile++;
}
#ifdef YYDEBUG
else if (strcmp(argv[i], "-y") == 0)
yydebug = 1;
#endif
#ifdef C_PROFILE
else if (strcmp(argv[i], "-p") == 0)
profile_it = 1;
#endif
else
{
port_number = atoi(argv[i++]);
if (i < argc)
e_port_number = atoi(argv[i++]);
if (i < argc)
port_number2 = atoi(argv[i++]);
if (i < argc)
e_port_number2 = atoi(argv[i++]);
}
}
chdir(mud_lib);
printf("main: Initialising tables.\n");
initialise();
/* MAIN LOOP */
backend();
// #ifdef FIND_LEAKS
#if 1
{
extern int lex_boundary;
free_all_objects();
for (k = 0; k < 100000; k++)
call_out();
free_all_objects();
for (k = 0; k < 50000; k++)
call_out();
free_all_objects();
for (k = 0; k < 10000; k++)
call_out();
dump_all_objects(0);
free_all_classes();
lex_boundary = 0;
free_lex_space();
free_stack_space();
free_Htable();
free_Cheap();
free_Otable();
free_Stable();
/* free_all_sent(); */
}
#endif
printf("Normal termination\n");
return 0;
}
static int no_debug_loop = 0;
#define MAX_MESSAGE 1024
void debug_message(const char *fmt,...)
{
char a[MAX_MESSAGE];
static int writes_until_close = 0;
static char *debug_log = NULL;
va_list args;
va_start(args, fmt);
vsprintf(a, fmt, args);
va_end(args);
if (debug_log == NULL)
{
#ifndef DEBUG_LOG
char name[100];
gethostname(name, sizeof name);
debug_log = (char *) malloc(strlen(name) + 11);
strcpy(debug_log, name);
strcat(debug_log, ".debug.log");
#else
debug_log = string_copy(DEBUG_LOG)->str;
#endif
}
if (writes_until_close == 0)
{
debugfp = fopen(DEBUG_LOG, "a");
if (debugfp)
{
force_no_su(C(DEBUG_LOG));
Serror_stream(debugfp);
}
writes_until_close = 64;
}
if (debugfp == NULL)
{
perror(debug_log);
/* abort (); */
/* should notify the game driver */
if (!no_debug_loop)
{
no_debug_loop = 1;
/* if (apply_single(Master, C("alert"), make_string(a)))
* clean(num_made+1);
* else wipe(1); */
no_debug_loop = 0;
}
}
(void) fprintf(debugfp, "%s", a);
(void) fflush(debugfp);
if (--writes_until_close == 0)
(void) fclose(debugfp);
#if 0
if (command_giver)
add_message("%s", a);
#endif
}
void debug_message_value(Val * v)
{
if (v == 0)
{
debug_message("<NULL>");
return;
}
switch (v->type)
{
case T_NUMBER:
debug_message("%d", (char *) v->u.number);
return;
case T_STRING:
debug_message("\"%s\"", v->u.string);
return;
case T_POINTER:
debug_message("POINTER(%s)", "you want me to print it?");
return;
case T_OBJECT:
debug_message("OBJ(%s)", v->u.ob->name);
return;
default:
fatal("<INVALID>\n");
return;
}
}