untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
/*
    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);

}