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