/* // 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_