#include "copyright.h" #include "config.h" #include <ctype.h> #include "db.h" #include "match.h" #include "externs.h" #include "params.h" #include "interface.h" /* Lachesis note on the routines in this package: * eval_booexp does just evaluation. * * parse_boolexp makes potentially recursive calls to several different * subroutines --- * parse_boolexp_F * This routine does the leaf level parsing and the NOT. * parse_boolexp_E * This routine does the ORs. * parse_boolexp_T * This routine does the ANDs. * * Because property expressions are leaf level expressions, I have only * touched eval_boolexp_F, asking it to call my additional parse_boolprop() * routine. */ int eval_boolexp(dbref player, boolexp *b, dbref thing) { frame *fr; int result; if(b == TRUE_BOOLEXP) return 1; else { switch(b->type) { case BOOLEXP_AND: return (eval_boolexp(player, b->sub1, thing) && eval_boolexp(player, b->sub2, thing)); case BOOLEXP_OR: return (eval_boolexp(player, b->sub1, thing) || eval_boolexp(player, b->sub2, thing)); case BOOLEXP_NOT: return !eval_boolexp(player, b->sub1, thing); case BOOLEXP_CONST: if (Typeof(b ->thing) == TYPE_PROGRAM) { fr = new_frame(player, b->thing, thing, DBFETCH(player)->location, 1); result = run_frame(fr, 1); if (fr && (fr->status != STATUS_SLEEP)) free_frame(fr); return result; } return (b->thing == player || member(b->thing, DBFETCH(player)->contents) || b->thing == DBFETCH(player)->location); case BOOLEXP_PROP: return(has_property(player, b->prop_name, b->prop_data, access_rights(player, player, NOTHING))); default: abort(); /* bad type */ } } } boolexp *copy_bool(boolexp *old) { boolexp *o = (boolexp *)malloc(sizeof(boolexp)); if (!old || !o) return 0; o->type = old->type; switch (old ->type) { case BOOLEXP_AND: case BOOLEXP_OR: o->sub1 = copy_bool(old->sub1); o->sub2 = copy_bool(old->sub2); break; case BOOLEXP_NOT: o->sub1 = copy_bool(old->sub1); break; case BOOLEXP_CONST: o->thing = old->thing; break; case BOOLEXP_PROP: o->prop_name = dup_string(old->prop_name); o->prop_data = dup_string(old->prop_data); break; default: log_status("PANIC: copy_boolexp: Error in boolexp!\n"); abort(); } return o; } /* If the parser returns TRUE_BOOLEXP, you lose */ /* TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead */ static char *parsebuf; static dbref parse_player; static void skip_whitespace() { while(*parsebuf && isspace(*parsebuf)) parsebuf++; } static boolexp *parse_boolexp_E(void); /* defined below */ static boolexp *parse_boolprop(char *buf); /* defined below */ /* F -> (E); F -> !F; F -> object identifier */ static boolexp *parse_boolexp_F() { boolexp *b; char *p; match_data md; char buf[BUFFER_LEN]; char msg[BUFFER_LEN]; skip_whitespace(); switch(*parsebuf) { case '(': parsebuf++; b = parse_boolexp_E(); skip_whitespace(); if(b == TRUE_BOOLEXP || *parsebuf++ != ')') { free_boolexp(b); return TRUE_BOOLEXP; } else return b; case NOT_TOKEN: parsebuf++; b = (boolexp *) malloc(sizeof(boolexp)); b->type = BOOLEXP_NOT; b->sub1 = parse_boolexp_F(); if(b->sub1 == TRUE_BOOLEXP) { free((void *) b); return TRUE_BOOLEXP; } else return b; default: /* must have hit an object ref */ /* load the name into our buffer */ p = buf; while(*parsebuf && *parsebuf != AND_TOKEN && *parsebuf != OR_TOKEN && *parsebuf != ')') *p++ = *parsebuf++; /* strip trailing whitespace */ *p-- = '\0'; while(isspace(*p)) *p-- = '\0'; /* check to see if this is a property expression */ if (index(buf, PROP_DELIMITER)) return parse_boolprop(buf); b = (boolexp *)malloc(sizeof(boolexp)); b->type = BOOLEXP_CONST; if (strcmp(buf, "#-1") && string_compare(buf, "nothing")) { /* do the match */ init_match(parse_player, buf, TYPE_THING, &md); match_neighbor(&md); match_possession(&md); match_me(&md); match_here(&md); match_absolute(&md); match_player(&md); if((b->thing = match_result(&md)) == NOTHING) { sprintf(msg, "I don't see %s here.", buf); notify(parse_player, parse_player, msg); free(b); return TRUE_BOOLEXP; } else if(b->thing == AMBIGUOUS) { sprintf(msg, "I don't know which %s you mean!", buf); notify(parse_player, parse_player, msg); free(b); return TRUE_BOOLEXP; } else return b; } else { b = (boolexp *)malloc(sizeof(boolexp)); b->type = BOOLEXP_CONST; b->thing = NOTHING; return b; } } } /* T -> F; T -> F & T */ static boolexp *parse_boolexp_T() { boolexp *b; boolexp *b2; if((b = parse_boolexp_F()) == TRUE_BOOLEXP) return b; else { skip_whitespace(); if(*parsebuf == AND_TOKEN) { parsebuf++; b2 = (boolexp *) malloc(sizeof(boolexp)); b2->type = BOOLEXP_AND; b2->sub1 = b; if((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } else return b2; } else return b; } } /* E -> T; E -> T | E */ static boolexp *parse_boolexp_E() { boolexp *b; boolexp *b2; if((b = parse_boolexp_T()) == TRUE_BOOLEXP) return b; else { skip_whitespace(); if(*parsebuf == OR_TOKEN) { parsebuf++; b2 = (boolexp *) malloc(sizeof(boolexp)); b2->type = BOOLEXP_OR; b2->sub1 = b; if((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } else return b2; } else return b; } } boolexp *parse_boolexp(dbref player, char *buf) { parsebuf = buf; parse_player = player; return parse_boolexp_E(); } /* parse a property expression If this gets changed, please also remember to modify set.c */ static boolexp *parse_boolprop(char *buf) { char *type, *class, *x, *temp; boolexp *b; x = type = dup_string(buf); class = (char *)strchr(type, PROP_DELIMITER); b = (boolexp *)malloc(sizeof(boolexp)); b->type = BOOLEXP_PROP; b->sub1 = b->sub2 = 0; b->thing = NOTHING; while (isspace(*type) && (*type != PROP_DELIMITER)) type++; if (*type == PROP_DELIMITER) { /* Oops! No property name! Clean up and return true. */ free(x); free(b); return TRUE_BOOLEXP; } /* get rid of trailing spaces */ for (temp = class - 1; isspace(*temp); temp --); temp++; *temp = '\0'; class++; /* skip over leading spaces */ while (isspace(*class) && *class) class++; for(temp = class + strlen(class); isspace(*temp); temp--); temp++; if (isspace(*temp)) *temp = '\0'; if (!*class) { /* Oops! No property data! Clean up and return true. */ free(x); free(b); return TRUE_BOOLEXP; } b->prop_name = dup_string(type); b->prop_data = dup_string(class); free(x); return b; } /* boolean expression dbref global search and replace */ /* To be used in copies, shifts, etc for sanity et. al. */ void bool_dgsr(boolexp *lock, dbref old, dbref new) { switch (lock->type) { case BOOLEXP_AND: case BOOLEXP_OR: bool_dgsr(lock->sub1, old, new); bool_dgsr(lock->sub2, old, new); break; case BOOLEXP_NOT: bool_dgsr(lock->sub1, old, new); break; case BOOLEXP_CONST: if (lock->thing == old) lock->thing = new; break; case BOOLEXP_PROP: break; default: log_status("PANIC: bool_dgsr: Error in boolexp!\n"); abort(); } } void sanitize_lock(boolexp *lock) { if (lock != NULL) switch (lock->type) { case BOOLEXP_AND: case BOOLEXP_OR: sanitize_lock(lock->sub1); sanitize_lock(lock->sub2); break; case BOOLEXP_NOT: sanitize_lock(lock->sub1); break; case BOOLEXP_CONST: if (lock->thing < (dbref) 0 || lock->thing >= db_top) lock->thing = HOME; /* well, it was better than NOTHING */ break; case BOOLEXP_PROP: break; default: log_status("PANIC: sanitize_lock: Error in boolexp!\n"); abort(); } }