#include "copyright.h" #include "config.h" #include <stdio.h> #include <ctype.h> #include "teeny.h" #include "db.h" /* * Increments a TeenyMud db, using the same methods that db/textdump.c * uses. * * Dump format: * * Preamble of lines starting with !'s. These are comments. * * A line starting with %, and followed by a number. This number is the total * number of objects contained in the dump (including garbage) * * A line starting with ~, and followed by a number. This number is the version * number of the database. TeenyMUD 1.2 can read any version number from 0 to * 5, ignoring fields that the server does not support. A summary of version * numbers supported by this release: 0 -- original, unmodified TeenyMUD 1.0 * or 1.1 textdump. 1 -- "standard" TeenyMUD 1.2 dump. 2 -- includes the * TIMESTAMP field in the dump. 3 -- includes the DROP/ODROP fields. 4 -- * contains both TIMESTAMP and DROP/ODROP. 5 -- used to mark a TeenyMUD-C * dump. * * A sequence of objects. Real objects start with a line like #127 to indicate * object number, and are followed by a sequence of lines, one per field, * describing the object data. Garbage objects are coded by a single line * like @1283. * * A line at the end **** END OF DUMP **** */ int Garbage = 0; extern char *malloc(); extern void free(); #ifdef TIMESTAMPS void stamp(int, FILE *); #endif int Increment = 0; int total_objects = 0; char *prog; static void getstring(); static void skip_line(); static void getnumber(); static void getlock(); static void putnumber(); static void putstring(); static void putlock(); static int convert_flags(); /* figure out what version we are */ #ifdef TIMESTAMPS #ifdef DROP_FIELDS static int dump_version = 4; /* TIMESTAMP, DROP, and ODROP */ #else static int dump_version = 2; /* TIMESTAMP */ #endif /* DROP_FIELDS */ #else #ifdef DROP_FIELDS static int dump_version = 3; /* DROP and ODROP */ #else static int dump_version = 1; /* nothing extra */ #endif /* DROP_FIELDS */ #endif /* TIMESTAMPS */ convert_file(in, out) FILE *in; FILE *out; { char work[BUFFSIZ + 16]; int objcount, objnum, i; int done; int flags, creatednum, objflags; int read_version = 0; extern int slack; /* Read and ignore the preamble */ do { if (fgets(work, BUFFSIZ + 16, in) == NULL) { warning("text_load", "bad preamble"); goto fail; } } while (work[0] == '!'); if (work[0] != '%') { warning("text_load", "could not get object count"); goto fail; } /* Do it to it. Loop away sucking in objects and building them */ done = 0; for (i = 0; !done; i++) { if (fgets(work, BUFFSIZ + 16, in) == NULL) goto fail; switch (work[0]) { case '~': /* version number */ read_version = atoi(work + 1); if (read_version > 5) { warning("text_load", "input DB version not supported"); goto fail; } i--; /* a kludge to fix the for loop */ break; case '#': /* Actual object */ objnum = atoi(work + 1); if (objnum != i) { warning("text_load", "input DB is out of synch"); goto fail; } if (fgets(work, BUFFSIZ + 16, in) == NULL) goto fail; flags = atoi(work); if (read_version == 5) flags = convert_flags(flags); /* convert 'em */ fprintf(out, "#%d\n%d\n", objnum + Increment, flags); /* Now suck in all the data elements */ getstring(i, NAME, in, out); getnumber(i, NEXT, in, out); getnumber(i, SITE, in, out); getnumber(i, LOC, in, out); getnumber(i, HOME, in, out); getnumber(i, OWNER, in, out); getnumber(i, CONTENTS, in, out); getnumber(i, EXITS, in, out); if ((read_version == 2) || (read_version > 3)) { #ifdef TIMESTAMPS getnumber(i, TIMESTAMP, in, out); #else skip_line(in); #endif /* TIMESTAMPS */ } else { #ifdef TIMESTAMPS stamp(i, out); #endif /* TIMESTAMPS */ } getlock(i, in, out); getstring(i, SUC, in, out); getstring(i, OSUC, in, out); getstring(i, FAIL, in, out); getstring(i, OFAIL, in, out); if (read_version > 2) { #ifdef DROP_FIELDS getstring(i, DROP, in, out); getstring(i, ODROP, in, out); #else skip_line(in); skip_line(in); #endif /* DROP_FIELDS */ } else { #ifdef DROP_FIELDS fprintf(out, "\n\n"); #endif /* DROP_FIELDS */ } if (read_version == 5) { skip_line(in); skip_line(in); } getstring(i, DESC, in, out); getstring(i, GENDER, in, out); if (read_version == 5) { skip_line(in); } break; case '@': /* Garbage object */ objnum = atoi(work + 1); if (objnum != i) { warning("text_load", "input DB is out of synch"); goto fail; } fprintf(out, "@%d\n", objnum + Increment); break; case '*': /* End of file */ done = 1; break; } } /* total_objects is already correct */ (void) fclose(in); return (0); fail: (void) fclose(in); warning("text_load", "load failed"); return (-1); } /* * Generic routines for reading junk in to an object. * */ static void getstring(obj, code, f, outf) int obj; int code; FILE *f; FILE *outf; { char work[BUFFSIZ + 16]; char *p; int ret; if (fgets(work, BUFFSIZ + 16, f) == NULL) { warning("get_string", "unexpected EOF in text_load"); return; } fputs(work, outf); /* for (p = work; *p != '\n' && *p; p++); *p = '\0'; if (p == work) { fprintf(out,"\n"); } else { fprintf(out,"%s\n",work); } */ } static void skip_line(f) FILE *f; { char temp[BUFFSIZ + 16]; if (fgets(temp, BUFFSIZ + 16, f) == NULL) { warning("skip_line", "unexpected EOF in text_load"); return; } } static void getnumber(obj, code, f, outf) int obj; int code; FILE *f; FILE *outf; { char work[BUFFSIZ + 16]; int num; if (fgets(work, BUFFSIZ + 16, f) == NULL) { warning("getnumber", "unexpected EOF in text_load"); return; } if ((!isdigit(work[0])) && !(work[0] == '-' && isdigit(work[1]))) { warning("getnumber", "bad integer read in text_load"); return; } num = atoi(work); if(code != SITE && code != TIMESTAMP) { if(num >= 0) num += Increment; } fprintf(outf,"%d\n",num); } static void getlock(obj, f, outf) int obj; FILE *f; FILE *outf; { char work[BUFFSIZ + 16], *p; int size, *lock, i; if (fgets(work, BUFFSIZ + 16, f) == NULL) { warning("get_string", "unexpected EOF in text_load"); return; } /* OK. Locks are slightly complex. We malloc memory HERE for it */ if (work[0] == '\n') { fputs(work, outf); return; } size = atoi(work); if (size <= 0) { warning("getlock", "bad lock field in text database"); fprintf(outf,"\n"); return; } lock = (int *) ty_malloc(sizeof(int) * (size + 1), "getlock"); lock[0] = size; p = work; for (i = 1; i <= size; i++) { while (!isspace(*p) && *p) p++; while (isspace(*p)) p++; if (*p == '\0') { warning("getlock", "bad lock field in text database"); return; } lock[i] = atoi(p); if(lock[i] >= 0) lock[i] += Increment; } putlock(lock, outf); } static void putlock(lock, f) int *lock; FILE *f; { int count, i, space; char work[BUFFSIZ], *p, *q; if (lock == NULL || lock[0] == 0) { fputs("\n", f); return; } space = BUFFSIZ; count = lock[0]; /* How many FOLLOW */ p = work; p = ty_itoa(p, count); *p++ = ' '; space -= p - work; for (i = 1; count > 0 && space > 8; count--, i++) { q = p; p = ty_itoa(p, lock[i]); *p++ = ' '; space -= p - q; } p--; *p++ = '\n'; *p = '\0'; fputs(work, f); } /* * the following defines and function are for converting TeenyMUD-C style * flags into TeenyMUD 1.2 style flags. */ #define O_STICKY 0x0004 #define O_WIZARD 0x0008 #define O_TEMPLE 0x0010 #define O_LINK_OK 0x0020 #define O_DARK 0x0040 #define O_GOD 0x0080 #define O_HAVEN 0x0100 #define O_JUMP_OK 0x0200 #define O_ABODE 0x0400 static int convert_flags(oldflags) int oldflags; { int newflags; newflags = (oldflags & TYPE_MASK); if (oldflags & O_STICKY) newflags |= STICKY; if (oldflags & O_WIZARD) newflags |= WIZARD; if (oldflags & O_TEMPLE) newflags |= TEMPLE; if (oldflags & O_LINK_OK) newflags |= LINK_OK; if (oldflags & O_DARK) newflags |= DARK; if (oldflags & O_GOD) newflags |= WIZARD; if (oldflags & O_HAVEN) newflags |= HAVEN; if (oldflags & O_JUMP_OK) newflags |= JUMP_OK; if (oldflags & O_ABODE) newflags |= ABODE; newflags |= (oldflags & INTERNAL_FLAGS); return newflags; } void main(int argc, char **argv) { FILE *in; FILE *out; FILE *temp; char temp_path[80]; char work[BUFFSIZ + 16]; prog = argv[0]; if (argc < 3 || argc > 5) { fprintf(stderr, "Usage: %s <input db> <output db> [<temp db>] [<#>]\n", prog); exit(-1); } if (!strcmp(argv[1], "-")) { in = stdin; } else { if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "%s: couldn't open %s.\n", prog, argv[1]); exit(-1); } } if ((out = fopen(argv[2], "w")) == NULL) { fprintf(stderr, "%s: couldn't create %s.\n", prog, argv[2]); exit(-1); } if (argc > 3) { if (strlen(argv[3]) > 80) { fprintf(stderr, "%s: %s - path too long.\n", prog, argv[3]); exit(-1); } strcpy(temp_path, argv[3]); } else { sprintf(temp_path, "/tmp/cnvt%d", getpid()); } if ((temp = fopen(temp_path, "w")) == NULL) { fprintf(stderr, "%s: couldn't create %s.\n", prog, temp_path); exit(-1); } if (argc == 5) Increment = atoi(argv[4]); if (convert_file(in, temp) == -1) { fprintf(stderr, "%s: conversion failed.\n", prog); exit(-1); } fclose(temp); if (Increment > 0) { fprintf(stderr, "%s: unfinished db left in %s, offset %d objects.\n", prog, temp_path, Increment); exit(1); } #ifdef TIMESTAMPS fprintf(out, "!\n! TinyMUD -> TeenyMUD converter dump\n!\n%%%d\n~2\n", total_objects); #else /* TIMESTAMPS */ fprintf(out, "!\n! TinyMUD -> TeenyMUD converter dump\n!\n%%%d\n~1\n", total_objects); #endif /* TIMESTAMPS */ fflush(out); if ((temp = fopen(temp_path, "r")) == NULL) { fprintf(stderr, "%s: couldn't reopen %s for read.\n", prog, temp_path); exit(-1); } while (fgets(work, BUFFSIZ + 16, temp) != NULL) { fputs(work, out); } fflush(out); fputs("*** End of converter dump ***\n", out); fflush(out); fclose(out); fclose(temp); unlink(temp_path); exit(0); } #ifdef TIMESTAMPS void stamp(obj,outf) int obj; FILE *outf; { struct timeval foo; (void) gettimeofday(&foo, (struct timezone *) 0); fprintf(outf, "%d\n", (int) (foo.tv_sec / 60)); } #endif /* * Reliable memory allocation. */ char * ty_malloc(n, util) int n; char *util; /* Identifies the calling routine */ { char *p; extern char *malloc(); if ((p = (char *) malloc((size_t) n)) == NULL) { fatal(util, "memory allocation failed"); } return (p); } /* * Reliable free(), which does NULL OK. */ void ty_free(p) char *p; { if (p == NULL) { return; /* Ok */ } free(p); } /* * 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); } } warning(str1, str2) char *str1; char *str2; { fprintf(stderr,"%s(warning): %s\n", str1, str2); }