# 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 "ed.h" # include "call_out.h" # include "comm.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 */ long 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, 1000, 8192 }, # define AUTO_OBJECT 1 { "auto_object", STRING_CONST, FALSE }, # define BINARY_PORT 2 { "binary_port", INT_CONST, FALSE, 1000 }, # define CACHE_SIZE 3 { "cache_size", INT_CONST, FALSE, 100, UINDEX_MAX }, # define CALL_OUTS 4 { "call_outs", INT_CONST, FALSE, 0, UINDEX_MAX }, # define CALL_STACK 5 { "call_stack", INT_CONST, FALSE, 10 }, # define CREATE 6 { "create", STRING_CONST, FALSE }, # define DIRECTORY 7 { "directory", STRING_CONST, FALSE }, # define DRIVER_OBJECT 8 { "driver_object", STRING_CONST, FALSE }, # define DUMP_FILE 9 { "dump_file", STRING_CONST, FALSE }, # define DYNAMIC_CHUNK 10 { "dynamic_chunk", INT_CONST, FALSE }, # define ED_TMPFILE 11 { "ed_tmpfile", STRING_CONST, FALSE }, # define EDITORS 12 { "editors", INT_CONST, FALSE, 1, 255 }, # define INCLUDE_DIRS 13 { "include_dirs", '(', FALSE }, # define INCLUDE_FILE 14 { "include_file", STRING_CONST, FALSE }, # define MAX_COST 15 { "max_cost", INT_CONST, FALSE, 100000L }, # define OBJECTS 16 { "objects", INT_CONST, FALSE, 100 }, # define RESERVED_CSTACK 17 { "reserved_cstack", INT_CONST, FALSE, 5 }, # define RESERVED_VSTACK 18 { "reserved_vstack", INT_CONST, FALSE, 20 }, # define SECTOR_SIZE 19 { "sector_size", INT_CONST, FALSE, 512, 8192 }, # define STATIC_CHUNK 20 { "static_chunk", INT_CONST, FALSE }, # define SWAP_FILE 21 { "swap_file", STRING_CONST, FALSE }, # define SWAP_FRAGMENT 22 { "swap_fragment", INT_CONST, FALSE }, # define SWAP_SIZE 23 { "swap_size", INT_CONST, FALSE, 1024, UINDEX_MAX }, # define TELNET_PORT 24 { "telnet_port", INT_CONST, FALSE, 1000 }, # define TYPECHECKING 25 { "typechecking", INT_CONST, FALSE, 0, 1 }, # define USERS 26 { "users", INT_CONST, FALSE, 1, 255 }, # define VALUE_STACK 27 { "value_stack", INT_CONST, FALSE, 100 }, # define NR_OPTIONS 28 }; typedef struct { char fill; /* filler */ char c; /* char */ } calign; typedef struct { char fill; /* filler */ short s; /* short */ } salign; typedef struct { char fill; /* filler */ Int i; /* Int */ } ialign; typedef struct { char fill; /* filler */ long l; /* long */ } lalign; typedef struct { char fill; /* filler */ char *p; /* char* */ } palign; typedef struct { /* struct align */ char c; } align; static char header[18]; /* dump file header */ static Uint starttime; /* start time */ static Uint elapsed; /* elapsed time */ static Uint boottime; /* boot time */ /* * NAME: conf->dump() * DESCRIPTION: dump system state on file */ void conf_dump() { Uint t[4]; int fd; 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 (!co_dump(fd)) { fatal("failed to dump callout table"); } header[2] = conf[TYPECHECKING].u.num; t[0] = conf[SECTOR_SIZE].u.num; t[1] = P_time(); t[2] = starttime; t[3] = elapsed + t[1] - boottime; lseek(fd, 0L, SEEK_SET); write(fd, header, sizeof(header)); write(fd, (char *) t, sizeof(t)); } /* * NAME: conf->restore() * DESCRIPTION: restore system stare from file */ static void conf_restore(fd) int fd; { char buffer[sizeof(header)]; Uint t[4]; if (read(fd, buffer, sizeof(header)) != sizeof(header) || buffer[0] != 1 || memcmp(buffer + 2, header + 2, sizeof(header) - 2) != 0 || read(fd, (char *) t, sizeof(t)) != sizeof(t)) { fatal("bad or incompatible restore file header"); } t[1] = P_time() - t[1]; starttime = t[2]; elapsed = t[3]; sw_restore(fd, (int) t[0]); kf_restore(fd); o_restore(fd, t[1]); co_restore(fd, t[1]); } /* * NAME: conferr() * DESCRIPTION: cause a fatal error during the configuration phase */ static void conferr(err) char *err; { fatal("config file, line %u: %s", tk_line(), err); } # define MAX_DIRS 32 /* * NAME: config->init() * DESCRIPTION: initialize the driver */ void conf_init(configfile, dumpfile) char *configfile, *dumpfile; { static char *nodir[1], *dirs[MAX_DIRS], buffer[STRINGSZ]; register char *p; register int h, l, m, c; FILE *fp; short s; Int i; int fd; calign cdummy; salign sdummy; ialign idummy; lalign ldummy; palign pdummy; if (!pp_init(configfile, nodir, 0)) { fatal("cannot open config file"); } while ((c=pp_gettok()) != EOF) { if (c != IDENTIFIER) { conferr("option expected"); } 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"); } } if (pp_gettok() != '=') { conferr("'=' expected"); } if ((c=pp_gettok()) != conf[m].type) { if (c != INT_CONST && c != STRING_CONST && c != '(') { conferr("syntax error"); } else { conferr("bad value type"); } } 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"); } conf[m].u.num = yylval.number; break; case STRING_CONST: p = (m == AUTO_OBJECT || m == DRIVER_OBJECT || m == INCLUDE_FILE) ? path_resolve(yytext) : yytext; if (conf[m].u.str != (char *) NULL) { FREE(conf[m].u.str); } l = strlen(p); if (l >= STRINGSZ) { l = STRINGSZ - 1; p[l] = '\0'; } mstatic(); conf[m].u.str = strcpy(ALLOC(char, l + 1), p); mdynamic(); break; case '(': if (pp_gettok() != '{') { conferr("'{' expected"); } l = 0; for (;;) { if (pp_gettok() != STRING_CONST) { conferr("string expected"); } if (l == MAX_DIRS - 1) { conferr("too many include directories"); } if (dirs[l] != (char *) NULL) { FREE(dirs[l]); } mstatic(); dirs[l++] = strcpy(ALLOC(char, strlen(yytext) + 1), yytext); mdynamic(); if ((c=pp_gettok()) == '}') { break; } if (c != ',') { conferr("',' expected"); } } if (pp_gettok() != ')') { conferr("')' expected"); } dirs[l] = (char *) NULL; break; } conf[m].set = TRUE; if (pp_gettok() != ';') { conferr("';' expected"); } } for (l = 0; l < NR_OPTIONS; l++) { char buf[128]; if (!conf[l].set) { sprintf(buf, "unspecified option %s", conf[l].name); conferr(buf); } } pp_clear(); if (dumpfile != (char *) NULL) { fd = open(dumpfile, O_RDONLY | O_BINARY); if (fd < 0) { fatal("cannot open restore file"); } } /* change directory */ if (chdir(conf[DIRECTORY].u.str) < 0) { fatal("bad base directory \"%s\"", conf[DIRECTORY].u.str); } mstatic(); /* initialize strings */ str_init(); /* initialize arrays */ arr_init((int) conf[ARRAY_SIZE].u.num); /* initialize object */ o_init((int) conf[OBJECTS].u.num); /* initialize swap */ sw_init(conf[SWAP_FILE].u.str, (int) conf[SWAP_SIZE].u.num, (int) conf[CACHE_SIZE].u.num, (int) conf[SECTOR_SIZE].u.num); /* 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 compiler */ c_init(conf[AUTO_OBJECT].u.str, conf[DRIVER_OBJECT].u.str, conf[INCLUDE_FILE].u.str, dirs, (int) conf[TYPECHECKING].u.num); /* initialize interpreter */ i_init((int) conf[VALUE_STACK].u.num, (int) conf[RESERVED_VSTACK].u.num, (int) conf[CALL_STACK].u.num, (int) conf[RESERVED_CSTACK].u.num, conf[CREATE].u.str); mdynamic(); /* initialize memory manager */ minit((unsigned int) conf[STATIC_CHUNK].u.num, (unsigned int) conf[DYNAMIC_CHUNK].u.num); /* create status.h file */ sprintf(buffer, "%s/status.h", dirs[0]); fp = fopen(path_file(path_resolve(buffer)), "w"); if (fp == (FILE *) NULL) { fatal("cannot create \"%s\"", buffer); } P_fbinio(fp); fprintf(fp, "/*\012 * This file defines the fields of the array returned "); fprintf(fp, "by the\012 * status() kfun. It is automatically generated "); fprintf(fp, "by DGD on startup.\012 */\012\012"); fprintf(fp, "# define ST_VERSION\t0\t/* driver version */\012"); fprintf(fp, "# define ST_STARTTIME\t1\t/* system start time */\012"); fprintf(fp, "# define ST_BOOTTIME\t2\t/* system boot time */\012"); fprintf(fp, "# define ST_UPTIME\t3\t/* system virtual uptime */\012"); fprintf(fp, "# define ST_SWAPSIZE\t4\t/* # sectors on swap device */\012"); fprintf(fp, "# define ST_SWAPUSED\t5\t/* # sectors allocated */\012"); fprintf(fp, "# define ST_SECTORSIZE\t6\t/* size of swap sector */\012"); fprintf(fp, "# define ST_SWAPRATE1\t7\t/* # objects swapped out per minute */\012"); fprintf(fp, "# define ST_SWAPRATE5\t8\t/* # objects swapped out per five minutes */\012"); fprintf(fp, "# define ST_SMEMSIZE\t9\t/* static memory allocated */\012"); fprintf(fp, "# define ST_SMEMUSED\t10\t/* static memory in use */\012"); fprintf(fp, "# define ST_DMEMSIZE\t11\t/* dynamic memory allocated */\012"); fprintf(fp, "# define ST_DMEMUSED\t12\t/* dynamic memory in use */\012"); fprintf(fp, "# define ST_OTABSIZE\t13\t/* object table size */\012"); fprintf(fp, "# define ST_NOBJECTS\t14\t/* # objects in the system */\012"); fprintf(fp, "# define ST_COTABSIZE\t15\t/* callouts table size */\012"); fprintf(fp, "# define ST_NCOSHORT\t16\t/* # short-term callouts */\012"); fprintf(fp, "# define ST_NCOLONG\t17\t/* # long-term callouts */\012"); fprintf(fp, "# define ST_UTABSIZE\t18\t/* user table size */\012"); fprintf(fp, "# define ST_ETABSIZE\t19\t/* editor table size */\012"); fprintf(fp, "\012# define O_COMPILETIME\t0\t/* time of compilation */\012"); fprintf(fp, "# define O_PROGSIZE\t1\t/* program size of object */\012"); fprintf(fp, "# define O_DATASIZE\t2\t/* data size of object */\012"); fprintf(fp, "# define O_NSECTORS\t3\t/* # sectors used by object */\012"); fprintf(fp, "# define O_CALLOUTS\t4\t/* callouts in object */\012"); fclose(fp); /* create type.h file */ sprintf(buffer, "%s/type.h", dirs[0]); fp = fopen(path_file(path_resolve(buffer)), "w"); if (fp == (FILE *) NULL) { fatal("cannot create \"%s\"", buffer); } P_fbinio(fp); fprintf(fp, "/*\012 * This file gives definitions for the value returned "); fprintf(fp, "by the\012 * typeof() kfun. It is automatically generated "); fprintf(fp, "by DGD on startup.\012 */\012\012"); fprintf(fp, "# define T_INT\t\t%d\012", T_INT); fprintf(fp, "# define T_FLOAT\t%d\012", T_FLOAT); fprintf(fp, "# define T_STRING\t%d\012", T_STRING); fprintf(fp, "# define T_OBJECT\t%d\012", T_OBJECT); fprintf(fp, "# define T_ARRAY\t%d\012", T_ARRAY); fprintf(fp, "# define T_MAPPING\t%d\012", T_MAPPING); fclose(fp); /* create limits.h file */ sprintf(buffer, "%s/limits.h", dirs[0]); fp = fopen(path_file(path_resolve(buffer)), "w"); if (fp == (FILE *) NULL) { fatal("cannot create \"%s\"", buffer); } P_fbinio(fp); fprintf(fp, "/*\012 * This file defines some basic sizes of datatypes and "); fprintf(fp, "resources.\012 * It is automatically generated by DGD on "); fprintf(fp, "startup.\012 */\012\012"); fprintf(fp, "# define CHAR_BIT\t\t8\t\t/* # bits in character */\012"); fprintf(fp, "# define CHAR_MIN\t\t0\t\t/* min character value */\012"); fprintf(fp, "# define CHAR_MAX\t\t255\t\t/* max character value */\012\012"); fprintf(fp, "# define INT_MIN\t\t0x80000000\t/* -2147483648 */\012"); fprintf(fp, "# define INT_MAX\t\t2147483647\t/* max integer value */\012\012"); fprintf(fp, "# define MAX_STRING_SIZE\t%u\t\t/* max string size */\012", USHRT_MAX - sizeof(string)); fprintf(fp, "# define MAX_ARRAY_SIZE\t\t%ld\t\t/* max array size */\012", conf[ARRAY_SIZE].u.num); fprintf(fp, "# define MAX_MAPPING_SIZE\t%ld\t\t/* max mapping size */\012\012", conf[ARRAY_SIZE].u.num); fprintf(fp, "# define MAX_EXEC_COST\t\t%ld\t\t/* max execution cost */\012", conf[MAX_COST].u.num); fclose(fp); /* create float.h file */ sprintf(buffer, "%s/float.h", dirs[0]); fp = fopen(path_file(path_resolve(buffer)), "w"); if (fp == (FILE *) NULL) { fatal("cannot create \"%s\"", buffer); } P_fbinio(fp); fprintf(fp, "/*\012 * This file describes the floating point type. It is "); fprintf(fp, "automatically\012 * generated by DGD on startup.\012 */\012\012"); fprintf(fp, "# define FLT_RADIX\t2\t\t\t/* binary */\012"); fprintf(fp, "# define FLT_ROUNDS\t1\t\t\t/* round to nearest */\012"); fprintf(fp, "# define FLT_EPSILON\t7.2759576142E-12\t/* smallest x: 1.0 + x != 1.0 */\012"); fprintf(fp, "# define FLT_DIG\t10\t\t\t/* decimal digits of precision*/\012"); fprintf(fp, "# define FLT_MANT_DIG\t36\t\t\t/* binary digits of precision */\012"); fprintf(fp, "# define FLT_MIN\t2.22507385851E-308\t/* positive minimum */\012"); fprintf(fp, "# define FLT_MIN_EXP\t(-1021)\t\t\t/* minimum binary exponent */\012"); fprintf(fp, "# define FLT_MIN_10_EXP\t(-307)\t\t\t/* minimum decimal exponent */\012"); fprintf(fp, "# define FLT_MAX\t1.79769313485E+308\t/* positive maximum */\012"); fprintf(fp, "# define FLT_MAX_EXP\t1024\t\t\t/* maximum binary exponent */\012"); fprintf(fp, "# define FLT_MAX_10_EXP\t308\t\t\t/* maximum decimal exponent */\012"); fclose(fp); /* preload compiled objects */ pc_preload(conf[AUTO_OBJECT].u.str, conf[DRIVER_OBJECT].u.str); /* initialize dumpfile header */ s = 0x1234; i = 0x12345678L; header[0] = 1; /* valid dump flag */ header[1] = 0; /* editor flag */ header[2] = conf[TYPECHECKING].u.num; /* global typechecking */ header[3] = sizeof(uindex); /* sizeof uindex */ header[4] = sizeof(long); /* sizeof long */ header[5] = sizeof(char *); /* sizeof char* */ header[6] = ((char *) &s)[0]; /* 1 of 2 */ header[7] = ((char *) &s)[1]; /* 2 of 2 */ header[8] = ((char *) &i)[0]; /* 1 of 4 */ header[9] = ((char *) &i)[1]; /* 2 of 4 */ header[10] = ((char *) &i)[2]; /* 3 of 4 */ header[11] = ((char *) &i)[3]; /* 4 of 4 */ header[12] = (char *) &cdummy.c - (char *) &cdummy.fill; /* char align */ header[13] = (char *) &sdummy.s - (char *) &sdummy.fill; /* short align */ header[14] = (char *) &idummy.i - (char *) &idummy.fill; /* int align */ header[15] = (char *) &ldummy.l - (char *) &ldummy.fill; /* long align */ header[16] = (char *) &pdummy.p - (char *) &pdummy.fill; /* pointer align */ header[17] = sizeof(align); /* struct align */ starttime = boottime = P_time(); i_set_cost((Int) conf[MAX_COST].u.num); if (dumpfile == (char *) NULL) { /* * initialize mudlib */ call_driver_object("initialize", 0); } else { /* * restore dump file */ conf_restore(fd); close(fd); call_driver_object("restored", 0); } i_del_value(sp++); /* initialize communications */ mstatic(); comm_init((int) conf[USERS].u.num, (int) conf[TELNET_PORT].u.num, (int) conf[BINARY_PORT].u.num); mdynamic(); } /* * NAME: config->basedir() * 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->exec_cost() * DESCRIPTION: return the maximum execution cost */ Int conf_exec_cost() { return conf[MAX_COST].u.num; } /* * NAME: config->status() * DESCRIPTION: return an array with information about resource usage */ array *conf_status() { register value *v; array *a; char *version; allocinfo *mstat; uindex ncoshort, ncolong; a = arr_new(20L); v = a->elts; /* version */ v->type = T_STRING; version = VERSION; str_ref((v++)->u.string = str_new(version, (long) strlen(version))); /* uptime */ v->type = T_INT; (v++)->u.number = starttime; v->type = T_INT; (v++)->u.number = boottime; v->type = T_INT; (v++)->u.number = elapsed + P_time() - boottime; /* swap */ v->type = T_INT; (v++)->u.number = conf[SWAP_SIZE].u.num; v->type = T_INT; (v++)->u.number = sw_count(); v->type = T_INT; (v++)->u.number = conf[SECTOR_SIZE].u.num; v->type = T_INT; (v++)->u.number = co_swaprate1(); v->type = T_INT; (v++)->u.number = co_swaprate5(); /* memory */ mstat = minfo(); v->type = T_INT; (v++)->u.number = mstat->smemsize; v->type = T_INT; (v++)->u.number = mstat->smemused; v->type = T_INT; (v++)->u.number = mstat->dmemsize; v->type = T_INT; (v++)->u.number = mstat->dmemused; /* objects */ v->type = T_INT; (v++)->u.number = conf[OBJECTS].u.num; v->type = T_INT; (v++)->u.number = o_count(); /* callouts */ co_info(&ncoshort, &ncolong); v->type = T_INT; (v++)->u.number = conf[CALL_OUTS].u.num; v->type = T_INT; (v++)->u.number = ncoshort; v->type = T_INT; (v++)->u.number = ncolong; /* users & editors */ v->type = T_INT; (v++)->u.number = conf[USERS].u.num; v->type = T_INT; v->u.number = conf[EDITORS].u.num; return a; } /* * NAME: config->object() * DESCRIPTION: return resource usage of an object */ array *conf_object(obj) object *obj; { register control *ctrl; register value *v; array *clist, *a; dataspace *data; clist = co_list(obj); ctrl = o_control(obj); data = o_dataspace(obj); a = arr_new(5L); v = a->elts; v->type = T_INT; (v++)->u.number = ctrl->compiled; v->type = T_INT; (v++)->u.number = ctrl->ninherits * sizeof(dinherit) + ctrl->progsize + ctrl->nstrings * (long) sizeof(dstrconst) + ctrl->strsize + ctrl->nfuncdefs * sizeof(dfuncdef) + ctrl->nvardefs * sizeof(dvardef) + ctrl->nfuncalls * 2L + ctrl->nsymbols * (long) sizeof(dsymbol); v->type = T_INT; (v++)->u.number = ctrl->nvariables * sizeof(value); v->type = T_INT; if (obj->flags & O_MASTER) { (v++)->u.number = ctrl->nsectors + data->nsectors; } else { (v++)->u.number = data->nsectors; } v->type = T_ARRAY; arr_ref(v->u.array = clist); return a; }