/* dbm.c */
#include "copyright.h"
#include "config.h"
#include <stdio.h>
#ifdef STRING_H
#include <string.h>
#else
#include <strings.h>
#endif /* STRING_H */
#include <sys/time.h>
#include <ctype.h>
#ifdef STDDEF_H
#include <stddef.h>
#else
#define size_t unsigned
#endif /* STDDEF_H */
#include "dbm.h"
#include "teeny.h"
/*
* This implements the mainline of the TeenyMUD database manager, for doing
* bulk operations standalone on a TeenyMUD database.
*
*/
char *strstr_CI();
int sel_handle();
int pur_handle();
int cho_handle();
int sum_handle();
int fix_handle();
int lists_handle();
void warning();
void fatal();
struct {
char *name;
int (*handler) ();
} cmdtab[] = {
{
"select", sel_handle
},
{
"purge", pur_handle
},
{
"chown", cho_handle
},
{
"summarize", sum_handle
},
{
"fix-exits", fix_handle
},
{
"fix-lists", lists_handle
},
{
NULL, NULL
}
};
/* This is the RPN expression we'll apply to the db */
static atom expr[MAXEXPR];
/* The current time, expressed as minute since the epoch. */
int currenttime;
/* Do it to it */
main(argc, argv)
int argc;
char *argv[];
{
char cmd[1024];
char *command, *p;
int i;
int ret;
int required;
struct timeval tv;
if (argc != 3) {
printf("Usage: %s <indexfile> <chunkfile>\n",
argv[0]);
exit(1);
}
(void) gettimeofday(&tv, (struct timezone *) 0);
currenttime = tv.tv_sec / 60;
/* Open up the database */
initialize_cache(10240L); /* Smallish cache. */
open_chunkfile(argv[2]);
printf("Reading descriptors...\n");
read_descriptors(argv[1]);
/* Now loop busily around until we quit. */
while (1) {
printf("dbm>");
get_cmd(cmd);
/* Strip out the first token. */
p = cmd;
while (isspace(*p))
p++;
if (!*p)
continue;
command = p;
while (!isspace(*p) && *p)
p++;
if (*p)
*p++ = '\0';
while (isspace(*p))
p++;
/* command points at the first token, p points */
/* at the rest of the string, if any. Try to find */
/* The command. */
if (strcmp(command, "quit") == 0)
break;
for (i = 0; cmdtab[i].name != NULL; i++) {
if (strcmp(cmdtab[i].name, command) == 0) {
ret = (cmdtab[i].handler) (p, expr, &required);
if (ret == -2) {
required = 0;
expr[0].type = STOP;
}
break;
}
}
if (cmdtab[i].name == NULL) {
printf("No such command.\n");
}
}
/* Bring the db back into synch, and quit. */
cache_flush();
if (write_descriptors(argv[1]) == -1) {
warning("Final db dump", "write_descriptors() failed.");
}
}
/*
* Routine to evalute an expression on a database object. Returns 1 if the
* object meets the conditions, 0 otherwise.
*
*/
static int eval_stack[512];/* Screw counting. Make the bugger *big* */
eval_expr(obj, exp, required)
int obj;
atom *exp;
int required;
{
int sp;
int op1, op2;
char *name;
int owner;
int flags;
int timestamp;
/* Go and get all the required stuff for this expression */
if (required & REQ_NAME) {
if (get_str_elt(obj, NAME, &name) == -1) {
printf("Bad db ref on object %d\n", obj);
return (0);
}
}
if (required & REQ_FLAG) {
if (get_int_elt(obj, FLAGS, &flags) == -1) {
printf("Bad db ref on object %d\n", obj);
return (0);
}
}
if (required & REQ_OWNER) {
if (get_int_elt(obj, OWNER, &owner) == -1) {
printf("Bad db ref on object %d\n", obj);
return (0);
}
}
if (required & REQ_TIME) {
if (get_int_elt(obj, TIMESTAMP, ×tamp) == -1) {
printf("Bad db ref on object %d\n", obj);
return (0);
}
}
sp = 0;
while (exp->type != STOP) {
switch (exp->type) {
case OR:
op1 = eval_stack[--sp];
op2 = eval_stack[--sp];
eval_stack[sp++] = op1 || op2;
break;
case AND:
op1 = eval_stack[--sp];
op2 = eval_stack[--sp];
eval_stack[sp++] = op1 && op2;
break;
case NOT:
op1 = eval_stack[--sp];
eval_stack[sp++] = !op1;
break;
case DBM_NUMBER:
eval_stack[sp++] = (obj == (exp->data).number);
break;
case DBM_FLAG:
eval_stack[sp++] = (flags & (exp->data).flag);
break;
case DBM_OWNER:
eval_stack[sp++] = (owner == (exp->data).owner);
break;
case DBM_NAME:
if (strstr_CI(name, ((exp->data).name)) != NULL)
eval_stack[sp++] = 1;
else
eval_stack[sp++] = 0;
break;
case DBM_TIME:
if ((exp->data).time < 0) { /* Unused < X minutes */
eval_stack[sp++] = ((currenttime - timestamp)
< -((exp->data).time));
} else { /* Unused > X minutes */
eval_stack[sp++] = ((currenttime - timestamp)
> (exp->data).time);
}
break;
case DBM_TYPE:
eval_stack[sp++] =
((flags & TYPE_MASK) == (exp->data).flag);
break;
}
exp++;
}
return (eval_stack[--sp]);
}
dump_expr(ex)
atom *ex;
{
while (ex->type != STOP) {
switch (ex->type) {
case AND:
printf("& ");
break;
case OR:
printf("| ");
break;
case NOT:
printf("!");
break;
case DBM_NUMBER:
printf("#%d ", (ex->data).number);
break;
case DBM_FLAG:
printf("flag=");
switch ((ex->data).flag) {
case GOD:
putchar('G');
break;
case WIZARD:
putchar('W');
break;
case ROBOT:
putchar('R');
break;
case STICKY:
putchar('S');
break;
case DARK:
putchar('D');
break;
case LINK_OK:
putchar('L');
break;
case HAVEN:
putchar('H');
break;
case JUMP_OK:
putchar('J');
break;
case ABODE:
putchar('A');
break;
}
putchar(' ');
break;
case DBM_TYPE:
printf("type=");
switch ((ex->data).flag) {
case TYP_ROOM:
putchar('R');
break;
case TYP_THING:
putchar('T');
break;
case TYP_EXIT:
putchar('E');
break;
case TYP_PLAYER:
putchar('P');
break;
}
putchar(' ');
break;
case DBM_TIME:
printf("unused %d", (ex->data).time);
break;
case DBM_OWNER:
printf("owner=%d ", (ex->data).owner);
break;
case DBM_NAME:
printf("name=%s ", (ex->data).name);
break;
}
ex++;
}
putchar('\n');
}
/*
* Read in a (potentially long) command line.
*/
get_cmd(buff)
char *buff;
{
char *p = buff;
char *q;
while (1) {
gets(p);
q = p;
while (*q)
q++; /* Find EOLN */
q--;
while (isspace(*q))
q--; /* Back up to 1st non-space */
if (*q == '\\') {
p = q;
} else {
q[1] = '\0';
break;
}
}
}
/*
* We need to emulate some support routines for the DB library that the MUD
* normally provides. These are them:
*
*/
/*
* Converts ints to strings.
*
*/
char *
ty_itoa(p, i)
char *p;
int i;
{
char *ty_itoa_prim();
if (i < 0) {
i = -i;
*p++ = '-';
} else if (i == 0) {
*p++ = '0';
return (p);
}
return (ty_itoa_prim(p, i));
}
/* recursively does it to it. Hee! Russ would love me. */
char *
ty_itoa_prim(p, i)
char *p;
int i;
{
if (i == 0) {
return (p);
} else {
p = ty_itoa_prim(p, i / 10);
*p++ = (char) (i % 10) + '0';
return (p);
}
}
char *
ty_malloc(n, p)
int n;
char *p;
{
char *foo;
foo = malloc((size_t) n);
if (foo == NULL) {
fatal(p, "Out of memory");
}
return (foo);
}
void ty_free(p)
char *p;
{
if (p && *p)
free(p);
}
/*
* Write a timestamp on an object. In minutes since Jan 1 1970
*/
void stamp(obj)
{
struct timeval foo;
(void) gettimeofday(&foo, (struct timezone *) 0);
if (set_int_elt(obj, TIMESTAMP, (int) (foo.tv_sec / 60)) == -1) {
warning("timestamp", "failed write to object");
}
}