/* boolexp.c */ #include "copyrite.h" #include "config.h" #include <ctype.h> #ifdef I_STRING #include <string.h> #else #include <strings.h> #endif #include "mushdb.h" #include "match.h" #include "externs.h" #include "conf.h" #include "lock.h" #include "intrface.h" #include "parse.h" #include "confmagic.h" int sizeof_boolexp _((struct boolexp * b)); int eval_boolexp _((dbref player, struct boolexp * b, dbref target, int nrecurs, lock_type ltype)); static void skip_whitespace _((void)); static struct boolexp *test_atr _((char *s, char c)); static struct boolexp *parse_boolexp_L _((void)); static struct boolexp *parse_boolexp_O _((void)); static struct boolexp *parse_boolexp_C _((void)); static struct boolexp *parse_boolexp_I _((void)); static struct boolexp *parse_boolexp_A _((void)); static struct boolexp *parse_boolexp_F _((void)); static struct boolexp *parse_boolexp_T _((void)); static struct boolexp *parse_boolexp_E _((void)); struct boolexp *parse_boolexp _((dbref player, const char *buf)); static int check_attrib_lock _((dbref player, dbref target, const char *atrname, const char *str)); int sizeof_boolexp(b) struct boolexp *b; { if (!b || b == TRUE_BOOLEXP) return 0; switch (b->type) { case BOOLEXP_CONST: return sizeof(struct boolexp); case BOOLEXP_IND: case BOOLEXP_NOT: case BOOLEXP_IS: case BOOLEXP_CARRY: case BOOLEXP_OWNER: return sizeof(struct boolexp) + sizeof_boolexp(b->sub1); case BOOLEXP_AND: case BOOLEXP_OR: return sizeof(struct boolexp) + sizeof_boolexp(b->sub1) + sizeof_boolexp(b->sub2); case BOOLEXP_ATR: case BOOLEXP_EVAL: return sizeof(struct boolexp) + sizeof(struct boolatr) + strlen(b->atr_lock->name) + 1 + strlen(b->atr_lock->text) + 1; } /* Broken lock */ return sizeof(struct boolexp); } int eval_boolexp(player, b, target, nrecurs, ltype) dbref player; /* The player trying to pass */ struct boolexp *b; /* The boolexp */ dbref target; /* The object with the lock */ int nrecurs; /* Recursion depth */ lock_type ltype; { ATTR *a; char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN]; if (!GoodObject(player)) return 0; if (nrecurs > MAX_DEPTH) { notify(player, "Sorry, broken lock!"); return 0; } if (!b) return 1; if (b == TRUE_BOOLEXP) { return 1; } else { switch (b->type) { case BOOLEXP_IND: if (b->sub1->type != BOOLEXP_CONST) return 0; /* We only allow evaluation of indirect locks if target can run * the lock on the referenced object. */ if (!Can_Run_Lock(target, b->sub1->thing, ltype)) return 0; nrecurs++; return (eval_boolexp(player, getlock(b->sub1->thing, ltype), b->sub1->thing, nrecurs, ltype)); case BOOLEXP_AND: return (eval_boolexp(player, b->sub1, target, nrecurs, ltype) && eval_boolexp(player, b->sub2, target, nrecurs, ltype)); case BOOLEXP_OR: return (eval_boolexp(player, b->sub1, target, nrecurs, ltype) || eval_boolexp(player, b->sub2, target, nrecurs, ltype)); case BOOLEXP_NOT: return !eval_boolexp(player, b->sub1, target, nrecurs, ltype); case BOOLEXP_CONST: return (b->thing == player || member(b->thing, db[player].contents)); case BOOLEXP_IS: return (b->sub1->thing == player); case BOOLEXP_CARRY: return (member(b->sub1->thing, db[player].contents)); case BOOLEXP_OWNER: return (Owner(b->sub1->thing) == Owner(player)); case BOOLEXP_ATR: a = atr_complete_match(player, b->atr_lock->name, target); if (!a) return 0; strcpy(tbuf1, uncompress(b->atr_lock->text)); strcpy(tbuf2, uncompress(a->value)); return local_wild_match(tbuf1, tbuf2); case BOOLEXP_EVAL: strcpy(tbuf1, uncompress(b->atr_lock->text)); return check_attrib_lock(player, target, b->atr_lock->name, tbuf1); default: do_log(LT_ERR, 0, 0, "Bad boolexp type %d in object #%d", b->type, b->thing); report(); return 0; } /* switch */ /* should never be reached */ do_log(LT_ERR, 0, 0, "Broken lock type %s in object called by #%d", ltype, player); return 0; } /* else */ } /* 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() { while (*parsebuf && isspace(*parsebuf)) parsebuf++; } #ifdef CAN_NEWSTYLE static struct boolexp * test_atr(char *s, char c) #else static struct boolexp * test_atr(s, c) char *s; char c; #endif { struct boolexp *b; char tbuf1[BUFFER_LEN]; strcpy(tbuf1, s); for (s = tbuf1; *s && (*s != c); s++) ; if (!*s) return (0); *s++ = 0; if (strlen(tbuf1) == 0) return (0); b = alloc_bool(); if (c == ':') b->type = BOOLEXP_ATR; else b->type = BOOLEXP_EVAL; /* !!! Possible portability problem!!!!! */ b->atr_lock = alloc_atr(tbuf1, s); return (b); } /* L -> (E); L -> object identifier */ static struct boolexp * parse_boolexp_L() { struct boolexp *b; char *p; char tbuf1[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; } /* break; */ default: /* must have hit an object ref */ /* load the name into our buffer */ p = tbuf1; 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 */ b = test_atr(tbuf1, ':'); if (b) return (b); /* check for an eval */ b = test_atr(tbuf1, '/'); if (b) return b; b = alloc_bool(); b->type = BOOLEXP_CONST; /* do the match */ b->thing = match_result(parse_player, tbuf1, TYPE_THING, MAT_EVERYTHING); if (b->thing == NOTHING) { notify(parse_player, tprintf("I don't see %s here.", tbuf1)); free_bool(b); return TRUE_BOOLEXP; } else if (b->thing == AMBIGUOUS) { notify(parse_player, tprintf("I don't know which %s you mean!", tbuf1)); free_bool(b); return TRUE_BOOLEXP; } else { return b; } /* break */ } } /* O -> $Identifier ; O -> L */ static struct boolexp * parse_boolexp_O() { struct boolexp *b2; skip_whitespace(); if (*parsebuf == OWNER_TOKEN) { parsebuf++; b2 = alloc_bool(); b2->type = BOOLEXP_OWNER; if (((b2->sub1 = parse_boolexp_L()) == TRUE_BOOLEXP) || (b2->sub1->type != BOOLEXP_CONST)) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); } return (parse_boolexp_L()); } /* C -> +Identifier ; C -> O */ static struct boolexp * parse_boolexp_C() { struct boolexp *b2; skip_whitespace(); if (*parsebuf == IN_TOKEN) { parsebuf++; b2 = alloc_bool(); b2->type = BOOLEXP_CARRY; if (((b2->sub1 = parse_boolexp_L()) == TRUE_BOOLEXP) || (b2->sub1->type != BOOLEXP_CONST)) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); } return (parse_boolexp_O()); } /* I -> =Identifier ; I -> C */ static struct boolexp * parse_boolexp_I() { struct boolexp *b2; skip_whitespace(); if (*parsebuf == IS_TOKEN) { parsebuf++; b2 = alloc_bool(); b2->type = BOOLEXP_IS; if (((b2->sub1 = parse_boolexp_L()) == TRUE_BOOLEXP) || (b2->sub1->type != BOOLEXP_CONST)) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); } return (parse_boolexp_C()); } /* A -> @L; A -> I */ static struct boolexp * parse_boolexp_A() { struct boolexp *b2; skip_whitespace(); if (*parsebuf == AT_TOKEN) { parsebuf++; b2 = alloc_bool(); b2->type = BOOLEXP_IND; if (((b2->sub1 = parse_boolexp_L()) == TRUE_BOOLEXP) || (b2->sub1->type != BOOLEXP_CONST)) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); } return (parse_boolexp_I()); } /* F -> !F;F -> A */ static struct boolexp * parse_boolexp_F() { struct boolexp *b2; skip_whitespace(); if (*parsebuf == NOT_TOKEN) { parsebuf++; b2 = alloc_bool(); b2->type = BOOLEXP_NOT; if ((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else return (b2); } return (parse_boolexp_A()); } /* T -> F; T -> F & T */ static struct boolexp * parse_boolexp_T() { struct boolexp *b; struct boolexp *b2; if ((b = parse_boolexp_F()) == TRUE_BOOLEXP) { return b; } else { skip_whitespace(); if (*parsebuf == AND_TOKEN) { parsebuf++; b2 = alloc_bool(); 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 struct boolexp * parse_boolexp_E() { struct boolexp *b; struct boolexp *b2; if ((b = parse_boolexp_T()) == TRUE_BOOLEXP) { return b; } else { skip_whitespace(); if (*parsebuf == OR_TOKEN) { parsebuf++; b2 = alloc_bool(); 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; } } } struct boolexp * parse_boolexp(player, buf) dbref player; const char *buf; { parsebuf = buf; parse_player = player; return parse_boolexp_E(); } static int check_attrib_lock(player, target, atrname, str) dbref player; dbref target; const char *atrname; const char *str; { /* player is attempting to pass the lock on target, which has * an attribute lock of the form "atrname/value". * This lock is passed if target performing get_eval(target/atrname) * would yield value. This does NOT do a wildcard * match. It is also case-sensitive for matching. */ ATTR *a; char const *asave, *ap; char buff[BUFFER_LEN], *bp; char *preserve[10]; if (!atrname || !*atrname || !str || !*str) return 0; /* fail if there's no matching attribute */ a = atr_get(target, strupper(atrname)); if (!a) return 0; if (!Can_Read_Attr(target, target, a)) return 0; asave = safe_uncompress(a->value); /* perform pronoun substitution */ save_global_regs("check_attrib_lock_save", preserve); bp = buff; ap = asave; process_expression(buff, &bp, &ap, target, player, player, PE_DEFAULT, PT_DEFAULT, NULL); *bp = '\0'; restore_global_regs("check_attrib_lock_save", preserve); free((Malloc_t) asave); return !strcmp(buff, str); }