/*
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);
}