/* boolexp.c */ #include "copyright.h" #ifdef WANT_ANSI #ifdef __STDC__ #include <stddef.h> #include <stdlib.h> #endif /* __STDC__ */ #endif /* WANT_ANSI */ #include "db.h" #include "match.h" #include "mudconf.h" #include "externs.h" #include "interface.h" #ifndef STANDALONE /* --------------------------------------------------------------------------- * check_attr: indicate if attribute ATTR on player passes key when checked by * the object lockobj */ int check_attr (dbref player, dbref lockobj, ATTR *attr, char *key) { char *buff; dbref aowner; int aflags, checkit; buff = atr_pget(player, attr->number, &aowner, &aflags); checkit = 0; if (See_attr(lockobj, player, attr, aowner)) { checkit = 1; #ifdef ATR_NAME } else if (attr->number == A_NAME) { checkit = 1; #endif } if (checkit && (!wild_match(key, buff, (char **)NULL, 0))) { checkit = 0; } free_lbuf(buff); return checkit; } int eval_boolexp(dbref player, dbref thing, struct boolexp * b) { dbref aowner, obj; int aflags, c; char *key, *buff; ATTR *a; if (b == TRUE_BOOLEXP) return 1; switch (b->type) { case BOOLEXP_AND: return (eval_boolexp(player, thing, b->sub1) && eval_boolexp(player, thing, b->sub2)); case BOOLEXP_OR: return (eval_boolexp(player, thing, b->sub1) || eval_boolexp(player, thing, b->sub2)); case BOOLEXP_NOT: return !eval_boolexp(player, thing, b->sub1); case BOOLEXP_INDIR: /* * BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at * evaluation time by the lock of the object whose number is the * argument of the operation. */ mudstate.lock_nest_lev++; if (mudstate.lock_nest_lev >= mudconf.lock_nest_lim) { #ifndef STANDALONE STARTLOG(LOG_BUGS,"BUG","LOCK") log_name_and_loc(player); log_text((char *)": Lock exceeded recursion limit."); ENDLOG notify(player, "Sorry, broken lock!"); #else fprintf(stderr, "Lock exceeded recursion limit.\n"); #endif mudstate.lock_nest_lev--; return (0); } if ((b->sub1->type != BOOLEXP_CONST) || (b->sub1->thing < 0)) { #ifndef STANDALONE STARTLOG(LOG_BUGS,"BUG","LOCK") log_name_and_loc(player); buff = alloc_mbuf("eval_boolexp.LOG.indir"); sprintf(buff, ": Lock had bad indirection (%c, type %d)", INDIR_TOKEN, b->sub1->type); log_text(buff); free_mbuf(buff); ENDLOG notify(player, "Sorry, broken lock!"); #else fprintf(stderr, "Broken lock.\n"); #endif mudstate.lock_nest_lev--; return (0); } key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags); c = eval_boolexp_atr(player, thing, key); free_lbuf(key); mudstate.lock_nest_lev--; return (c); case BOOLEXP_CONST: return (b->thing == player || member(b->thing, Contents(player))); case BOOLEXP_ATR: a = atr_num(b->thing); if (!a) return 0; /* no such attribute */ /* First check the object itself, then its contents */ if (check_attr(player, thing, a, (char *)b->sub1)) return 1; DOLIST(obj, Contents(player)) { if (check_attr(obj, thing, a, (char *)b->sub1)) return 1; } return 0; case BOOLEXP_IS: return (b->sub1->thing == player); case BOOLEXP_CARRY: return (member(b->sub1->thing, Contents(player))); case BOOLEXP_OWNER: return (Owner(b->sub1->thing) == Owner(player)); default: abort(); /* bad type */ return 0; } } int eval_boolexp_atr(dbref player, dbref thing, char *key) { struct boolexp *b; int ret_value; b = parse_boolexp(player, key); if (b == NULL) ret_value = 1; else ret_value = eval_boolexp(player, thing, b); free_boolexp(b); return (ret_value); } #endif /* 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 char parsestore[LBUF_SIZE]; static dbref parse_player; static void skip_whitespace() { while (*parsebuf && isspace(*parsebuf)) parsebuf++; } static struct boolexp *parse_boolexp_E(); /* defined below */ static struct boolexp *test_atr(char *s) { ATTR *attrib; struct boolexp *b; char *buff, *s1; int anum; buff = alloc_lbuf("test_atr"); strcpy(buff, s); for (s = buff; *s && (*s != ':'); s++) ; if (!*s) { free_lbuf(buff); return((struct boolexp *)NULL); } *s++ = '\0'; /* see if left side is valid attribute. Access to attr is checked on eval * Also allow numeric references to attributes. It can't hurt us, and * lets us import stuff that stores attr locks by number instead of by * name. */ if (!(attrib = atr_str(buff))) { /* Only #1 can lock on numbers */ if (!God(parse_player)) return((struct boolexp *)NULL); s1 = buff; for (s1=buff; isdigit(*s1); s1++) ; if (*s1) { free_lbuf(buff); return((struct boolexp *)NULL); } anum = atoi(buff); } else { anum = attrib->number; } /* made it now make the parse tree node */ b = alloc_bool("test_str"); b->type = BOOLEXP_ATR; b->thing = (dbref)anum; b->sub1 = (struct boolexp *)strsave(s); free_lbuf(buff); return (b); } /* L -> (E); L -> object identifier */ static struct boolexp * parse_boolexp_L() { struct boolexp *b; char *p, *buf; buf = NULL; skip_whitespace(); switch (*parsebuf) { case '(': parsebuf++; b = parse_boolexp_E(); skip_whitespace(); if (b == TRUE_BOOLEXP || *parsebuf++ != ')') { free_boolexp(b); return TRUE_BOOLEXP; } break; default: /* must have hit an object ref */ /* load the name into our buffer */ buf = alloc_lbuf("parse_boolexp_L"); p = buf; while (*parsebuf && *parsebuf != AND_TOKEN && *parsebuf != OR_TOKEN && *parsebuf != ')') { *p++ = *parsebuf++; } /* strip trailing whitespace */ *p-- = '\0'; while (isspace(*p)) *p-- = '\0'; /* check for an attribute */ if ((b = test_atr(buf)) != NULL) { free_lbuf(buf); return (b); } b = alloc_bool("parse_boolexp_L"); b->type = BOOLEXP_CONST; /* do the match */ #ifndef STANDALONE init_match(parse_player, buf, TYPE_THING); match_neighbor(); match_possession(); match_me(); match_absolute(); match_player(); b->thing = match_result(); if (b->thing == NOTHING) { notify(parse_player, tprintf("I don't see %s here.", buf)); free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } if (b->thing == AMBIGUOUS) { notify(parse_player, tprintf("I don't know which %s you mean!", buf)); free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } #else /* STANDALONE ... had better be #<num> or we're hosed */ if (buf[0] != '#') { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } b->thing = atol(&buf[1]); if (b->thing < 0) { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } #endif free_lbuf(buf); } return b; } /* F -> !F; F -> @L; F -> =L; F -> +L; F -> $L */ /* The argument to ` must be type BOOLEXP_CONST */ static struct boolexp * parse_boolexp_F() { struct boolexp *b2; skip_whitespace(); switch (*parsebuf) { case NOT_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.not"); b2->type = BOOLEXP_NOT; if ((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); /*NOTREACHED*/ break; case INDIR_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.indir"); b2->type = BOOLEXP_INDIR; b2->sub1 = parse_boolexp_L(); if ((b2->sub1) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ((b2->sub1->type) != BOOLEXP_CONST) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); /*NOTREACHED*/ break; case IS_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.is"); b2->type = BOOLEXP_IS; b2->sub1 = parse_boolexp_L(); if ((b2->sub1) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ((b2->sub1->type) != BOOLEXP_CONST) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); /*NOTREACHED*/ break; case CARRY_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.carry"); b2->type = BOOLEXP_CARRY; b2->sub1 = parse_boolexp_L(); if ((b2->sub1) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ((b2->sub1->type) != BOOLEXP_CONST) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); /*NOTREACHED*/ break; case OWNER_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.owner"); b2->type = BOOLEXP_OWNER; b2->sub1 = parse_boolexp_L(); if ((b2->sub1) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ((b2->sub1->type) != BOOLEXP_CONST) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); /*NOTREACHED*/ break; default: return (parse_boolexp_L()); } } /* T -> F; T -> F & T */ static struct boolexp * parse_boolexp_T() { struct boolexp *b; struct boolexp *b2; if ((b = parse_boolexp_F()) != TRUE_BOOLEXP) { skip_whitespace(); if (*parsebuf == AND_TOKEN) { parsebuf++; b2 = alloc_bool("parse_boolexp_T"); b2->type = BOOLEXP_AND; b2->sub1 = b; if ((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } b = b2; } } return b; } /* E -> T; E -> T | E */ static struct boolexp * parse_boolexp_E() { struct boolexp *b; struct boolexp *b2; if ((b = parse_boolexp_T()) != TRUE_BOOLEXP) { skip_whitespace(); if (*parsebuf == OR_TOKEN) { parsebuf++; b2 = alloc_bool("parse_boolexp_E"); b2->type = BOOLEXP_OR; b2->sub1 = b; if ((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } b = b2; } } return b; } struct boolexp * parse_boolexp(dbref player, const char *buf) { strcpy(parsestore, buf); parsebuf = parsestore; parse_player = player; if ((buf == NULL) || (*buf == '\0')) return (TRUE_BOOLEXP); return parse_boolexp_E(); }