/*
// ColdMUD was created and is copyright 1993, 1994 by Greg Hudson
//
// ColdX is a derivitive work, and is copyright 1995 by the ColdX Project.
// Full copyright information can be found in the file doc/CREDITS
//
// File: main.c
// Version: 0.1-5
// Last Edited: 4 Aug 1995
//
// ---
//
//
*/
/* #define _POSIX_SOURCE */
#define _main_
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include "defs.h"
#include "x.tab.h"
#include "codegen.h"
#include "opcodes.h"
#include "object.h"
#include "match.h"
#include "cache.h"
#include "sig.h"
#include "db.h"
#include "util.h"
#include "io.h"
#include "data.h"
#include "log.h"
#include "dump.h"
#include "execute.h"
#include "ident.h"
#include "cmstring.h"
#include "token.h"
#include "main.h"
/* -------------------------------------------------------------------- */
int main(int argc, char **argv) {
initialize(argc, argv);
main_loop();
/* Sync the cache, flush output buffers, and exit normally. */
cache_sync();
db_close();
flush_output();
return 0;
}
/* -------------------------------------------------------------------- */
static void initialize(int argc, char **argv) {
FILE * fp;
Object * obj;
List * parents,
* args;
int i,
use_text_dump;
String * str;
Data arg,
* d;
/* Ditch stdin, so we can reuse the file descriptor */
fclose(stdin);
/* Initialize internal tables and variables. */
init_codegen();
init_ident();
init_op_table();
init_match();
init_util();
init_sig();
init_execute();
init_scratch_file();
init_token();
if (argc < 2) {
fprintf(stderr, "Usage: %s <database> <db args>\n", argv[0]);
/*
-d basedir
-f filedir
-c compile <stdin>
*/
exit(1);
}
/* Switch into database directory. */
if (chdir(argv[1]) == -1) {
fprintf(stderr, "Couldn't change to directory %s.\n", argv[1]);
exit(1);
}
/* Build argument list from arguments. */
args = list_new(argc);
d = list_empty_spaces(args, argc);
for (i = 0; i < argc; i++) {
str = string_from_chars(argv[i], strlen(argv[i]));
d->type = STRING;
d->u.str = str;
d++;
}
/* people like to know what is up */
write_err("Initializing database...");
/* Initialize database and network modules. */
init_cache();
use_text_dump = init_db();
/* Order of operations note: it might seem like we'd want to read the text
* dump (if we're going to) before making sure there's a root and system
* object. However, this way is correct, since the textdump reader can
* evaluate arbitrary C-- code and thus should start with a consistent
* database. */
/* Make sure there is a root object. */
obj = cache_retrieve(ROOT_DBREF);
if (!obj) {
parents = list_new(0);
obj = object_new(ROOT_DBREF, parents);
list_discard(parents);
}
cache_discard(obj);
/* Make sure there is a system object. */
obj = cache_retrieve(SYSTEM_DBREF);
if (!obj) {
parents = list_new(1);
d = list_empty_spaces(parents, 1);
d->type = DBREF;
d->u.dbref = ROOT_DBREF;
obj = object_new(SYSTEM_DBREF, parents);
list_discard(parents);
}
cache_discard(obj);
/* Read a text dump if there was no existing binary database. */
if (use_text_dump) {
write_err("Reading from textdump...");
fp = fopen("textdump", "r");
if (!fp) {
fail_to_start("Couldn't open text dump file.");
} else {
text_dump_read(fp);
fclose(fp);
}
}
/* Send a startup message to the system object. */
arg.type = LIST;
arg.u.list = args;
task(NULL, SYSTEM_DBREF, startup_id, 1, &arg);
list_discard(args);
}
/* -------------------------------------------------------------------- */
static void main_loop(void) {
int seconds = 0;
time_t next_heartbeat = 0, t;
while (running) {
/* delete any defunct connection or server records */
flush_defunct();
/* Sanity check: make sure there are no objects in active chains. */
/* cache_sanity_check(); */
/* Find number of seconds before next heartbeat. */
if (heartbeat_freq != -1) {
next_heartbeat = (last_heartbeat -
(last_heartbeat % heartbeat_freq)
) + heartbeat_freq;
time(&t);
seconds = (t >= next_heartbeat) ? 0 : next_heartbeat - t;
seconds = (paused ? 0 : seconds);
/* fprintf(stderr, "seconds: %d\n", seconds); */
}
/* wait seconds for something to happen */
handle_io_event_wait(seconds);
/* input */
handle_connection_input();
/* handle new or pending connections */
handle_new_and_pending_connections();
/* send a heartbeat if necessary */
if (heartbeat_freq != -1) {
time(&t);
if (t >= next_heartbeat) {
last_heartbeat = t;
task(NULL, SYSTEM_DBREF, heartbeat_id, 0);
}
}
/* output */
handle_connection_output();
/* complete paused tasks */
if (paused)
run_paused_tasks();
}
}
#undef _main_