/* 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"); } }