/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ /* configure all options BEFORE including system stuff. */ #include "config.h" #include "mud.h" #include "match.h" #include "vars.h" #include "sbuf.h" #include "U/u.h" /* Zen recursive descent boolean evaluation. Code by Molly, 1991. Some of this code is deliberately weird. live with it. */ /* test if x is a token char */ #define ISTOK(x) (x =='!'||x =='('||x ==')'||x == '&'||x=='|') /* WARNING! this is initted statically and deinnited in the main evaluator. */ static Sbuf sb; static char *bp; static int lasttok = '$'; static char *whop; static char *wherep; static int checkmode = 0; static int evaluate_truth(char *s, int withflg); static int nexttok(void); static int b_subexpr(void); static int b_expr(void); static int bool_pasteID(char *who, char *what, Sbuf *s); static int evaluate_truth (char *s, int withflg) { char *lp; if (whop == (char *) 0) return (0); if (!strcmp (s, whop)) return (1); /* check the stuff the guy is carrying */ if (ut_listchk (whop, var_cont, s)) return (1); /* check the stuff the guy is using */ if ((lp = ut_getatt (whop, 0, typ_obj, var_using, (char *) 0)) != (char *) 0) { if (!strcmp (s, lp)) return (1); } /* if with flag is set, then check if the thing is in the room or is another player in the room */ if (withflg && wherep != (char *) 0) { if (ut_listchk (wherep, var_ply, s) || ut_listchk (wherep, var_cont, s)) return (1); } return (0); } static int nexttok (void) { int quot = 0; while (isspace (*bp)) bp++; if (ISTOK (*bp)) { quot = *bp++; return (quot); } if ((*bp == 'T' || *bp == 'F') && (ISTOK (*(bp + 1)) || isspace (*(bp + 1)) || *(bp + 1) == '\0')) { quot = *bp++; return (quot); } sbuf_reset (&sb); while (*bp != '\0') { /* enter quote */ if (!quot && (*bp == '\'' || *bp == '\"')) { quot = *bp++; continue; } /* done quote */ if (quot && *bp == quot) { quot = 0; bp++; continue; } /* done word */ if (!quot && (isspace (*bp) || ISTOK (*bp))) { sbuf_put ('\0', &sb); break; } /* handle escapes */ if (*bp == '\\') { bp++; if (*bp != '\0') { sbuf_put (*bp, &sb); bp++; } continue; } /* default - just copy */ sbuf_put (*bp, &sb); bp++; } if (sbuf_len (&sb) >= 0) { /* sbuf_len() return char count - 1 */ sbuf_put ('\0', &sb); if (!strcmp (sbuf_buf (&sb), "with")) return ('+'); return ('^'); } return ('$'); } static int b_subexpr (void) { int x; switch (lasttok = nexttok ()) { case 'T': return (1); case 'F': return (0); case '^': if (checkmode) return (1); return (evaluate_truth (sbuf_buf (&sb), 0)); case '+': lasttok = nexttok (); if (lasttok != '^') { if (checkmode && whop != (char *) 0) say (whop, "missing WITH item\n", (char *) 0); return (-1); } if (checkmode) return (1); return (evaluate_truth (sbuf_buf (&sb), 1)); case '!': if ((x = b_subexpr ()) == -1) { if (checkmode && whop != (char *) 0) say (whop, "missing subexpression after '!'\n", (char *) 0); return (-1); } return (!x); case '(': x = b_expr (); if (lasttok != ')') { if (checkmode && whop != (char *) 0) say (whop, "missing right parenthesis\n", (char *) 0); return (-1); } return (x); case '$': return ('$'); default: if (checkmode && whop != (char *) 0) { say (whop, "syntax error", (char *) 0); if (bp != (char *) 0 && *bp != '\0') say (whop, " near \"", bp, "\"", (char *) 0); say (whop, "\n", (char *) 0); } return (-1); } } static int b_expr (void) { int ret = b_subexpr (); int x; for (;;) { switch (lasttok = nexttok ()) { case '&': if ((x = b_subexpr ()) == -1) { if (checkmode && whop != (char *) 0) say (whop, "missing AND clause\n", (char *) 0); return (-1); } if (x == '$') { if (checkmode && whop != (char *) 0) say (whop, "missing subexpression\n", (char *) 0); return (-1); } ret = (ret && x); break; case '|': if ((x = b_subexpr ()) == -1) { if (checkmode && whop != (char *) 0) say (whop, "missing OR clause\n", (char *) 0); return (-1); } if (x == '$') { if (checkmode && whop != (char *) 0) say (whop, "missing subexpression\n", (char *) 0); return (-1); } ret = (ret || x); break; default: return (ret); } } } int bool_eval (char *who, char *where, char *s, int check) { int ret; bp = s; whop = who; wherep = where; checkmode = check; sbuf_initstatic (&sb); ret = b_expr (); if (ret < 0 && checkmode && whop != (char *) 0) say (whop, "invalid boolean expression.\n", (char *) 0); sbuf_freestatic (&sb); whop = (char *) 0; wherep = (char *) 0; checkmode = 0; return (ret); } /* check a lock. */ int bool_locked (char *who, char *what, char *where, char *lockvar, int deflt) { char *lockp; lockp = ut_getatt (what, 1, (char *) 0, lockvar, (char *) 0); if (lockp == (char *) 0) return (deflt); if (attistype (lockp, typ_bool)) return (bool_eval (who, where, attdata (lockp), 0) == 0); if (attistype (lockp, typ_u)) { parser_setinput (attdata (lockp)); if (parser_compile (who)) (void) parser_run (who, what, 0, (char **) 0); return (eval_cmd_returnedtrue ()); } return (deflt); } /* check a lock's syntax. */ int bool_syntax (char *who, char *exp) { int ret; ret = bool_eval (who, (char *) 0, exp, 1); if (ret == -1) return (1); return (0); } /* Match a string against the environment, and paste the object ID in to the specified Sbuf. */ static int bool_pasteID (char *who, char *what, Sbuf * s) { char objid[MAXOID]; char *where; where = ut_loc (who); if (!matchlocal (who, what, where, MTCH_UNIQ | MTCH_NONLOC | MTCH_MEOK, objid)) { (void) sbuf_strcat (objid, s); sbuf_unput (s); /* lose trailing \0 */ return (0); } return (-1); } /* Re-write a lock, matching junk against the environment and generating object IDs. Sbuf out - pre-initted */ int bool_rewrite (char *who, char *s, Sbuf * out) { char quot = '\0'; char ch; char *thing = ""; char *p; while (*s) { /* End a quoted thing */ if (quot && *s == quot) { *s = '\0'; if (bool_pasteID (who, thing, out)) { *s = quot; return (-1); } *s++ = quot; quot = '\0'; continue; } /* Make the rest of these clauses if(!quot && <stuff> */ if (quot) { s++; continue; } /* Skip white-boy space. Marcus-like */ if (isspace (*s)) { s++; continue; } /* Copy TOK type things blindly */ if (ISTOK (*s) || ((*s == 'T' || *s == 'F') && (ISTOK (*(s + 1)) || isspace (*(s + 1)) || *(s + 1) == '\0'))) { sbuf_put (*s++, out); continue; } /* Start quoted thing */ if (*s == '\'' || *s == '\"') { quot = *s++; thing = s; continue; } if (!strncmp ("with ", s, 5)) { s += 5; (void) sbuf_strcat ("with ", out); sbuf_unput (out); /* lose trailing \0 */ continue; } /* Grub out an un-quoted thing name */ thing = s; p = (char *) 0; while (!ISTOK (*s) && *s) { if (!isspace (*s) && isspace (s[1])) p = s + 1; s++; } if (!p) p = s; ch = *p; *p = '\0'; if (bool_pasteID (who, thing, out)) { *s = ch; return (-1); } *p = ch; } /* OK. Fell off end of string. Check for unclosed quoted thing */ if (quot) { if (bool_pasteID (who, thing, out)) return (-1); } sbuf_put ('\0', out); return (0); }