/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ #include #include #include "db.h" #include "defs.h" #include "match.h" #include "ctype.h" #include "params.h" #include "config.h" #include "strings.h" #include "externs.h" #include "property.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. */ int eval_boolexp(dbref player, dbref passer, struct boolexp *b, dbref onthing) { if (b == TRUE_BOOLEXP) { return(1); } switch (b->type) { case BOOLEXP_AND: return( eval_boolexp(player,passer,b->u.dyad.sub1,onthing) && eval_boolexp(player,passer,b->u.dyad.sub2,onthing) ); break; case BOOLEXP_OR: return( eval_boolexp(player,passer,b->u.dyad.sub1,onthing) || eval_boolexp(player,passer,b->u.dyad.sub2,onthing) ); break; case BOOLEXP_NOT: return(!eval_boolexp(player,passer,b->u.monad,onthing)); break; case BOOLEXP_OBJ: if (Typeof(b->u.obj.thing) == TYPE_PROGRAM) { return(interp_with_me(player,passer,b->u.obj.thing,onthing,b->u.obj.param,makearray(1,makeinst(PROG_STRING,dup_string("lock"))))); } return( (b->u.obj.thing == passer) || ( ( (Typeof(passer) == TYPE_ROOM) || (Typeof(passer) == TYPE_PLAYER) ) && member(b->u.obj.thing,DBFETCH(passer)->contents) ) || (b->u.obj.thing == DBFETCH(passer)->location) ); break; case BOOLEXP_PROP: return(lockprop_check(onthing,passer,b->u.prop)); break; } abort(); } struct boolexp *copy_bool(struct boolexp *old) { struct boolexp *o; if (old == TRUE_BOOLEXP) return(TRUE_BOOLEXP); o = malloc(sizeof(struct boolexp)); if (! o) return(TRUE_BOOLEXP); o->type = old->type; switch (old->type) { case BOOLEXP_AND: case BOOLEXP_OR: o->u.dyad.sub1 = copy_bool(old->u.dyad.sub1); o->u.dyad.sub2 = copy_bool(old->u.dyad.sub2); break; case BOOLEXP_NOT: o->u.monad = copy_bool(old->u.monad); break; case BOOLEXP_OBJ: o->u.obj.thing = old->u.obj.thing; o->u.obj.param = dup_string(old->u.obj.param); break; case BOOLEXP_PROP: if (! old->u.prop) { free(o); return(TRUE_BOOLEXP); } o->u.prop = copy_lockprop(old->u.prop); break; default: log_status("PANIC: copy_boolexp: Error in boolexp!"); abort(); } return(o); } /* If the parser returns TRUE_BOOLEXP, you lose */ /* TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead */ static const char *parsebuf; static dbref parse_player; static void skip_whitespace(void) { while (*parsebuf && Cisspace(*parsebuf)) parsebuf++; } static struct boolexp *parse_boolexp_E(void); /* forward */ static struct boolexp *parse_boolprop(char *buf); /* forward */ static struct boolexp *parse_boolexp_leaf(void) { struct boolexp *b; char *p; struct match_data md; char buf[BUFFER_LEN]; char msg[BUFFER_LEN]; p = &buf[0]; while ( *parsebuf && (*parsebuf != AND_TOKEN) && (*parsebuf != OR_TOKEN) && (*parsebuf != ')') && (p-&buf[0] < BUFFER_LEN) ) { *p++ = *parsebuf++; } /* strip trailing whitespace */ *p-- = '\0'; while (Cisspace(*p)) *p-- = '\0'; /* check to see if this is a property expression */ if (index(&buf[0],PROP_DELIMITER)) return(parse_boolprop(&buf[0])); p = index(&buf[0],'\''); if (p) { *p++ = '\0'; } else { p = 0; } b = malloc(sizeof(struct boolexp)); b->type = BOOLEXP_OBJ; init_match(parse_player,&buf[0],TYPE_THING,&md); match_neighbor(&md); match_possession(&md); match_me(&md); match_here(&md); match_absolute(&md); match_player(&md); b->u.obj.thing = match_result(&md); if (b->u.obj.thing == NOTHING) { snprintf(&msg[0],sizeof(msg),"I don't see %s here.",buf); notify(parse_player,msg); free(b); return(TRUE_BOOLEXP); } if (b->u.obj.thing == AMBIGUOUS) { snprintf(&msg[0],sizeof(msg),"I don't know which %s you mean!",buf); notify(parse_player,msg); free(b); return(TRUE_BOOLEXP); } if ((b->u.obj.thing < 0) || (b->u.obj.thing >= db_top)) { snprintf(&msg[0],sizeof(msg),"Nonexistent dbref #%d.",(int)b->u.obj.thing); notify(parse_player,msg); free(b); return(TRUE_BOOLEXP); } if (Typeof(b->u.obj.thing) == TYPE_GARBAGE) { notify(parse_player,"Can't lock to garbage."); free(b); return(TRUE_BOOLEXP); } b->u.obj.param = dup_string(p); return(b); } /* F -> (E); F -> !F; F -> object identifier */ static struct boolexp *parse_boolexp_F(void) { struct boolexp *b; 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); } break; case NOT_TOKEN: parsebuf ++; b = malloc(sizeof(struct boolexp)); b->type = BOOLEXP_NOT; b->u.monad = parse_boolexp_F(); if (b->u.monad == TRUE_BOOLEXP) { free(b); return(TRUE_BOOLEXP); } else { return(b); } break; default: /* must have hit an object ref or property */ return(parse_boolexp_leaf()); break; } } /* T -> F; T -> F & T (pseudo tailmerged) */ static struct boolexp *parse_boolexp_T(void) { struct boolexp *b; struct boolexp *b2; b = parse_boolexp_F(); if (b == TRUE_BOOLEXP) return(TRUE_BOOLEXP); while (1) { skip_whitespace(); if (*parsebuf != AND_TOKEN) break; parsebuf ++; b2 = malloc(sizeof(struct boolexp)); b2->type = BOOLEXP_AND; b2->u.dyad.sub1 = b; b2->u.dyad.sub2 = parse_boolexp_F(); if (b2->u.dyad.sub2 == TRUE_BOOLEXP) { free_boolexp(b2); return(TRUE_BOOLEXP); } b = b2; } return(b); } /* E -> T; E -> T | E (pseudo tailmerged) */ static struct boolexp *parse_boolexp_E() { struct boolexp *b; struct boolexp *b2; b = parse_boolexp_T(); if (b == TRUE_BOOLEXP) return(TRUE_BOOLEXP); while (1) { skip_whitespace(); if (*parsebuf != OR_TOKEN) break; parsebuf ++; b2 = malloc(sizeof(struct boolexp)); b2->type = BOOLEXP_OR; b2->u.dyad.sub1 = b; b2->u.dyad.sub2 = parse_boolexp_T(); if (b2->u.dyad.sub2 == TRUE_BOOLEXP) { free_boolexp(b2); return(TRUE_BOOLEXP); } b = b2; } return(b); } struct boolexp *parse_boolexp(dbref player, const 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 struct boolexp *parse_boolprop(char *buf) { char *name; char *value; int namelen; int valuelen; struct boolexp *b; char *t; name = buf; value = index(buf,PROP_DELIMITER); if (! value) return(TRUE_BOOLEXP); for (;(name= value) return(TRUE_BOOLEXP); for (t=value-1;Cisspace(*t);t--) ; namelen = (t+1) - name; for (value++;(*value)&&Cisspace(*value);value++) ; if (! *value) return(TRUE_BOOLEXP); for (t=value;(*t)&&!Cisspace(*t);t++) ; valuelen = t - value; b = malloc(sizeof(struct boolexp)); b->type = BOOLEXP_PROP; b->u.prop = make_lockprop(name,namelen,value,valuelen); return(b); } void free_boolexp(struct boolexp *b) { if (b != TRUE_BOOLEXP) { switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: free_boolexp(b->u.dyad.sub1); free_boolexp(b->u.dyad.sub2); break; case BOOLEXP_NOT: free_boolexp(b->u.monad); break; case BOOLEXP_OBJ: free(b->u.obj.param); break; case BOOLEXP_PROP: free_lockprop(b->u.prop); break; } free(b); } } void write_boolexp_param(FILE *f, const char *s) { for (;*s;s++) { switch (*s) { case '\\': case '`': putc('\\',f); break; } putc(*s,f); } putc('`',f); } char *read_boolexp_param(FILE *f) { char *s; int a; int l; int c; int q; void save(char ch) { if (l >= a) s = realloc(s,a=l+8); s[l++] = ch; } s = 0; a = 0; l = 0; q = 0; while (1) { c = getc(f); if (c == EOF) { free(s); return(0); } if (q) { q = 0; save(c); } else if (c == '\\') { q = 1; } else if (c == '`') { save('\0'); return(s); } else { save(c); } } }