#include <stdio.h> #include <strings.h> #include <ctype.h> #include "teeny.h" #include "dbm.h" /* Copyright(C) 1990, Andrew Molitor, All Rights Reserved. This software may be freely used, modified, and redistributed, as long as this copyright message is left intact, and this software is not used to develop any commercial product, or used in any product that is provided on a pay-for-use basis. No warranties whatsoever. This is not guaranteed to compile, nor, in the event that it does compile to binaries, are these binaries guaranteed to perform any function whatsoever. */ /* 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 */ 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; wp++; break; #ifdef TIMESTAMPS 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; #endif 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 'S': ex[wp++].data.flag = STICKY; break; case 'D': ex[wp++].data.flag = DARK; break; case 'L': ex[wp++].data.flag = LINK_OK; 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; #ifdef TIMESTAMPS } else if(strcmp("unused",q) == 0){ *tok = DBM_TIME; #endif } 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); }