/* select.c */
#include "copyright.h"
#include "config.h"
#include <stdio.h>
#ifdef STRING_H
#include <string.h>
#else
#include <strings.h>
#endif /* STRING_H */
#include <ctype.h>
#include "teeny.h"
#include "dbm.h"
/*
* Implements the select command for the dbm.
*
*/
static char toocomplex[] = "Expression too complex.\n";
int stack[64]; /* We only stack operators, so don't need
* full atoms here. */
char *get_tok();
int sel_handle(str, ex, required)
char *str;
atom *ex;
int *required;
{
int wp, sp;
int tok;
int bad_ex;
char *p, foo;
sp = 0;
wp = 0;
bad_ex = 0;
*required = 0;
ex[0].type = STOP;
do {
str = get_tok(str, &tok);
switch (tok) {
case BADTOK:
printf("Bad token.\n");
bad_ex = 1;
break;
case OPEN:
if (sp < 63) {
stack[sp++] = OPEN;
} else {
bad_ex = 1;
printf(toocomplex);
break;
}
break;
case CLOSE:
while (sp > 0 && stack[sp - 1] != OPEN && wp < (MAXEXPR - 1)) {
ex[wp++].type = stack[--sp];
}
if (sp == 0 || stack[sp - 1] != OPEN) {
bad_ex = 1;
printf("Too complex, or unbalanced parens.\n");
break;
}
sp--;
break;
case AND:
while (sp > 0 && stack[sp - 1] == NOT && wp < (MAXEXPR - 1)) {
ex[wp++].type = stack[--sp];
}
if (wp == (MAXEXPR - 1)) {
printf(toocomplex);
bad_ex = 1;
break;
}
if (sp < 63) {
stack[sp++] = AND;
} else {
printf(toocomplex);
bad_ex = 1;
break;
}
break;
case OR:
while (sp > 0 && (stack[sp - 1] == NOT
|| stack[sp - 1] == AND) && wp < (MAXEXPR - 1)) {
ex[wp++].type = stack[--sp];
}
if (wp == (MAXEXPR - 1)) {
printf(toocomplex);
bad_ex = 1;
break;
}
if (sp < 63) {
stack[sp++] = OR;
} else {
printf(toocomplex);
bad_ex = 1;
break;
}
break;
case NOT:
if (sp < 63) {
stack[sp++] = NOT;
} else {
printf(toocomplex);
bad_ex = 1;
break;
}
break;
case STOP:
while (sp > 0 && wp < (MAXEXPR - 1)) {
if (stack[sp - 1] != AND && stack[sp - 1] != OR
&& stack[sp - 1] != NOT) {
bad_ex = 1;
break;
}
ex[wp++].type = stack[--sp];
}
if (wp == (MAXEXPR - 1)) {
printf(toocomplex);
bad_ex = 1;
break;
}
ex[wp++].type = STOP;
break;
/* Cope with the various atomic formulae now */
/* They all just get written into the expression. */
case DBM_NAME:
ex[wp].type = tok;
*required |= REQ_NAME;
while (isspace(*str))
str++;
if (*str != '=') {
printf("Bad name specifier.\n");
bad_ex = 1;
break;
}
str++;
while (isspace(*str))
str++;
p = str;
if (*str == '\"') { /* Quoted string */
str++;
p++; /* Skip the " */
while (*str != '\"' && *str)
str++;
} else { /* Single word */
while (!isspace(*str) && *str)
str++;
}
foo = *str;
*str = '\0';
ex[wp].data.name = ty_malloc(strlen(p) + 1, "sel_handle");
strcpy(ex[wp].data.name, p);
*str = foo;
if (*str == '\"')
str++; /* Skip trailing " */
wp++;
break;
case DBM_TIME:
ex[wp].type = tok;
*required |= REQ_TIME;
while (isspace(*str))
str++;
if (*str != '>' && *str != '<') {
printf("Bad timestamp specifier.\n");
bad_ex = 1;
break;
}
foo = *str++;
while (isspace(*str))
str++;
if (!isdigit(*str)) {
printf("Bad time specifier.\n");
bad_ex = 1;
break;
}
ex[wp].data.time = atoi(str);
while (isdigit(*str))
str++;
switch (*str++) {
case 'd':
ex[wp].data.time *= (24 * 60);
break;
case 'h':
ex[wp].data.time *= 60;
break;
case 'm':
/* Leave it be. */
break;
default:
str--;
printf("Bad time specifier.\n");
bad_ex = 1;
break;
}
if (!bad_ex) {
/* We negate this to indicate unused < X min */
if (foo == '<')
ex[wp].data.time = -(ex[wp].data.time);
wp++;
}
break;
case DBM_OWNER:
ex[wp].type = tok;
*required |= REQ_OWNER;
while (isspace(*str))
str++;
if (*str != '=') {
printf("Bad owner specifier.\n");
bad_ex = 1;
break;
}
str++;
while (isspace(*str))
str++;
if (*str++ != '#' || !isdigit(*str)) {
printf("Bad owner specifier.\n");
bad_ex = 1;
break;
}
ex[wp++].data.owner = atoi(str);
while (isdigit(*str))
str++;
break;
case DBM_NUMBER:
ex[wp].type = tok;
*required |= REQ_NUMBER;
if (!isdigit(*str)) {
printf("bad object number\n");
bad_ex = 1;
break;
}
ex[wp++].data.number = atoi(str);
while (isdigit(*str))
str++;
break;
case DBM_TYPE:
case DBM_FLAG:
ex[wp].type = tok;
*required |= REQ_FLAG;
while (isspace(*str))
str++;
if (*str != '=') {
printf("Bad type/flag specifier.\n");
bad_ex = 1;
break;
}
str++;
while (isspace(*str))
str++;
switch (*str) {
case 'P':
ex[wp++].data.flag = TYP_PLAYER;
break;
case 'T':
ex[wp++].data.flag = TYP_THING;
break;
case 'E':
ex[wp++].data.flag = TYP_EXIT;
break;
case 'R':
ex[wp++].data.flag = TYP_ROOM;
break;
case 'W':
ex[wp++].data.flag = WIZARD;
break;
case 'G':
ex[wp++].data.flag = GOD;
break;
case 'r': /* robot */
ex[wp++].data.flag = ROBOT;
break;
case 'S':
ex[wp++].data.flag = STICKY;
break;
case 'D':
ex[wp++].data.flag = DARK;
break;
case 'L':
ex[wp++].data.flag = LINK_OK;
break;
case 'H':
ex[wp++].data.flag = HAVEN;
break;
case 'J':
ex[wp++].data.flag = JUMP_OK;
break;
case 'A':
ex[wp++].data.flag = ABODE;
break;
}
str++; /* Skip the flag */
break;
}
} while (tok != STOP && !bad_ex);
if (bad_ex) {
printf("Bad expression.\n");
return (-2);
} else {
return (0);
}
}
/*
* Snarf the next token out of the string, return a pointer to the next
* character after it, and stuff the token into the provided int.
*
*/
char *
get_tok(p, tok)
char *p;
int *tok;
{
char foo, *q;
*tok = BADTOK;
while (isspace(*p))
p++;
switch (*p) {
case '\0':
*tok = STOP;
break;
case '&':
*tok = AND;
break;
case '|':
*tok = OR;
break;
case '!':
*tok = NOT;
break;
case '(':
*tok = OPEN;
break;
case ')':
*tok = CLOSE;
break;
case '#':
*tok = DBM_NUMBER;
break;
}
/* 'Twasn't one of the one char jobs. */
if (*tok == BADTOK) { /* If no luck above */
q = p;
while (isalpha(*p))
p++;
foo = *p;
*p = '\0';
if (strcmp("name", q) == 0) {
*tok = DBM_NAME;
} else if (strcmp("flag", q) == 0) {
*tok = DBM_FLAG;
} else if (strcmp("unused", q) == 0) {
*tok = DBM_TIME;
} else if (strcmp("owner", q) == 0) {
*tok = DBM_OWNER;
} else if (strcmp("type", q) == 0) {
*tok = DBM_TYPE;
}
*p = foo;
} else { /* Just skip over the one character */
p++;
}
return (p);
}