/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ /* configure all options BEFORE including system stuff. */ #include "config.h" #include "mud.h" #define ISPUN(x) (x=='#'||x=='['||x==']'||x =='!'||x =='('||x ==')'||x=='&'||x=='|'||x=='=') typedef struct _b_exp { int typ; char *str; struct _b_exp *rhs; struct _b_exp *lhs; } b_exp; static b_exp *build_expr (); static char *tokp; static char *bufp; static int lasttok; static char *curnam; static Obj *curobj; b_exp *compiled; static b_exp *new_b_exp(void); static int nexttok(void); static b_exp *build_subexpr(void); static b_exp *build_expr(void); static int eval_subexpr(b_exp *ex); static int eval_truthof(char *s1, char *s2, int re); static int eval_expr(b_exp *ex); static b_exp *new_b_exp (void) { b_exp *ret; ret = (b_exp *) malloc (sizeof (b_exp)); if (ret == (b_exp *) 0) fatal ("malloc new expression node: ", (char *) -1, "\n", (char *) 0); ret->typ = '$'; ret->str = (char *) 0; ret->rhs = ret->lhs = (b_exp *) 0; return (ret); } static int nexttok (void) { int quot = 0; int ghoti = 0; char tbuf[512]; char *top; while (isspace (*bufp)) bufp++; top = tbuf; if (ISPUN (*bufp)) { quot = *bufp++; return (quot); } if ((*bufp == 'T' || *bufp == 'F') && (isspace (*(bufp + 1)) || *(bufp + 1) == '\0')) { quot = *bufp++; bufp++; return (quot); } while (*bufp != '\0') { ghoti = 1; if (!quot && (*bufp == '\'' || *bufp == '\"')) { quot = *bufp++; continue; } /* done quote */ if (quot && *bufp == quot) { quot = 0; bufp++; continue; } /* done word */ if (!quot && (isspace (*bufp) || ISPUN (*bufp))) break; /* handle escapes */ if (*bufp == '\\') { bufp++; if (*bufp != '\0') { *top++ = *bufp++; } continue; } /* default - just copy */ *top++ = *bufp++; } if (top - tbuf > (int) sizeof (tbuf) - 2) fatal ("string buffer overrun in expression\n", (char *) 0); if (ghoti) { *top = '\0'; tokp = (char *) malloc (top - tbuf + 1); if (tokp == (char *) 0) fatal ("cannot allocate string: ", (char *) -1, "\n", (char *) 0); strcpy (tokp, tbuf); return ('W'); } return ('$'); } static b_exp *build_subexpr (void) { b_exp *ret; switch (lasttok = nexttok ()) { case 'W': ret = new_b_exp (); ret->typ = 'W'; ret->str = tokp; return (ret); case '!': ret = new_b_exp (); if ((ret->rhs = build_subexpr ()) == (b_exp *) 0) return ((b_exp *) 0); ret->typ = '!'; return (ret); case '(': ret = build_expr (); if ((lasttok = nexttok ()) != ')') { fprintf (stderr, "missing right parenthesis\n"); return ((b_exp *) 0); } return (ret); case '[': lasttok = nexttok (); if (lasttok != 'W') { fprintf (stderr, "missing regular expression\n"); return ((b_exp *) 0); } if ((lasttok = nexttok ()) != ']') { fprintf (stderr, "missing regular expression terminator \n"); return ((b_exp *) 0); } ret = new_b_exp (); ret->typ = 'R'; ret->str = tokp; return (ret); case '#': lasttok = nexttok (); if (lasttok != 'W') { fprintf (stderr, "missing object ID\n"); return ((b_exp *) 0); } ret = new_b_exp (); ret->typ = 'O'; ret->str = tokp; return (ret); case '$': case 'T': case 'F': ret = new_b_exp (); ret->typ = lasttok; return (ret); default: fprintf (stderr, "syntax error"); if (lasttok == 'W') { fprintf (stderr, " near \"%s\"", tokp); } else { if (bufp != (char *) 0 && *bufp != '\0') fprintf (stderr, " near \"%c %s\"", lasttok, bufp); } fprintf (stderr, "\n"); return ((b_exp *) 0); } } static b_exp *build_expr (void) { b_exp *ret; b_exp *lhs; if ((lhs = build_subexpr ()) == (b_exp *) 0) return ((b_exp *) 0); switch (lasttok = nexttok ()) { case '&': ret = new_b_exp (); if ((ret->rhs = build_subexpr ()) == (b_exp *) 0) return ((b_exp *) 0); if (ret->rhs->typ == '$') { fprintf (stderr, "missing AND clause\n"); return ((b_exp *) 0); } ret->typ = '&'; ret->lhs = lhs; return (ret); case '=': ret = new_b_exp (); if ((ret->rhs = build_subexpr ()) == (b_exp *) 0) return ((b_exp *) 0); if (lhs->typ != 'W') { fprintf (stderr, "missing attribute for comparison\n"); return ((b_exp *) 0); } if (ret->rhs->typ != 'W' && ret->rhs->typ != 'R') { fprintf (stderr, "missing string for comparison\n"); return ((b_exp *) 0); } ret->typ = '='; ret->lhs = lhs; return (ret); case '|': ret = new_b_exp (); if ((ret->rhs = build_subexpr ()) == (b_exp *) 0) return ((b_exp *) 0); if (ret->rhs->typ == '$') { fprintf (stderr, "missing OR clause\n"); return ((b_exp *) 0); } ret->typ = '|'; ret->lhs = lhs; return (ret); default: return (lhs); } } static int eval_subexpr (ex) b_exp *ex; { switch (ex->typ) { case 'W': fprintf (stderr, "meaningless evaluation"); if (ex->str != (char *) 0) fprintf (stderr, ": \"%s\"", ex->str); fprintf (stderr, "\n"); return (1); case 'O': if (!strcmp (ex->str, curnam)) return (1); return (0); case 'T': return (1); case 'F': return (0); default: return (-1); } } static int eval_truthof (s1, s2, re) char *s1; char *s2; int re; { #ifdef REGEX extern char *regcmp (); extern char *regex (); #else extern char *re_comp (); #endif char *xp; char *vp; char *ap; char *tp; int tl = 0; /* look for a '.' in the attribute name */ for (xp = s1; *xp != '\0' && *xp != '.'; xp++); if (*xp == '.') { tl = xp - s1; ap = ++xp; tp = s1; } else { ap = s1; tp = (char *) 0; } /* feh */ if (*ap == '\0' || (vp = objattr (curobj, ap, 0)) == (char *) 0) return (0); /* specified type ? must match */ if (tp != (char *) 0 && (strncmp (vp, tp, tl) || vp[tl] != ' ')) return (0); /* this eats - already done in objattr really */ xp = vp; /* skip to end of type */ while (*xp != ' ' && *xp != '\0') xp++; if (*xp == '\0') return (0); xp++; /* skip to end of attribute name */ while (*xp != '=' && *xp != '\0') xp++; if (*xp == '\0') return (0); xp++; /* if not a regular expression, this is simplicty */ if (!re) { if (!strcmp (xp, s2)) return (1); return (0); } #ifdef REGEX if ((vp = regcmp (s2, (char *) 0)) == (char *) 0) { fprintf (stderr, "bad regular expression\n"); exit (1); } tp = regex (vp, xp); free (vp); return (tp != (char *) 0); #else if ((vp = re_comp (s2)) != (char *) 0) { fprintf (stderr, "bad regular expression: %s\n", vp); exit (1); } return (re_exec (xp)); #endif } static int eval_expr (ex) b_exp *ex; { int rh; int lh; switch (ex->typ) { case '|': rh = eval_expr (ex->rhs); lh = eval_expr (ex->lhs); return (lh || rh); case '&': rh = eval_expr (ex->rhs); lh = eval_expr (ex->lhs); return (rh == lh); case '=': if (ex->lhs->typ != 'W' || (ex->rhs->typ != 'W' && ex->rhs->typ != 'R')) return (0); return (eval_truthof (ex->lhs->str, ex->rhs->str, ex->rhs->typ == 'R' ? 1 : 0)); default: return (eval_subexpr (ex)); } } int setexpr (char *s) { bufp = s; if ((compiled = build_expr ()) == (b_exp *) 0) return (1); return (0); } int checkexpr (char *nam, Obj * op) { int ret; curnam = nam; curobj = op; ret = eval_expr (compiled); curnam = (char *) 0; curobj = (Obj *) 0; return (ret); }