#include <stdio.h>
#include <ctype.h>
#include "teeny.h"
#define O_TYPE_ROOM 0x0
#define O_TYPE_THING 0x1
#define O_TYPE_EXIT 0x2
#define O_TYPE_PLAYER 0x3
#define O_TYPE_MASK 0x7
#define O_ANTILOCK 0x8
#define O_WIZARD 0x10
#define O_LINK_OK 0x20
#define O_DARK 0x40
#define O_TEMPLE 0x80
#define O_STICKY 0x100
#define O_BUILDER 0x200
#define O_HAVEN 0x400
#define O_ABODE 0x800
#define O_ROBOT 0x4000
#define O_GOD 0x40000
#define O_GENDER_MASK 0x3000
#define O_GENDER_SHIFT 12
#define O_GENDER_UNASSIGNED 0x0
#define O_GENDER_NEUTER 0x1
#define O_GENDER_FEMALE 0x2
#define O_GENDER_MALE 0x3
#ifdef GARBAGE
#define O_TYPE_GARBAGE 0x6
int Garbage = 0;
#endif /* GARBAGE */
extern char *malloc();
extern void free();
char Name[BUFFSIZ + 16];
char Password[BUFFSIZ + 16];
char Description[BUFFSIZ + 16];
char Fail[BUFFSIZ + 16];
char Success[BUFFSIZ + 16];
char Ofail[BUFFSIZ + 16];
char Osuccess[BUFFSIZ + 16];
char Gender[BUFFSIZ + 16];
char Lockbuff[BUFFSIZ + 16];
int *Lock = NULL;
int Flags;
int Next;
int Pennies;
int Location;
int Exits;
int Owner;
int Contents;
int Home;
#ifdef TIMESTAMPS
int Timestamp;
#endif /* TIMESTAMPS */
int Increment = 0;
int total_objects = 0;
char *prog;
int convert_file(in, out)
FILE *in;
FILE *out;
{
int i, objnum;
int done = 0;
char work[BUFFSIZ + 16];
for (i = 0; !done; i++) {
if (fgets(work, BUFFSIZ + 16, in) == NULL) {
fprintf(stderr, "%s: unexpected EOF in input db.\n", prog);
goto fail;
}
switch (work[0]) {
case '#':
objnum = atoi(work + 1);
/*
* if(objnum != i){ fprintf(stderr, "%s: input and output dbs are out
* of synch.\n", prog); goto fail; }
*/
if (fgets(Name, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(Description, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Location = atoi(work);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Contents = atoi(work);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Exits = atoi(work);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Next = atoi(work);
if (fgets(Lockbuff, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(Fail, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(Success, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(Ofail, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(Osuccess, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Owner = atoi(work);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Pennies = atoi(work);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Flags = atoi(work);
if (fgets(Password, BUFFSIZ + 16, in) == NULL)
goto fail;
#ifdef TIMESTAMPS
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
Timestamp = (int) (atol(work) / 60);
if (fgets(work, BUFFSIZ + 16, in) == NULL)
goto fail;
#endif /* TIMESTAMP */
if (convert_object() == -1) {
fprintf(stderr, "%s: failed to convert object #%d.\n", prog, i);
goto fail;
}
if (write_object(objnum, out) == -1) {
fprintf(stderr, "%s: failed to write object #%d.\n", prog, i);
goto fail;
}
break;
case '*':
done = 1;
break;
default:
fprintf(stderr, "%s: input db is totally fucked.\n", prog);
goto fail;
}
}
total_objects = i + 1;
fclose(in);
return 1;
fail:
fclose(in);
return -1;
}
int convert_object()
{
int newflags;
/* convert the flags first thing */
switch (Flags & O_TYPE_MASK) {
case O_TYPE_THING:
newflags = TYP_THING;
break;
case O_TYPE_PLAYER:
newflags = TYP_PLAYER;
break;
case O_TYPE_EXIT:
newflags = TYP_EXIT;
break;
#ifdef GARBAGE
case O_TYPE_GARBAGE:
Garbage = 1;
return 1;
#endif /* GARBAGE */
default:
newflags = TYP_ROOM;
}
if ((Flags & O_WIZARD) || (Flags & O_GOD))
newflags |= WIZARD;
if (Flags & O_LINK_OK)
newflags |= LINK_OK;
if (Flags & O_DARK)
newflags |= DARK;
if (Flags & O_TEMPLE)
newflags |= TEMPLE;
if (Flags & O_STICKY)
newflags |= STICKY;
if (Flags & O_HAVEN) {
if ((newflags & TYPE_MASK) == TYP_PLAYER)
newflags |= STICKY;
else
newflags |= HAVEN;
}
if (Flags & O_ABODE)
newflags |= ABODE;
if ((Flags & O_ROBOT) && ((newflags & TYPE_MASK) == TYP_PLAYER))
newflags |= TEMPLE;
if (Flags & O_BUILDER)
newflags |= BUILDER;
if ((((Flags & O_GENDER_MASK) >> O_GENDER_SHIFT) != O_GENDER_UNASSIGNED) &&
((newflags & TYPE_MASK) == TYP_PLAYER)) {
switch ((Flags & O_GENDER_MASK) >> O_GENDER_SHIFT) {
case O_GENDER_NEUTER:
strcpy(Gender, "neuter\n");
break;
case O_GENDER_FEMALE:
strcpy(Gender, "female\n");
break;
case O_GENDER_MALE:
strcpy(Gender, "male\n");
break;
default:
strcpy(Gender, "\n");
}
} else
strcpy(Gender, "\n");
if ((newflags & TYPE_MASK) == TYP_PLAYER) {
char *p;
for (p = Name; *p && *p != '\n'; p++);
*p = '\0';
if (Password[0] != '\n') {
strcat(Name, " ");
strcat(Name, Password);
} else {
strcat(Name, " null\n");
}
}
if (Lockbuff[0] != '\n') {
char *p;
for (p = Lockbuff; *p && *p != '\n'; p++);
*p = '\0';
} else
Lockbuff[0] = '\0';
if (!strcmp(Lockbuff, "-1"))
Lockbuff[0] = '\0';
if ((Flags & O_ANTILOCK) && Lockbuff[0] != '\0') {
char temp[BUFFSIZ + 16];
strcpy(temp, "!(");
strcat(temp, Lockbuff);
strcat(temp, ")");
strcpy(Lockbuff, temp);
}
if (Lockbuff[0] != '\0') {
if ((Lock = bool_parse(Lockbuff)) == NULL)
return -1;
}
if ((newflags & TYPE_MASK) == TYP_EXIT) {
Home = Location;
Location = -1; /* fucked */
} else {
if ((newflags & TYPE_MASK) != TYP_ROOM) {
Home = Exits;
Exits = -1; /* no exits */
} else {
Home = Location;
Location = 0;
}
}
Flags = newflags;
return 1;
}
int write_object(objnum, out)
int objnum;
FILE *out;
{
if (Increment > 0) {
objnum += Increment;
if (Location > 0)
Location += Increment;
Owner += Increment;
if (Next > 0)
Next += Increment;
if (Exits > 0)
Exits += Increment;
if (Contents > 0)
Contents += Increment;
if (Home > 0)
Home += Increment;
}
#ifdef GARBAGE
if (Garbage) {
fprintf(out, "@%d\n", objnum);
fflush(out);
Garbage = 0;
return 1;
}
#endif /* GARBAGE */
fprintf(out, "#%d\n%d\n", objnum, Flags);
fputs(Name, out);
fprintf(out, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n", Next, Pennies, Location, Home,
Owner, Contents, Exits);
#ifdef TIMESTAMPS
fprintf(out, "%d\n", Timestamp);
#endif /* TIMESTAMPS */
#ifdef KLUDGE
fprintf(out, "%d\n", (int) (time(0) / 60));
#endif /* KLUDGE */
if (Lock != NULL)
putlock(Lock, out);
else
fputs("\n", out);
fputs(Success, out);
fputs(Osuccess, out);
fputs(Fail, out);
fputs(Ofail, out);
fputs(Description, out);
fputs(Gender, out);
fflush(out);
if (Lock != NULL) {
free((int *) Lock);
Lock = NULL;
}
return 1;
}
void main(argc, argv)
int argc;
char **argv;
{
FILE *in;
FILE *out;
FILE *temp;
char temp_path[80];
char work[BUFFSIZ + 16];
#ifdef PIPE
char out_cmmd[BUFSIZ];
#endif /* PIPE */
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);
}
}
#ifdef PIPE
sprintf(out_cmmd, "compress > %s", argv[2]);
if ((out = popen(out_cmmd, "w")) == NULL) {
fprintf(stderr, "%s: couldn't execute %s.\n", prog, out_cmmd);
exit(-1);
}
#else /* PIPE */
if ((out = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "%s: couldn't create %s.\n", prog, argv[2]);
exit(-1);
}
#endif /* PIPE */
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);
#ifdef PIPE
pclose(out);
#else /* PIPE */
fclose(out);
#endif /* PIPE */
fclose(temp);
unlink(temp_path);
exit(0);
}
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);
}
/* Opcodes for our little Boolean expression evaluator. */
#define STOP -1
#define AND -2
#define OR -3
#define NOT -4
#define OPEN -5
#define CLOSE -6
#define BADREF -7
char *get_tok();
int stack[64]; /* Expressions can't be too big. */
static int work[256];
/*
* We use these structs, an array of them, to build parse trees from our
* internal RPN locks so we can write them out in infix.
*
*/
struct tree {
int dat;
short left, right; /* Array offsets */
};
/*
* Parses a boolean expression, stuffs it into a hunk of memory, and returns
* a pointer to said hunk. Returns NULL if it can't cope.
*
*/
int *
bool_parse(str)
char *str;
{
int wp, sp;
int tok, *thelock;
sp = 0;
wp = 1;
do {
str = get_tok(str, &tok);
if (tok == BADREF) {
fprintf(stderr, "%s: bad lock.\n", prog);
return (NULL);
}
switch (tok) {
case OPEN:
if (sp < 63) {
stack[sp++] = OPEN;
} else {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
break;
case CLOSE:
while (sp > 0 && stack[sp - 1] != OPEN && wp < 255) {
work[wp++] = stack[--sp];
}
if (sp == 0 || stack[sp - 1] != OPEN) {
fprintf(stderr,
"%s: lock to complex, or unbalanced parens.\n",
prog);
return (NULL);
}
sp--;
break;
case AND:
while (sp > 0 && stack[sp - 1] == NOT && wp < 255) {
work[wp++] = stack[--sp];
}
if (wp == 255) {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
if (sp < 63) {
stack[sp++] = AND;
} else {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
break;
case OR:
while (sp > 0 && (stack[sp - 1] == NOT
|| stack[sp - 1] == AND) && wp < 255) {
work[wp++] = stack[--sp];
}
if (wp == 255) {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
if (sp < 63) {
stack[sp++] = OR;
} else {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
break;
case NOT:
if (sp < 63) {
stack[sp++] = NOT;
} else {
fprintf(stderr, "%s: lock too complex.\n");
return (NULL);
}
break;
case STOP:
while (sp > 0 && wp < 255) {
if (stack[sp - 1] != AND && stack[sp - 1] != OR
&& stack[sp - 1] != NOT) {
fprintf(stderr, "%s: bad lock.\n", prog);
return (NULL);
}
work[wp++] = stack[--sp];
}
if (wp == 255) {
fprintf(stderr, "%s: lock too complex.\n", prog);
return (NULL);
}
work[wp++] = STOP;
break;
default:
work[wp++] = tok;
break;
}
} while (tok != STOP);
/* Stow it away somewhere. */
thelock = (int *) malloc(sizeof(int) * wp);
thelock[0] = --wp;
while (wp > 0) {
thelock[wp] = work[wp];
wp--;
}
return (thelock);
}
/*
* Grabs the next token out a string, and returns a poointer to the next
* thing in the string.
*
*/
char *
get_tok(p, tok)
char *p;
int *tok;
{
char *q, ch;
int obj;
/* Skip white-boy space, Marcus-like */
while (isspace(*p) && *p)
p++;
switch (*p) {
case '&':
*tok = AND;
break;
case '|':
*tok = OR;
break;
case '!':
*tok = NOT;
break;
case '(':
*tok = OPEN;
break;
case ')':
*tok = CLOSE;
break;
case '\0':
*tok = STOP;
break;
default:
/* Snarf out an object name */
q = p;
while (*p != '&' && *p != '|' && *p != '!' && *p != ')' && *p) {
p++;
}
p--;
while (isspace(*p))
p--;
ch = p[1];
p[1] = '\0';
obj = atoi(q);
if (Increment > 0)
obj += Increment;
p[1] = ch;
if (obj < 0) {
*tok = BADREF;
} else {
*tok = obj;
}
}
/* p points at the last char of the token. */
p++;
return (p);
}
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);
}
}