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