gurba-0.40/
gurba-0.40/bin/
gurba-0.40/lib/
gurba-0.40/lib/cmds/guild/fighter/
gurba-0.40/lib/cmds/monster/
gurba-0.40/lib/cmds/race/catfolk/
gurba-0.40/lib/cmds/race/dwarf/
gurba-0.40/lib/cmds/verb/
gurba-0.40/lib/daemons/data/
gurba-0.40/lib/data/boards/
gurba-0.40/lib/data/messages/
gurba-0.40/lib/data/players/
gurba-0.40/lib/design/
gurba-0.40/lib/domains/gurba/
gurba-0.40/lib/domains/gurba/guilds/fighter/
gurba-0.40/lib/domains/gurba/monsters/
gurba-0.40/lib/domains/gurba/objects/armor/
gurba-0.40/lib/domains/gurba/objects/clothing/
gurba-0.40/lib/domains/gurba/objects/weapons/
gurba-0.40/lib/domains/gurba/vendors/
gurba-0.40/lib/kernel/cmds/admin/
gurba-0.40/lib/kernel/daemons/
gurba-0.40/lib/kernel/include/
gurba-0.40/lib/kernel/lib/
gurba-0.40/lib/kernel/net/
gurba-0.40/lib/kernel/sys/
gurba-0.40/lib/logs/
gurba-0.40/lib/pub/
gurba-0.40/lib/std/modules/languages/
gurba-0.40/lib/std/races/
gurba-0.40/lib/std/races/monsters/
gurba-0.40/lib/wiz/fudge/
gurba-0.40/lib/wiz/spud/
gurba-0.40/src/host/beos/
gurba-0.40/src/host/pc/res/
gurba-0.40/src/kfun/
gurba-0.40/src/lpc/
gurba-0.40/src/parser/
gurba-0.40/tmp/
# define INCLUDE_FILE_IO
# include "dgd.h"
# include "str.h"
# include "array.h"
# include "object.h"
# include "xfloat.h"
# include "interpret.h"
# include "data.h"
# include "path.h"
# include "editor.h"
# include "call_out.h"
# include "comm.net.h"
# include "version.h"
# include "macro.h"
# include "token.h"
# include "ppcontrol.h"
# include "node.h"
# include "parser.h"
# include "compile.h"
# include "csupport.h"
# include "table.h"

typedef struct {
    char *name;		/* name of the option */
    short type;		/* option type */
    bool set;		/* TRUE if option is set */
    Uint low, high;	/* lower and higher bound, for numeric values */
    union {
	long num;	/* numeric value */
	char *str;	/* string value */
    } u;
} config;

static config conf[] = {
# define ARRAY_SIZE	0
				{ "array_size",		INT_CONST, FALSE,
							1, USHRT_MAX / 2 },
# define AUTO_OBJECT	1
				{ "auto_object",	STRING_CONST, FALSE },
# define BINARY_PORT	2
				{ "binary_port",	INT_CONST, FALSE,
							0, USHRT_MAX },
# define CACHE_SIZE	3
				{ "cache_size",		INT_CONST, FALSE,
							2, UINDEX_MAX },
# define CALL_OUTS	4
				{ "call_outs",		INT_CONST, FALSE,
							0, UINDEX_MAX },
# define CREATE		5
				{ "create",		STRING_CONST, FALSE },
# define DIRECTORY	6
				{ "directory",		STRING_CONST, FALSE },
# define DRIVER_OBJECT	7
				{ "driver_object",	STRING_CONST, FALSE },
# define DUMP_FILE	8
				{ "dump_file",		STRING_CONST, FALSE },
# define DYNAMIC_CHUNK	9
				{ "dynamic_chunk",	INT_CONST, FALSE },
# define ED_TMPFILE	10
				{ "ed_tmpfile",		STRING_CONST, FALSE },
# define EDITORS	11
				{ "editors",		INT_CONST, FALSE,
							0, UCHAR_MAX },
# define INCLUDE_DIRS	12
				{ "include_dirs",	'(', FALSE },
# define INCLUDE_FILE	13
				{ "include_file",	STRING_CONST, FALSE },
# define OBJECTS	14
				{ "objects",		INT_CONST, FALSE,
							2, UINDEX_MAX },
# define SECTOR_SIZE	15
				{ "sector_size",	INT_CONST, FALSE,
							512, 8192 },
# define STATIC_CHUNK	16
				{ "static_chunk",	INT_CONST, FALSE },
# define SWAP_FILE	17
				{ "swap_file",		STRING_CONST, FALSE },
# define SWAP_FRAGMENT	18
				{ "swap_fragment",	INT_CONST, FALSE },
# define SWAP_SIZE	19
				{ "swap_size",		INT_CONST, FALSE,
							1024, SW_UNUSED },
# define TELNET_PORT	20
				{ "telnet_port",	INT_CONST, FALSE,
							0, USHRT_MAX },
# define TYPECHECKING	21
				{ "typechecking",	INT_CONST, FALSE,
							0, 1 },
# define USERS		22
				{ "users",		INT_CONST, FALSE,
							1, UCHAR_MAX },
# define NR_OPTIONS	23
};


typedef struct { char fill; char c;	} alignc;
typedef struct { char fill; short s;	} aligns;
typedef struct { char fill; Int i;	} aligni;
typedef struct { char fill; char *p;	} alignp;
typedef struct { char c;		} alignz;

typedef char dumpinfo[28];

# define FORMAT_VERSION	2

# define DUMP_VALID	0	/* valud dump flag */
# define DUMP_VERSION	1	/* dump file version number */
# define DUMP_DRIVER	2	/* 0: vanilla DGD, 1: iChat DGD */
# define DUMP_TYPECHECK	3	/* global typechecking */
# define DUMP_SECSIZE	4	/* sector size */
# define DUMP_TYPE	4	/* first XX bytes, dump type */
# define DUMP_STARTTIME	20	/* start time */
# define DUMP_ELAPSED	24	/* elapsed time */

static dumpinfo header;		/* dumpfile header */
# define s0	(header[ 6])	/* short, msb */
# define s1	(header[ 7])	/* short, lsb */
# define i0	(header[ 8])	/* Int, msb */
# define i1	(header[ 9])
# define i2	(header[10])
# define i3	(header[11])	/* Int, lsb */
# define usize	(header[12])	/* sizeof(uindex) */
# define dsize	(header[13])	/* sizeof(sector) */
# define psize	(header[14])	/* sizeof(char*) */
# define calign	(header[15])	/* align(char) */
# define salign	(header[16])	/* align(short) */
# define ialign	(header[17])	/* align(Int) */
# define palign	(header[18])	/* align(char*) */
# define zalign	(header[19])	/* align(struct) */
static int ualign;		/* align(uindex) */
static int dalign;		/* align(sector) */
static dumpinfo rheader;	/* restored header */
# define rs0	(rheader[ 6])	/* short, msb */
# define rs1	(rheader[ 7])	/* short, lsb */
# define ri0	(rheader[ 8])	/* Int, msb */
# define ri1	(rheader[ 9])
# define ri2	(rheader[10])
# define ri3	(rheader[11])	/* Int, lsb */
# define rusize	(rheader[12])	/* sizeof(uindex) */
# define rdsize	(rheader[13])	/* sizeof(sector) */
# define rpsize	(rheader[14])	/* sizeof(char*) */
# define rcalign (rheader[15])	/* align(char) */
# define rsalign (rheader[16])	/* align(short) */
# define rialign (rheader[17])	/* align(Int) */
# define rpalign (rheader[18])	/* align(char*) */
# define rzalign (rheader[19])	/* align(struct) */
static int rualign;		/* align(uindex) */
static int rdalign;		/* align(sector) */
static Uint starttime;		/* start time */
static Uint elapsed;		/* elapsed time */
static Uint boottime;		/* boot time */

/*
 * NAME:	conf->dumpinit()
 * DESCRIPTION:	initialize dump file information
 */
static void conf_dumpinit()
{
    short s;
    Int i;
    alignc cdummy;
    aligns sdummy;
    aligni idummy;
    alignp pdummy;

    header[DUMP_VALID] = TRUE;			/* valid dump flag */
    header[DUMP_VERSION] = FORMAT_VERSION;	/* dump file version number */
    header[DUMP_DRIVER] = 0;			/* vanilla DGD */
    header[DUMP_TYPECHECK] = conf[TYPECHECKING].u.num;
    header[DUMP_SECSIZE + 0] = conf[SECTOR_SIZE].u.num >> 8;
    header[DUMP_SECSIZE + 1] = conf[SECTOR_SIZE].u.num;

    starttime = boottime = P_time();

    s = 0x1234;
    i = 0x12345678L;
    s0 = strchr((char *) &s, 0x12) - (char *) &s;
    s1 = strchr((char *) &s, 0x34) - (char *) &s;
    i0 = strchr((char *) &i, 0x12) - (char *) &i;
    i1 = strchr((char *) &i, 0x34) - (char *) &i;
    i2 = strchr((char *) &i, 0x56) - (char *) &i;
    i3 = strchr((char *) &i, 0x78) - (char *) &i;
    usize = sizeof(uindex);
    dsize = sizeof(sector);
    psize = sizeof(char*);
    calign = (char *) &cdummy.c - (char *) &cdummy.fill;
    salign = (char *) &sdummy.s - (char *) &sdummy.fill;
    ialign = (char *) &idummy.i - (char *) &idummy.fill;
    palign = (char *) &pdummy.p - (char *) &pdummy.fill;
    zalign = sizeof(alignz);

    ualign = (usize == sizeof(short)) ? salign : ialign;
    dalign = (dsize == sizeof(short)) ? salign : ialign;
}

/*
 * NAME:	conf->dump()
 * DESCRIPTION:	dump system state on file
 */
void conf_dump()
{
    int fd;
    Uint etime;

    header[DUMP_TYPECHECK] = conf[TYPECHECKING].u.num;
    header[DUMP_STARTTIME + 0] = starttime >> 24;
    header[DUMP_STARTTIME + 1] = starttime >> 16;
    header[DUMP_STARTTIME + 2] = starttime >> 8;
    header[DUMP_STARTTIME + 3] = starttime;
    etime = elapsed + P_time() - boottime;
    header[DUMP_ELAPSED + 0] = etime >> 24;
    header[DUMP_ELAPSED + 1] = etime >> 16;
    header[DUMP_ELAPSED + 2] = etime >> 8;
    header[DUMP_ELAPSED + 3] = etime;

    fd = sw_dump(conf[DUMP_FILE].u.str);
    if (!kf_dump(fd)) {
	fatal("failed to dump kfun table");
    }
    if (!o_dump(fd)) {
	fatal("failed to dump object table");
    }
    if (!pc_dump(fd)) {
	fatal("failed to dump precompiled objects");
    }
    if (!co_dump(fd)) {
	fatal("failed to dump callout table");
    }

    lseek(fd, 0L, SEEK_SET);
    write(fd, header, sizeof(dumpinfo));
}

/*
 * NAME:	conf->restore()
 * DESCRIPTION:	restore system state from file
 */
static void conf_restore(fd)
int fd;
{
    unsigned int secsize;
    long posn;

    if (read(fd, rheader, sizeof(dumpinfo)) != sizeof(dumpinfo) ||
	memcmp(header, rheader, DUMP_TYPE) != 0) {
	error("Bad or incompatible restore file header");
    }

    starttime = (UCHAR(rheader[DUMP_STARTTIME + 0]) << 24) |
		(UCHAR(rheader[DUMP_STARTTIME + 1]) << 16) |
		(UCHAR(rheader[DUMP_STARTTIME + 2]) << 8) |
		 UCHAR(rheader[DUMP_STARTTIME + 3]);
    elapsed =  (UCHAR(rheader[DUMP_ELAPSED + 0]) << 24) |
	       (UCHAR(rheader[DUMP_ELAPSED + 1]) << 16) |
	       (UCHAR(rheader[DUMP_ELAPSED + 2]) << 8) |
		UCHAR(rheader[DUMP_ELAPSED + 3]);
    rualign = (rusize == sizeof(short)) ? rsalign : rialign;
    rdalign = (rdsize == sizeof(short)) ? rsalign : rialign;
    if (usize < rusize || dsize < rdsize) {
	error("Cannot restore uindex or sector of greater width");
    }
    secsize = (UCHAR(rheader[DUMP_SECSIZE + 0]) << 8) |
	       UCHAR(rheader[DUMP_SECSIZE + 1]);
    if (secsize > conf[SECTOR_SIZE].u.num) {
	error("Cannot restore bigger sector size");
    }

    sw_restore(fd, secsize);
    kf_restore(fd);
    o_restore(fd);

    posn = lseek(fd, 0L, SEEK_CUR);	/* preserve current file position */
    o_conv();				/* convert all objects */
    lseek(fd, posn, SEEK_SET);		/* restore file position */

    pc_restore(fd);
    boottime = P_time();
    co_restore(fd, boottime);
}

/*
 * NAME:	conf->dsize()
 * DESCRIPTION:	compute the size and alignment of a struct
 *		0x000000ff size in dump file
 *		0x0000ff00 alignment in dump file
 *		0x00ff0000 size
 *		0xff000000 alignment
 */
Uint conf_dsize(layout)
char *layout;
{
    register char *p;
    register Uint sz, rsz, al, ral;
    register Uint size, rsize, align, ralign;

    p = layout;
    size = rsize = 0;
    align = ralign = 1;

    for (;;) {
	switch (*p++) {
	case 'c':	/* character */
	    sz = rsz = sizeof(char);
	    al = calign;
	    ral = rcalign;
	    break;

	case 's':	/* short */
	    sz = rsz = sizeof(short);
	    al = salign;
	    ral = rsalign;
	    break;

	case 'u':	/* uindex */
	    sz = usize;
	    rsz = rusize;
	    al = ualign;
	    ral = rualign;
	    break;

	case 'i':	/* Int */
	    sz = rsz = sizeof(Int);
	    al = ialign;
	    ral = rialign;
	    break;

	case 'd':	/* sector */
	    sz = dsize;
	    rsz = rdsize;
	    al = dalign;
	    ral = rdalign;
	    break;

	case 'p':	/* pointer */
	    sz = psize;
	    rsz = rpsize;
	    al = palign;
	    ral = rpalign;
	    break;

	case 'x':	/* hte */
	    size = ALGN(size, zalign);
	    size = ALGN(size, palign);
	    size += psize;
	    size = ALGN(size, palign);
	    size += psize;
	    size = ALGN(size, zalign);
	    rsize = ALGN(rsize, rzalign);
	    rsize = ALGN(rsize, rpalign);
	    rsize += rpsize;
	    rsize = ALGN(rsize, rpalign);
	    rsize += rpsize;
	    rsize = ALGN(rsize, rzalign);
	    align = ALGN(align, palign);
	    ralign = ALGN(ralign, rpalign);
	    continue;

	case '[':	/* struct */
	    sz = conf_dsize(p);
	    al = (sz >> 8) & 0xff;
	    rsz = (sz >> 16) & 0xff;
	    ral = sz >> 24;
	    sz &= 0xff;
	    p = strchr(p, ']') + 1;
	    break;

	case ']':
	case '\0':	/* end of layout */
	    if (p != layout + 2) {
		/* a stuct and not an array element */
		align = ALGN(align, zalign);
		ralign = ALGN(ralign, rzalign);
	    }
	    return ALGN(rsize, ralign) |
	    	   (ralign << 8) |
		   (ALGN(size, align) << 16) |
		   (align << 24);
	}

	size = ALGN(size, al) + sz;
	rsize = ALGN(rsize, ral) + rsz;
	align = ALGN(align, al);
	ralign = ALGN(ralign, ral);
    }
}

/*
 * NAME:	conf_dconv()
 * DESCRIPTION:	convert structs from dumpfile format
 */
Uint conf_dconv(buf, rbuf, layout, n)
register char *buf, *rbuf;
char *layout;
Uint n;
{
    register Uint i, ri, j, size, rsize;
    register char *p;

    rsize = conf_dsize(layout);
    size = (rsize >> 16) & 0xff;
    rsize &= 0xff;
    while (n > 0) {
	i = ri = 0;
	for (p = layout; *p != '\0' && *p != ']'; p++) {
	    switch (*p) {
	    case 'c':
		i = ALGN(i, calign);
		ri = ALGN(ri, rcalign);
		buf[i] = rbuf[ri];
		i += sizeof(char);
		ri += sizeof(char);
		break;

	    case 's':
		i = ALGN(i, salign);
		ri = ALGN(ri, rsalign);
		buf[i + s0] = rbuf[ri + rs0];
		buf[i + s1] = rbuf[ri + rs1];
		i += sizeof(short);
		ri += sizeof(short);
		break;

	    case 'u':
		i = ALGN(i, ualign);
		ri = ALGN(ri, rualign);
		if (usize == rusize) {
		    if (usize == sizeof(short)) {
			buf[i + s0] = rbuf[ri + rs0];
			buf[i + s1] = rbuf[ri + rs1];
			i += sizeof(short);
			ri += sizeof(short);
		    } else {
			buf[i + i0] = rbuf[ri + ri0];
			buf[i + i1] = rbuf[ri + ri1];
			buf[i + i2] = rbuf[ri + ri2];
			buf[i + i3] = rbuf[ri + ri3];
			i += sizeof(Int);
			ri += sizeof(Int);
		    }
		} else {
		    j = (UCHAR(rbuf[ri + rs0] & rbuf[ri + rs1]) == 0xff) ?
			 -1 : 0;
		    buf[i + i0] = j;
		    buf[i + i1] = j;
		    buf[i + i2] = rbuf[ri + rs0];
		    buf[i + i3] = rbuf[ri + rs1];
		    i += sizeof(Int);
		    ri += sizeof(short);
		}
		break;

	    case 'i':
		i = ALGN(i, ialign);
		ri = ALGN(ri, rialign);
		buf[i + i0] = rbuf[ri + ri0];
		buf[i + i1] = rbuf[ri + ri1];
		buf[i + i2] = rbuf[ri + ri2];
		buf[i + i3] = rbuf[ri + ri3];
		i += sizeof(Int);
		ri += sizeof(Int);
		break;

	    case 'd':
		i = ALGN(i, dalign);
		ri = ALGN(ri, rdalign);
		if (dsize == rdsize) {
		    if (dsize == sizeof(short)) {
			buf[i + s0] = rbuf[ri + rs0];
			buf[i + s1] = rbuf[ri + rs1];
			i += sizeof(short);
			ri += sizeof(short);
		    } else {
			buf[i + i0] = rbuf[ri + ri0];
			buf[i + i1] = rbuf[ri + ri1];
			buf[i + i2] = rbuf[ri + ri2];
			buf[i + i3] = rbuf[ri + ri3];
			i += sizeof(Int);
			ri += sizeof(Int);
		    }
		} else {
		    j = (UCHAR(rbuf[ri + rs0] & rbuf[ri + rs1]) == 0xff) ?
			 -1 : 0;
		    buf[i + i0] = j;
		    buf[i + i1] = j;
		    buf[i + i2] = rbuf[ri + rs0];
		    buf[i + i3] = rbuf[ri + rs1];
		    i += sizeof(Int);
		    ri += sizeof(short);
		}
		break;

	    case 'p':
		i = ALGN(i, palign);
		ri = ALGN(ri, rpalign);
		for (j = psize; j > 0; --j) {
		    buf[i++] = 0;
		}
		ri += rpsize;
		break;

	    case '[':
		j = conf_dsize(++p);
		i = ALGN(i, j >> 24);
		ri = ALGN(ri, (j >> 8) & 0xff);
		j = conf_dconv(buf + i, rbuf + ri, p, (Uint) 1);
		i += (j >> 16) & 0xff;
		ri += j & 0xff;
		p = strchr(p, ']');
		break;

	    case 'x':
		i = ALGN(i, zalign);
		i = ALGN(i, palign);
		for (j = psize; j > 0; --j) {
		    buf[i++] = 0;
		}
		i = ALGN(i, palign);
		for (j = psize; j > 0; --j) {
		    buf[i++] = 0;
		}
		ri = ALGN(ri, rzalign);
		ri = ALGN(ri, rpalign);
		ri += rpsize;
		ri = ALGN(ri, rpalign);
		for (j = rpsize; j > 0; --j) {
		    if (rbuf[ri] != 0) {
			buf[i - 1] = 1;
			break;
		    }
		    ri++;
		}
		ri += j;
		i = ALGN(i, zalign);
		ri = ALGN(ri, rzalign);
		break;
	    }
	}

	buf += size;
	rbuf += rsize;
	--n;
    }

    return (size << 16) | rsize;
}

/*
 * NAME:	conf->dread()
 * DESCRIPTION:	read from dumpfile
 */
void conf_dread(fd, buf, layout, n)
int fd;
char *buf, *layout;
register Uint n;
{
    char buffer[16384];
    register unsigned int i, size, rsize;
    Uint tmp;

    tmp = conf_dsize(layout);
    size = (tmp >> 16) & 0xff;
    rsize = tmp & 0xff;
    while (n != 0) {
	i = sizeof(buffer) / rsize;
	if (i > n) {
	    i = n;
	}
	if (read(fd, buffer, i * rsize) != i * rsize) {
	    fatal("cannot read from dump file");
	}
	conf_dconv(buf, buffer, layout, (Uint) i);
	buf += size * i;
	n -= i;
    }
}


# define MAX_DIRS	32

static char *dirs[MAX_DIRS];

/*
 * NAME:	conferr()
 * DESCRIPTION:	error during the configuration phase
 */
static void conferr(err)
char *err;
{
    message("Config error, line %u: %s\012", tk_line(), err);	/* LF */
}

/*
 * NAME:	config->config()
 * DESCRIPTION:	read config file
 */
static bool conf_config()
{
    register char *p;
    register int h, l, m, c;

    for (h = NR_OPTIONS; h > 0; ) {
	conf[--h].u.num = 0;
    }
    memset(dirs, '\0', sizeof(dirs));

    while ((c=pp_gettok()) != EOF) {
	if (c != IDENTIFIER) {
	    conferr("option expected");
	    return FALSE;
	}

	l = 0;
	h = NR_OPTIONS;
	for (;;) {
	    c = strcmp(yytext, conf[m = (l + h) >> 1].name);
	    if (c == 0) {
		break;	/* found */
	    } else if (c < 0) {
		h = m;	/* search in lower half */
	    } else {
		l = m + 1;	/* search in upper half */
	    }
	    if (l >= h) {
		conferr("unknown option");
		return FALSE;
	    }
	}

	if (pp_gettok() != '=') {
	    conferr("'=' expected");
	    return FALSE;
	}

	if ((c=pp_gettok()) != conf[m].type) {
	    if (c != INT_CONST && c != STRING_CONST && c != '(') {
		conferr("syntax error");
		return FALSE;
	    } else {
		conferr("bad value type");
		return FALSE;
	    }
	}

	switch (c) {
	case INT_CONST:
	    if (yylval.number < conf[m].low ||
		(conf[m].high != 0 && yylval.number > conf[m].high)) {
		conferr("int value out of range");
		return FALSE;
	    }
	    conf[m].u.num = yylval.number;
	    break;

	case STRING_CONST:
	    p = (m == AUTO_OBJECT || m == DRIVER_OBJECT || m == INCLUDE_FILE) ?
		 path_resolve(yytext) : yytext;
	    l = strlen(p);
	    if (l >= STRINGSZ) {
		l = STRINGSZ - 1;
		p[l] = '\0';
	    }
	    m_static();
	    conf[m].u.str = strcpy(REALLOC(conf[m].u.str, char, 0, l + 1), p);
	    m_dynamic();
	    break;

	case '(':
	    if (pp_gettok() != '{') {
		conferr("'{' expected");
		return FALSE;
	    }
	    l = 0;
	    for (;;) {
		if (pp_gettok() != STRING_CONST) {
		    conferr("string expected");
		    return FALSE;
		}
		if (l == MAX_DIRS - 1) {
		    conferr("too many include directories");
		    return FALSE;
		}
		m_static();
		dirs[l] = strcpy(REALLOC(dirs[l], char, 0, strlen(yytext) + 1),
				 yytext);
		l++;
		m_dynamic();
		if ((c=pp_gettok()) == '}') {
		    break;
		}
		if (c != ',') {
		    conferr("',' expected");
		    return FALSE;
		}
	    }
	    if (pp_gettok() != ')') {
		conferr("')' expected");
		return FALSE;
	    }
	    dirs[l] = (char *) NULL;
	    break;
	}
	conf[m].set = TRUE;
	if (pp_gettok() != ';') {
	    conferr("';' expected");
	    return FALSE;
	}
    }

    for (l = 0; l < NR_OPTIONS; l++) {
	if (!conf[l].set) {
	    char buffer[64];

	    sprintf(buffer, "unspecified option %s", conf[l].name);
	    conferr(buffer);
	    return FALSE;
	}
    }
}

static char *fname;		/* file name */
static int fd;			/* file descriptor */
static char *obuf;		/* output buffer */
static unsigned int bufsz;	/* buffer size */

/*
 * NAME:	config->open()
 * DESCRIPTION:	create a new file
 */
static bool copen(file)
char *file;
{
    if ((file=path_file(fname=path_resolve(file))) == (char *) NULL ||
	(fd=open(file, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644)) < 0) {
	message("Config error: cannot create \"/%s\"\012", fname);	/* LF */
	return FALSE;
    }
    bufsz = 0;

    return TRUE;
}

/*
 * NAME:	config->put()
 * DESCRIPTION:	write a string to a file
 */
static void cputs(str)
register char *str;
{
    register unsigned int len, chunk;

    len = strlen(str);
    while (bufsz + len > BUF_SIZE) {
	chunk = BUF_SIZE - bufsz;
	memcpy(obuf + bufsz, str, chunk);
	write(fd, obuf, BUF_SIZE);
	str += chunk;
	len -= chunk;
	bufsz = 0;
    }
    if (len > 0) {
	memcpy(obuf + bufsz, str, len);
	bufsz += len;
    }
}

/*
 * NAME:	config->close()
 * DESCRIPTION:	close a file
 */
static bool cclose()
{
    if (bufsz > 0 && write(fd, obuf, bufsz) != bufsz) {
	message("Config error: cannot write \"/%s\"\012", fname);	/* LF */
	close(fd);
	return FALSE;
    }
    close(fd);

    return TRUE;
}

/*
 * NAME:	config->includes()
 * DESCRIPTION:	create include files
 */
static bool conf_includes()
{
    char buf[BUF_SIZE], buffer[STRINGSZ];

    /* create status.h file */
    obuf = buf;
    sprintf(buffer, "%s/status.h", dirs[0]);
    if (!copen(buffer)) {
	return FALSE;
    }
    cputs("/*\012 * This file defines the fields of the array returned ");
    cputs("by the\012 * status() kfun.  It is automatically generated ");
    cputs("by DGD on startup.\012 */\012\012");
    cputs("# define ST_VERSION\t0\t/* driver version */\012");
    cputs("# define ST_STARTTIME\t1\t/* system start time */\012");
    cputs("# define ST_BOOTTIME\t2\t/* system reboot time */\012");
    cputs("# define ST_UPTIME\t3\t/* system virtual uptime */\012");
    cputs("# define ST_SWAPSIZE\t4\t/* # sectors on swap device */\012");
    cputs("# define ST_SWAPUSED\t5\t/* # sectors allocated */\012");
    cputs("# define ST_SECTORSIZE\t6\t/* size of swap sector */\012");
    cputs("# define ST_SWAPRATE1\t7\t/* # objects swapped out per minute */\012");
    cputs("# define ST_SWAPRATE5\t8\t/* # objects swapped out per five minutes */\012");
    cputs("# define ST_SMEMSIZE\t9\t/* static memory allocated */\012");
    cputs("# define ST_SMEMUSED\t10\t/* static memory in use */\012");
    cputs("# define ST_DMEMSIZE\t11\t/* dynamic memory allocated */\012");
    cputs("# define ST_DMEMUSED\t12\t/* dynamic memory in use */\012");
    cputs("# define ST_OTABSIZE\t13\t/* object table size */\012");
    cputs("# define ST_NOBJECTS\t14\t/* # objects in the system */\012");
    cputs("# define ST_COTABSIZE\t15\t/* callouts table size */\012");
    cputs("# define ST_NCOSHORT\t16\t/* # short-term callouts */\012");
    cputs("# define ST_NCOLONG\t17\t/* # long-term callouts */\012");
    cputs("# define ST_UTABSIZE\t18\t/* user table size */\012");
    cputs("# define ST_ETABSIZE\t19\t/* editor table size */\012");
    cputs("# define ST_STRSIZE\t20\t/* max string size */\012");
    cputs("# define ST_ARRAYSIZE\t21\t/* max array/mapping size */\012");
    cputs("# define ST_STACKDEPTH\t22\t/* remaining stack depth */\012");
    cputs("# define ST_TICKS\t23\t/* remaining ticks */\012");
    cputs("# define ST_PRECOMPILED\t24\t/* precompiled objects */\012");

    cputs("\012# define O_COMPILETIME\t0\t/* time of compilation */\012");
    cputs("# define O_PROGSIZE\t1\t/* program size of object */\012");
    cputs("# define O_DATASIZE\t2\t/* # variables in object */\012");
    cputs("# define O_NSECTORS\t3\t/* # sectors used by object */\012");
    cputs("# define O_CALLOUTS\t4\t/* callouts in object */\012");
    cputs("# define O_INDEX\t5\t/* unique ID for master object */\012");

    cputs("\012# define CO_HANDLE\t0\t/* callout handle */\012");
    cputs("# define CO_FUNCTION\t1\t/* function name */\012");
    cputs("# define CO_DELAY\t2\t/* delay */\012");
    cputs("# define CO_FIRSTXARG\t3\t/* first extra argument */\012");
    if (!cclose()) {
	return FALSE;
    }

    /* create type.h file */
    sprintf(buffer, "%s/type.h", dirs[0]);
    if (!copen(buffer)) {
	return FALSE;
    }
    cputs("/*\012 * This file gives definitions for the value returned ");
    cputs("by the\012 * typeof() kfun.  It is automatically generated ");
    cputs("by DGD on startup.\012 */\012\012");
    sprintf(buffer, "# define T_INT\t\t%d\012", T_INT);
    cputs(buffer);
    sprintf(buffer, "# define T_FLOAT\t%d\012", T_FLOAT);
    cputs(buffer);
    sprintf(buffer, "# define T_STRING\t%d\012", T_STRING);
    cputs(buffer);
    sprintf(buffer, "# define T_OBJECT\t%d\012", T_OBJECT);
    cputs(buffer);
    sprintf(buffer, "# define T_ARRAY\t%d\012", T_ARRAY);
    cputs(buffer);
    sprintf(buffer, "# define T_MAPPING\t%d\012", T_MAPPING);
    cputs(buffer);
    if (!cclose()) {
	return FALSE;
    }

    /* create limits.h file */
    sprintf(buffer, "%s/limits.h", dirs[0]);
    if (!copen(buffer)) {
	return FALSE;
    }
    cputs("/*\012 * This file defines some basic sizes of datatypes and ");
    cputs("resources.\012 * It is automatically generated by DGD on ");
    cputs("startup.\012 */\012\012");
    cputs("# define CHAR_BIT\t\t8\t\t/* # bits in character */\012");
    cputs("# define CHAR_MIN\t\t0\t\t/* min character value */\012");
    cputs("# define CHAR_MAX\t\t255\t\t/* max character value */\012\012");
    cputs("# define INT_MIN\t\t0x80000000\t/* -2147483648 */\012");
    cputs("# define INT_MAX\t\t2147483647\t/* max integer value */\012\012");
    sprintf(buffer, "# define MAX_STRING_SIZE\t%u\t\t/* max string size */\012",
	    USHRT_MAX);
    cputs(buffer);
    if (!cclose()) {
	return FALSE;
    }

    /* create float.h file */
    sprintf(buffer, "%s/float.h", dirs[0]);
    if (!copen(buffer)) {
	return FALSE;
    }
    cputs("/*\012 * This file describes the floating point type. It is ");
    cputs("automatically\012 * generated by DGD on startup.\012 */\012\012");
    cputs("# define FLT_RADIX\t2\t\t\t/* binary */\012");
    cputs("# define FLT_ROUNDS\t1\t\t\t/* round to nearest */\012");
    cputs("# define FLT_EPSILON\t7.2759576142E-12\t/* smallest x: 1.0 + x != 1.0 */\012");
    cputs("# define FLT_DIG\t10\t\t\t/* decimal digits of precision*/\012");
    cputs("# define FLT_MANT_DIG\t36\t\t\t/* binary digits of precision */\012");
    cputs("# define FLT_MIN\t2.22507385851E-308\t/* positive minimum */\012");
    cputs("# define FLT_MIN_EXP\t(-1021)\t\t\t/* minimum binary exponent */\012");
    cputs("# define FLT_MIN_10_EXP\t(-307)\t\t\t/* minimum decimal exponent */\012");
    cputs("# define FLT_MAX\t1.79769313485E+308\t/* positive maximum */\012");
    cputs("# define FLT_MAX_EXP\t1024\t\t\t/* maximum binary exponent */\012");
    cputs("# define FLT_MAX_10_EXP\t308\t\t\t/* maximum decimal exponent */\012");
    if (!cclose()) {
	return FALSE;
    }

    /* create trace.h file */
    sprintf(buffer, "%s/trace.h", dirs[0]);
    if (!copen(buffer)) {
	return FALSE;
    }
    cputs("/*\012 * This file describes the fields of the array returned for ");
    cputs("every stack\012 * frame by the call_trace() function.  It is ");
    cputs("automatically generated by DGD\012 * on startup.\012 */\012\012");
    cputs("# define TRACE_OBJNAME\t0\t/* name of the object */\012");
    cputs("# define TRACE_PROGNAME\t1\t/* name of the object the function is in */\012");
    cputs("# define TRACE_FUNCTION\t2\t/* function name */\012");
    cputs("# define TRACE_LINE\t3\t/* line number */\012");
    cputs("# define TRACE_EXTERNAL\t4\t/* external call flag */\012");
    cputs("# define TRACE_FIRSTARG\t5\t/* first argument to function */\012");
    return cclose();
}

/*
 * NAME:	config->init()
 * DESCRIPTION:	initialize the driver
 */
bool conf_init(configfile, fd)
char *configfile;
int fd;
{
    bool init;

    /*
     * process config file
     */
    if (!pp_init(configfile, (char **) NULL, 0)) {
	message("Config error: cannot open config file\012");	/* LF */
	m_finish();
	return FALSE;
    }
    init = conf_config();
    pp_clear();
    if (!init) {
	m_finish();
	return FALSE;
    }

    /* change directory */
    if (chdir(conf[DIRECTORY].u.str) < 0) {
	message("Config error: bad base directory \"%s\"\012",	/* LF */
		conf[DIRECTORY].u.str);
	m_finish();
	return FALSE;
    }

    m_static();

    /* initialize strings */
    str_init();

    /* initialize arrays */
    arr_init((int) conf[ARRAY_SIZE].u.num);

    /* initialize objects */
    o_init((uindex) conf[OBJECTS].u.num);

    /* initialize swap device */
    sw_init(conf[SWAP_FILE].u.str,
	    (sector) conf[SWAP_SIZE].u.num,
	    (sector) conf[CACHE_SIZE].u.num,
	    (unsigned int) conf[SECTOR_SIZE].u.num);

    /* initialize swapped data handler */
    d_init();

    /* initalize editor */
    ed_init(conf[ED_TMPFILE].u.str,
	    (int) conf[EDITORS].u.num);

    /* initialize call_outs */
    co_init((uindex) conf[CALL_OUTS].u.num,
	    (int) conf[SWAP_FRAGMENT].u.num);

    /* initialize kfuns */
    kf_init();

    /* initialize interpreter */
    i_init(conf[CREATE].u.str);

    /* initialize compiler */
    c_init(conf[AUTO_OBJECT].u.str,
	   conf[DRIVER_OBJECT].u.str,
	   conf[INCLUDE_FILE].u.str,
	   dirs);

    m_dynamic();

    if (!init) {
	comm_finish();
	m_finish();
	return FALSE;
    }

    /* initialize memory manager */
    m_init((size_t) conf[STATIC_CHUNK].u.num,
    	   (size_t) conf[DYNAMIC_CHUNK].u.num);

    /* initialize communications */
    m_static();
    comm_init((int) conf[USERS].u.num);
    m_dynamic();

    /*
     * create include files
     */
    if (!conf_includes()) {
	comm_finish();
	m_finish();
	return FALSE;
    }

    /* preload compiled objects */
    pc_preload(conf[AUTO_OBJECT].u.str, conf[DRIVER_OBJECT].u.str);

    /* initialize dumpfile header */
    conf_dumpinit();

    if (ec_push((ec_ftn) NULL)) {
	endthread();
	message((char *) NULL);
	message("Config error: initialization failed\012");	/* LF */
	comm_finish();
	ed_finish();
	m_finish();
	return FALSE;
    }
    if (fd < 0) {
	/* initialize mudlib */
	call_driver_object(cframe, "initialize", 0);
    } else {
	/* restore dump file */
	conf_restore(fd);

	/* notify mudlib */
	call_driver_object(cframe, "restored", 0);
    }
    ec_pop();
    i_del_value(cframe->sp++);
    endthread();

    return TRUE;
}

/*
 * NAME:	config->base_dir()
 * DESCRIPTION:	return the driver base directory
 */
char *conf_base_dir()
{
    return conf[DIRECTORY].u.str;
}

/*
 * NAME:	config->driver()
 * DESCRIPTION:	return the driver object name
 */
char *conf_driver()
{
    return conf[DRIVER_OBJECT].u.str;
}

/*
 * NAME:	config->typechecking()
 * DESCRIPTION:	return the global typechecking flag
 */
bool conf_typechecking()
{
    return (bool) conf[TYPECHECKING].u.num;
}

/*
 * NAME:	config->array_size()
 * DESCRIPTION:	return the maximum array size
 */
unsigned short conf_array_size()
{
    return conf[ARRAY_SIZE].u.num;
}

/*
 * NAME:	config->statusi()
 * DESCRIPTION:	return resource usage information
 */
bool conf_statusi(f, idx, v)
frame *f;
Int idx;
register value *v;
{
    char *version;
    allocinfo *mstat;
    uindex ncoshort, ncolong;

    switch (idx) {
    case 0:	/* ST_VERSION */
	v->type = T_STRING;
	version = VERSION;
	str_ref(v->u.string = str_new(version, (long) strlen(version)));
	break;

    case 1:	/* ST_STARTTIME */
	v->type = T_INT;
	v->u.number = starttime;
	break;

    case 2:	/* ST_BOOTTIME */
	v->type = T_INT;
	v->u.number = boottime;
	break;

    case 3:	/* ST_UPTIME */
	v->type = T_INT;
	v->u.number = elapsed + P_time() - boottime;
	break;

    case 4:	/* ST_SWAPSIZE */
	v->type = T_INT;
	v->u.number = conf[SWAP_SIZE].u.num;
	break;

    case 5:	/* ST_SWAPUSED */
	v->type = T_INT;
	v->u.number = sw_count();
	break;

    case 6:	/* ST_SECTORSIZE */
	v->type = T_INT;
	v->u.number = conf[SECTOR_SIZE].u.num;
	break;

    case 7:	/* ST_SWAPRATE1 */
	v->type = T_INT;
	v->u.number = co_swaprate1();
	break;

    case 8:	/* ST_SWAPRATE5 */
	v->type = T_INT;
	v->u.number = co_swaprate5();
	break;

    case 9:	/* ST_SMEMSIZE */
	mstat = m_info();
	v->type = T_INT;
	v->u.number = mstat->smemsize;
	break;

    case 10:	/* ST_SMEMUSED */
	mstat = m_info();
	v->type = T_INT;
	v->u.number = mstat->smemused;
	break;

    case 11:	/* ST_DMEMSIZE */
	mstat = m_info();
	v->type = T_INT;
	v->u.number = mstat->dmemsize;
	break;

    case 12:	/* ST_DMEMUSED */
	mstat = m_info();
	v->type = T_INT;
	v->u.number = mstat->dmemused;
	break;

    case 13:	/* ST_OTABSIZE */
	v->type = T_INT;
	v->u.number = conf[OBJECTS].u.num;
	break;

    case 14:	/* ST_NOBJECTS */
	v->type = T_INT;
	v->u.number = o_count();
	break;

    case 15:	/* ST_COTABSIZE */
	v->type = T_INT;
	v->u.number = conf[CALL_OUTS].u.num;
	break;

    case 16:	/* ST_NCOSHORT */
	co_info(&ncoshort, &ncolong);
	v->type = T_INT;
	v->u.number = ncoshort;
	break;

    case 17:	/* ST_NCOLONG */
	co_info(&ncoshort, &ncolong);
	v->type = T_INT;
	v->u.number = ncolong;
	break;

    case 18:	/* ST_UTABSIZE */
	v->type = T_INT;
	v->u.number = conf[USERS].u.num;
	break;

    case 19:	/* ST_ETABSIZE */
	v->type = T_INT;
	v->u.number = conf[EDITORS].u.num;
	break;

    case 20:	/* ST_STRSIZE */
	v->type = T_INT;
	v->u.number = USHRT_MAX;
	break;

    case 21:	/* ST_ARRAYSIZE */
	v->type = T_INT;
	v->u.number = conf[ARRAY_SIZE].u.num;
	break;

    case 22:	/* ST_STACKDEPTH */
	v->type = T_INT;
	v->u.number = i_get_depth(f);
	break;

    case 23:	/* ST_TICKS */
	v->type = T_INT;
	v->u.number = i_get_ticks(f);
	break;

    case 24:	/* ST_PRECOMPILED */
	v->type = T_ARRAY;
	arr_ref(v->u.array = pc_list(f->data));
	break;

    default:
	return FALSE;
    }

    return TRUE;
}

/*
 * NAME:	config->status()
 * DESCRIPTION:	return an array with information about resource usage
 */
array *conf_status(f)
register frame *f;
{
    register value *v;
    register Int i;
    array *a;

    a = arr_new(f->data, 25L);
    for (i = 0, v = a->elts; i < 25; i++, v++) {
	conf_statusi(f, i, v);
    }
    return a;
}

/*
 * NAME:	config->objecti()
 * DESCRIPTION:	return object resource usage information
 */
bool conf_objecti(data, obj, idx, v)
dataspace *data;
register object *obj;
Int idx;
register value *v;
{
    register control *ctrl;
    object *prog;

    prog = (obj->flags & O_MASTER) ? obj : &otable[obj->u_master];
    ctrl = (O_UPGRADING(prog)) ? otable[prog->prev].ctrl : o_control(prog);

    switch (idx) {
    case 0:	/* O_COMPILETIME */
	v->type = T_INT;
	v->u.number = ctrl->compiled;
	break;

    case 1:	/* O_PROGSIZE */
	v->type = T_INT;
	v->u.number = d_get_progsize(ctrl);
	break;

    case 2:	/* O_DATASIZE */
	v->type = T_INT;
	v->u.number = ctrl->nvariables;
	break;

    case 3:	/* O_NSECTORS */
	v->type = T_INT;
	v->u.number = (obj->flags & O_CREATED) ? o_dataspace(obj)->nsectors : 0;
	if (obj->flags & O_MASTER) {
	    v->u.number += ctrl->nsectors;
	}
	break;

    case 4:	/* O_CALLOUTS */
	v->type = T_ARRAY;
	arr_ref(v->u.array = (obj->flags & O_CREATED) ?
			      co_list(data, obj) : arr_new(data, 0L));
	break;

    case 5:	/* O_INDEX */
	v->type = T_INT;
	v->u.number = (obj->flags & O_MASTER) ?
		       (Uint) obj->index : obj->u_master;
	break;


    default:
	return FALSE;
    }

    return TRUE;
}

/*
 * NAME:	config->object()
 * DESCRIPTION:	return resource usage of an object
 */
array *conf_object(data, obj)
register dataspace *data;
register object *obj;
{
    register value *v;
    register Int i;
    array *a;

    a = arr_new(data, 6L);
    for (i = 0, v = a->elts; i < 6; i++, v++) {
	conf_objecti(data, obj, i, v);
    }
    return a;
}