btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * boolexp.c 
 */

/*
 * $Id: boolexp.c,v 1.3 2005/08/08 09:43:05 murrayma Exp $ 
 */
#include "copyright.h"
#include "config.h"

#include "db.h"
#include "match.h"
#include "mudconf.h"
#include "externs.h"
#include "interface.h"
#include "attrs.h"
#include "flags.h"
#include "powers.h"
#include "alloc.h"

#ifndef STANDALONE

static int parsing_internal = 0;

/*
 * ---------------------------------------------------------------------------
 * * check_attr: indicate if attribute ATTR on player passes key when checked by
 * * the object lockobj
 */

static int check_attr(player, lockobj, attr, key)
dbref player, lockobj;
ATTR *attr;
char *key;
{
    char *buff;
    dbref aowner;
    int aflags, checkit;

    buff = atr_pget(player, attr->number, &aowner, &aflags);
    checkit = 0;

    if (attr->number == A_LENTER) {
	/* We can see enterlocks... else we'd break zones */
	checkit = 1;
    } else if (See_attr(lockobj, player, attr, aowner, aflags)) {
	checkit = 1;
    } else if (attr->number == A_NAME) {
	checkit = 1;
    }
    if (checkit && (!wild_match(key, buff))) {
	checkit = 0;
    }
    free_lbuf(buff);
    return checkit;
}

int eval_boolexp(player, thing, from, b)
dbref player, thing, from;
BOOLEXP *b;
{
    dbref aowner, obj, source;
    int aflags, c, checkit;
    char *key, *buff, *buff2, *bp, *str;
    ATTR *a;

    if (b == TRUE_BOOLEXP)
	return 1;

    switch (b->type) {
    case BOOLEXP_AND:
	return (eval_boolexp(player, thing, from, b->sub1) &&
	    eval_boolexp(player, thing, from, b->sub2));
    case BOOLEXP_OR:
	return (eval_boolexp(player, thing, from, b->sub1) ||
	    eval_boolexp(player, thing, from, b->sub2));
    case BOOLEXP_NOT:
	return !eval_boolexp(player, thing, from, b->sub1);
    case BOOLEXP_INDIR:
	/*
	 * BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at
	 * evaluation time by the lock of the object whose number is the
	 * argument of the operation.
	 */

	mudstate.lock_nest_lev++;
	if (mudstate.lock_nest_lev >= mudconf.lock_nest_lim) {
#ifndef STANDALONE
	    STARTLOG(LOG_BUGS, "BUG", "LOCK") {
		log_name_and_loc(player);
		log_text((char *) ": Lock exceeded recursion limit.");
		ENDLOG;
	    } notify(player, "Sorry, broken lock!");
#else
	    fprintf(stderr, "Lock exceeded recursion limit.\n");
#endif
	    mudstate.lock_nest_lev--;
	    return (0);
	}
	if ((b->sub1->type != BOOLEXP_CONST) || (b->sub1->thing < 0)) {
#ifndef STANDALONE
	    STARTLOG(LOG_BUGS, "BUG", "LOCK") {
		log_name_and_loc(player);
		buff = alloc_mbuf("eval_boolexp.LOG.indir");
		sprintf(buff, ": Lock had bad indirection (%c, type %d)",
		    INDIR_TOKEN, b->sub1->type);
		log_text(buff);
		free_mbuf(buff);
		ENDLOG;
	    }
	    notify(player, "Sorry, broken lock!");
#else
	    fprintf(stderr, "Broken lock.\n");
#endif
	    mudstate.lock_nest_lev--;
	    return (0);
	}
	key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags);
	c = eval_boolexp_atr(player, b->sub1->thing, from, key);
	free_lbuf(key);
	mudstate.lock_nest_lev--;
	return (c);
    case BOOLEXP_CONST:
	return (b->thing == player || member(b->thing, Contents(player)));
    case BOOLEXP_ATR:
	a = atr_num(b->thing);
	if (!a)
	    return 0;		/*
				 * no such attribute 
				 */

	/*
	 * First check the object itself, then its contents 
	 */

	if (check_attr(player, from, a, (char *) b->sub1))
	    return 1;
	DOLIST(obj, Contents(player)) {
	    if (check_attr(obj, from, a, (char *) b->sub1))
		return 1;
	}
	return 0;
    case BOOLEXP_EVAL:
	a = atr_num(b->thing);
	if (!a)
	    return 0;		/*
				 * no such attribute 
				 */
	source = from;
	buff = atr_pget(from, a->number, &aowner, &aflags);
	if (!buff || !*buff) {
	    free_lbuf(buff);
	    buff = atr_pget(thing, a->number, &aowner, &aflags);
	    source = thing;
	}
	checkit = 0;

	if ((a->number == A_NAME) || (a->number == A_LENTER)) {
	    checkit = 1;
	} else if (Read_attr(source, source, a, aowner, aflags)) {
	    checkit = 1;
	}
	if (checkit) {
	    buff2 = bp = alloc_lbuf("eval_boolexp");
	    str = buff;
	    exec(buff2, &bp, 0, source, player,
		EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **) NULL, 0);
	    *bp = '\0';
	    checkit = !string_compare(buff2, (char *) b->sub1);
	    free_lbuf(buff2);
	}
	free_lbuf(buff);
	return checkit;
    case BOOLEXP_IS:

	/*
	 * If an object check, do that 
	 */

	if (b->sub1->type == BOOLEXP_CONST)
	    return (b->sub1->thing == player);

	/*
	 * Nope, do an attribute check 
	 */

	a = atr_num(b->sub1->thing);
	if (!a)
	    return 0;
	return (check_attr(player, from, a, (char *) (b->sub1)->sub1));
    case BOOLEXP_CARRY:

	/*
	 * If an object check, do that 
	 */

	if (b->sub1->type == BOOLEXP_CONST)
	    return (member(b->sub1->thing, Contents(player)));

	/*
	 * Nope, do an attribute check 
	 */

	a = atr_num(b->sub1->thing);
	if (!a)
	    return 0;
	DOLIST(obj, Contents(player)) {
	    if (check_attr(obj, from, a, (char *) (b->sub1)->sub1))
		return 1;
	}
	return 0;
    case BOOLEXP_OWNER:
	return (Owner(b->sub1->thing) == Owner(player));
    default:
	abort();		/*
				 * bad type 
				 */
	return 0;
    }
}

int eval_boolexp_atr(player, thing, from, key)
dbref player, thing, from;
char *key;
{
    BOOLEXP *b;
    int ret_value;

    b = parse_boolexp(player, key, 1);
    if (b == NULL) {
	ret_value = 1;
    } else {
	ret_value = eval_boolexp(player, thing, from, b);
	free_boolexp(b);
    }
    return (ret_value);
}

#endif

/*
 * 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 char parsestore[LBUF_SIZE];
static dbref parse_player;

static void skip_whitespace(void)
{
    while (*parsebuf && isspace(*parsebuf))
	parsebuf++;
}

static BOOLEXP *parse_boolexp_E(void);	/*


					 * * defined below  
					 */

static BOOLEXP *test_atr(s)
char *s;
{
    ATTR *attrib;
    BOOLEXP *b;
    char *buff, *s1;
    int anum, locktype;

    buff = alloc_lbuf("test_atr");
    StringCopy(buff, s);
    for (s = buff; *s && (*s != ':') && (*s != '/'); s++);
    if (!*s) {
	free_lbuf(buff);
	return ((BOOLEXP *) NULL);
    }
    if (*s == '/')
	locktype = BOOLEXP_EVAL;
    else
	locktype = BOOLEXP_ATR;

    *s++ = '\0';
    /*
     * see if left side is valid attribute.  Access to attr is checked on 
     * 
     * *  * *  * *  * *  * * eval * Also allow numeric references to *
     * attributes. * It * can't * hurt  * us, and * lets us import stuff
     * * that stores * attr * locks by * number * instead of by * name. 
     */
    if (!(attrib = atr_str(buff))) {

	/*
	 * Only #1 can lock on numbers 
	 */
	if (!God(parse_player)) {
	    free_lbuf(buff);
	    return ((BOOLEXP *) NULL);
	}
	s1 = buff;
	for (s1 = buff; isdigit(*s1); s1++);
	if (*s1) {
	    free_lbuf(buff);
	    return ((BOOLEXP *) NULL);
	}
	anum = atoi(buff);
    } else {
	anum = attrib->number;
    }

    /*
     * made it now make the parse tree node 
     */
    b = alloc_bool("test_str");
    b->type = locktype;
    b->thing = (dbref) anum;
    b->sub1 = (BOOLEXP *) strsave(s);
    free_lbuf(buff);
    return (b);
}

/*
 * L -> (E); L -> object identifier 
 */

static BOOLEXP *parse_boolexp_L(void)
{
    BOOLEXP *b;
    char *p, *buf;

#ifndef STANDALONE
    MSTATE mstate;

#endif

    buf = NULL;
    skip_whitespace();

    switch (*parsebuf) {
    case '(':
	parsebuf++;
	b = parse_boolexp_E();
	skip_whitespace();
	if (b == TRUE_BOOLEXP || *parsebuf++ != ')') {
	    free_boolexp(b);
	    return TRUE_BOOLEXP;
	}
	break;
    default:

	/*
	 * must have hit an object ref.  Load the name into our * * * 
	 * 
	 * *  * *  * * buffer 
	 */

	buf = alloc_lbuf("parse_boolexp_L");
	p = buf;
	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 
	 */

	if ((b = test_atr(buf)) != NULL) {
	    free_lbuf(buf);
	    return (b);
	}
	b = alloc_bool("parse_boolexp_L");
	b->type = BOOLEXP_CONST;

	/*
	 * do the match 
	 */

#ifndef STANDALONE

	/*
	 * If we are parsing a boolexp that was a stored lock then *
	 * * * * * * we know that object refs are all dbrefs, so we * 
	 * skip * * the * * * expensive match code. 
	 */

    if (parsing_internal) {
        if (buf[0] != '#') {
            free_lbuf(buf);
            free_bool(b);
            return TRUE_BOOLEXP;
        }
        b->thing = atoi(&buf[1]);
        if (!Good_obj(b->thing)) {
            free_lbuf(buf);
            free_bool(b);
            return TRUE_BOOLEXP;
        }
    } else {
	    save_match_state(&mstate);
	    init_match(parse_player, buf, TYPE_THING);
	    match_everything(MAT_EXIT_PARENTS);
	    b->thing = match_result();
	    restore_match_state(&mstate);
	}

	if (b->thing == NOTHING) {
	    notify(parse_player, tprintf("I don't see %s here.", buf));
	    free_lbuf(buf);
	    free_bool(b);
	    return TRUE_BOOLEXP;
	}
	if (b->thing == AMBIGUOUS) {
	    notify(parse_player, tprintf("I don't know which %s you mean!",
		    buf));
	    free_lbuf(buf);
	    free_bool(b);
	    return TRUE_BOOLEXP;
	}
#else				/*
				 * * STANDALONE ... had better be #<num> or we're hosed  
				 */
	if (buf[0] != '#') {
	    free_lbuf(buf);
	    free_bool(b);
	    return TRUE_BOOLEXP;
	}
	b->thing = atoi(&buf[1]);
	if (b->thing < 0) {
	    free_lbuf(buf);
	    free_bool(b);
	    return TRUE_BOOLEXP;
	}
#endif
	free_lbuf(buf);
    }
    return b;
}

/*
 * F -> !F; F -> @L; F -> =L; F -> +L; F -> $L 
 */

/*
 * The argument L must be type BOOLEXP_CONST 
 */

static BOOLEXP *parse_boolexp_F(void)
{
    BOOLEXP *b2;

    skip_whitespace();
    switch (*parsebuf) {
    case NOT_TOKEN:
	parsebuf++;
	b2 = alloc_bool("parse_boolexp_F.not");
	b2->type = BOOLEXP_NOT;
	if ((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else
	    return (b2);
	/*
	 * NOTREACHED 
	 */
	break;
    case INDIR_TOKEN:
	parsebuf++;
	b2 = alloc_bool("parse_boolexp_F.indir");
	b2->type = BOOLEXP_INDIR;
	b2->sub1 = parse_boolexp_L();
	if ((b2->sub1) == TRUE_BOOLEXP) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else if ((b2->sub1->type) != BOOLEXP_CONST) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else
	    return (b2);
	/*
	 * NOTREACHED 
	 */
	break;
    case IS_TOKEN:
	parsebuf++;
	b2 = alloc_bool("parse_boolexp_F.is");
	b2->type = BOOLEXP_IS;
	b2->sub1 = parse_boolexp_L();
	if ((b2->sub1) == TRUE_BOOLEXP) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else if (((b2->sub1->type) != BOOLEXP_CONST) &&
	    ((b2->sub1->type) != BOOLEXP_ATR)) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else
	    return (b2);
	/*
	 * NOTREACHED 
	 */
	break;
    case CARRY_TOKEN:
	parsebuf++;
	b2 = alloc_bool("parse_boolexp_F.carry");
	b2->type = BOOLEXP_CARRY;
	b2->sub1 = parse_boolexp_L();
	if ((b2->sub1) == TRUE_BOOLEXP) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else if (((b2->sub1->type) != BOOLEXP_CONST) &&
	    ((b2->sub1->type) != BOOLEXP_ATR)) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else
	    return (b2);
	/*
	 * NOTREACHED 
	 */
	break;
    case OWNER_TOKEN:
	parsebuf++;
	b2 = alloc_bool("parse_boolexp_F.owner");
	b2->type = BOOLEXP_OWNER;
	b2->sub1 = parse_boolexp_L();
	if ((b2->sub1) == TRUE_BOOLEXP) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else if ((b2->sub1->type) != BOOLEXP_CONST) {
	    free_boolexp(b2);
	    return (TRUE_BOOLEXP);
	} else
	    return (b2);
	/*
	 * NOTREACHED 
	 */
	break;
    default:
	return (parse_boolexp_L());
    }
}

/*
 * T -> F; T -> F & T 
 */

static BOOLEXP *parse_boolexp_T(void)
{
    BOOLEXP *b, *b2;

    if ((b = parse_boolexp_F()) != TRUE_BOOLEXP) {
	skip_whitespace();
	if (*parsebuf == AND_TOKEN) {
	    parsebuf++;

	    b2 = alloc_bool("parse_boolexp_T");
	    b2->type = BOOLEXP_AND;
	    b2->sub1 = b;
	    if ((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) {
		free_boolexp(b2);
		return TRUE_BOOLEXP;
	    }
	    b = b2;
	}
    }
    return b;
}

/*
 * E -> T; E -> T | E 
 */

static BOOLEXP *parse_boolexp_E(void)
{
    BOOLEXP *b, *b2;

    if ((b = parse_boolexp_T()) != TRUE_BOOLEXP) {
	skip_whitespace();
	if (*parsebuf == OR_TOKEN) {
	    parsebuf++;

	    b2 = alloc_bool("parse_boolexp_E");
	    b2->type = BOOLEXP_OR;
	    b2->sub1 = b;
	    if ((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) {
		free_boolexp(b2);
		return TRUE_BOOLEXP;
	    }
	    b = b2;
	}
    }
    return b;
}

BOOLEXP *parse_boolexp(player, buf, internal)
dbref player;
const char *buf;
int internal;
{
    StringCopy(parsestore, buf);
    parsebuf = parsestore;
    parse_player = player;
    if ((buf == NULL) || (*buf == '\0'))
	return (TRUE_BOOLEXP);
#ifndef STANDALONE
    parsing_internal = internal;
#endif
    return parse_boolexp_E();
}