dmuck0.15-beta/docs/muf/
dmuck0.15-beta/game/
dmuck0.15-beta/game/logs/
dmuck0.15-beta/game/muf/
dmuck0.15-beta/game/muf/text/
#include "copyright.h"
#include "config.h"

#include <ctype.h>

#include "db.h"
#include "match.h"
#include "externs.h"
#include "params.h"
#include "interface.h"

/* Lachesis note on the routines in this package:
 *   eval_booexp does just evaluation.
 *
 *   parse_boolexp makes potentially recursive calls to several different
 *   subroutines ---
 *          parse_boolexp_F
 *            This routine does the leaf level parsing and the NOT.
 *        parse_boolexp_E
 *            This routine does the ORs.
 *        parse_boolexp_T
 *            This routine does the ANDs.
 *
 *   Because property expressions are leaf level expressions, I have only
 *   touched eval_boolexp_F, asking it to call my additional parse_boolprop()
 *   routine.
 */

int eval_boolexp(dbref player, boolexp *b, dbref thing)
{
  frame *fr;
  int result;
  
  if(b == TRUE_BOOLEXP) return 1;
  else
  {
    switch(b->type)
    {
      case BOOLEXP_AND:
        return (eval_boolexp(player, b->sub1, thing)
          && eval_boolexp(player, b->sub2, thing));
      case BOOLEXP_OR:
        return (eval_boolexp(player, b->sub1, thing)
          || eval_boolexp(player, b->sub2, thing));
      case BOOLEXP_NOT:
        return !eval_boolexp(player, b->sub1, thing);
      case BOOLEXP_CONST:
        if (Typeof(b ->thing) == TYPE_PROGRAM)
        {
	  fr = new_frame(player, b->thing, thing, DBFETCH(player)->location, 1);
	  result = run_frame(fr, 1);
	  if (fr && (fr->status != STATUS_SLEEP)) free_frame(fr);
          return result;
        }
        return (b->thing == player
          || member(b->thing, DBFETCH(player)->contents)
          || b->thing == DBFETCH(player)->location);
      case BOOLEXP_PROP:
        return(has_property(player, b->prop_name,
          b->prop_data, access_rights(player, player, NOTHING)));
      default:
        abort();           /* bad type */
    }
  }
}

boolexp *copy_bool(boolexp *old)
{
  boolexp *o = (boolexp *)malloc(sizeof(boolexp));
  
  if (!old || !o) return 0;
  
  o->type = old->type;
  
  switch (old ->type)
  {
    case BOOLEXP_AND:
    case BOOLEXP_OR:
      o->sub1 = copy_bool(old->sub1);
      o->sub2 = copy_bool(old->sub2);
      break;
    case BOOLEXP_NOT:
      o->sub1 = copy_bool(old->sub1);
      break;
    case BOOLEXP_CONST:
      o->thing = old->thing;
      break;
    case BOOLEXP_PROP:
      o->prop_name = dup_string(old->prop_name);
      o->prop_data = dup_string(old->prop_data);
      break;
    default:
      log_status("PANIC: copy_boolexp: Error in boolexp!\n");
      abort();
  }
  return o;
}

/* If the parser returns TRUE_BOOLEXP, you lose */
/* TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead */
static char *parsebuf;
static dbref parse_player;

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

static boolexp *parse_boolexp_E(void); /* defined below */
static boolexp *parse_boolprop(char *buf); /* defined below */

/* F -> (E); F -> !F; F -> object identifier */
static boolexp *parse_boolexp_F()
{
  boolexp *b;
  char *p;
  match_data md;
  char buf[BUFFER_LEN];
  char msg[BUFFER_LEN];
  
  skip_whitespace();
  switch(*parsebuf)
  {
    case '(':
      parsebuf++;
      b = parse_boolexp_E();
      skip_whitespace();
      if(b == TRUE_BOOLEXP || *parsebuf++ != ')')
      {
        free_boolexp(b);
        return TRUE_BOOLEXP;
      }
      else
        return b;
    case NOT_TOKEN:
      parsebuf++;
      b = (boolexp *) malloc(sizeof(boolexp));
      b->type = BOOLEXP_NOT;
      b->sub1 = parse_boolexp_F();
      if(b->sub1 == TRUE_BOOLEXP)
      {
        free((void *) b);
        return TRUE_BOOLEXP;
      }
      else
        return b;
    default:
      /* must have hit an object ref */
      /* load the name into our buffer */
      p = buf;
      while(*parsebuf && *parsebuf != AND_TOKEN && *parsebuf != OR_TOKEN
        && *parsebuf != ')')
        *p++ = *parsebuf++;
      /* strip trailing whitespace */
      *p-- = '\0';
      while(isspace(*p)) *p-- = '\0';
    
      /* check to see if this is a property expression */
      if (index(buf, PROP_DELIMITER)) return parse_boolprop(buf);
    
      b = (boolexp *)malloc(sizeof(boolexp));
      b->type = BOOLEXP_CONST;
    
      if (strcmp(buf, "#-1") && string_compare(buf, "nothing"))
      {
        /* do the match */
        init_match(parse_player, buf, TYPE_THING, &md);
        match_neighbor(&md);
        match_possession(&md);
        match_me(&md);
        match_here(&md);
        match_absolute(&md);
        match_player(&md);
    
        if((b->thing = match_result(&md)) == NOTHING)
        {
          sprintf(msg, "I don't see %s here.", buf);
          notify(parse_player, parse_player, msg);
          free(b);
          return TRUE_BOOLEXP;
        }
        else if(b->thing == AMBIGUOUS)
        {
          sprintf(msg, "I don't know which %s you mean!", buf);
          notify(parse_player, parse_player, msg);
          free(b);
          return TRUE_BOOLEXP;
        }
        else return b;
      }
      else
      {
        b = (boolexp *)malloc(sizeof(boolexp));
        b->type = BOOLEXP_CONST;
        b->thing = NOTHING;
        return b;
      }
  }
}

/* T -> F; T -> F & T */
static boolexp *parse_boolexp_T()
{
  boolexp *b;
  boolexp *b2;
  
  if((b = parse_boolexp_F()) == TRUE_BOOLEXP)
    return b;
  else
  {
    skip_whitespace();
    if(*parsebuf == AND_TOKEN)
    {
      parsebuf++;
      
      b2 = (boolexp *) malloc(sizeof(boolexp));
      b2->type = BOOLEXP_AND;
      b2->sub1 = b;
      if((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP)
      {
        free_boolexp(b2);
        return TRUE_BOOLEXP;
      }
      else return b2;
    }
    else return b;
  }
}

/* E -> T; E -> T | E */
static boolexp *parse_boolexp_E()
{
  boolexp *b;
  boolexp *b2;
  
  if((b = parse_boolexp_T()) == TRUE_BOOLEXP)
    return b;
  else
  {
    skip_whitespace();
    if(*parsebuf == OR_TOKEN)
    {
      parsebuf++;
      
      b2 = (boolexp *) malloc(sizeof(boolexp));
      b2->type = BOOLEXP_OR;
      b2->sub1 = b;
      if((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP)
      {
        free_boolexp(b2);
        return TRUE_BOOLEXP;
      }
      else return b2;
    }
    else return b;
  }
}

boolexp *parse_boolexp(dbref player, char *buf)
{
  parsebuf = buf;
  parse_player = player;
  return parse_boolexp_E();
}

/* parse a property expression
   If this gets changed, please also remember to modify set.c       */
static boolexp *parse_boolprop(char *buf)
{
  char *type, *class, *x, *temp;
  boolexp *b;

  x = type = dup_string(buf);
  class = (char *)strchr(type, PROP_DELIMITER);
  b = (boolexp *)malloc(sizeof(boolexp));
  b->type = BOOLEXP_PROP;
  b->sub1 = b->sub2 = 0;
  b->thing = NOTHING;
  while (isspace(*type) && (*type != PROP_DELIMITER)) type++;
  if (*type == PROP_DELIMITER)
  {
    /* Oops!  No property name!  Clean up and return true. */
    free(x);
    free(b);
    return TRUE_BOOLEXP;
  }
  /* get rid of trailing spaces */
  for (temp = class - 1; isspace(*temp); temp --);
  temp++;
  *temp = '\0';
  class++;
  /* skip over leading spaces */
  while (isspace(*class) && *class) class++;
  for(temp = class + strlen(class); isspace(*temp); temp--);
  temp++;
  if (isspace(*temp)) *temp = '\0';
  if (!*class)
  {
    /* Oops!  No property data!  Clean up and return true. */
    free(x);
    free(b);
    return TRUE_BOOLEXP;
  }
  b->prop_name = dup_string(type);
  b->prop_data = dup_string(class);
  free(x);
  return b;
}

/* boolean expression dbref global search and replace   */
/* To be used in copies, shifts, etc for sanity et. al. */

void bool_dgsr(boolexp *lock, dbref old, dbref new)
{
  switch (lock->type)
  {
    case BOOLEXP_AND:
    case BOOLEXP_OR:
      bool_dgsr(lock->sub1, old, new);
      bool_dgsr(lock->sub2, old, new);
      break;
    case BOOLEXP_NOT:
      bool_dgsr(lock->sub1, old, new);
      break;
    case BOOLEXP_CONST:
      if (lock->thing == old) lock->thing = new;
      break;
    case BOOLEXP_PROP:
      break;
    default:
      log_status("PANIC: bool_dgsr: Error in boolexp!\n");
      abort();
   }
}

void sanitize_lock(boolexp *lock)
{
  if (lock != NULL)
  switch (lock->type)
  {
    case BOOLEXP_AND:
    case BOOLEXP_OR:
      sanitize_lock(lock->sub1);
      sanitize_lock(lock->sub2);
      break;
    case BOOLEXP_NOT:
      sanitize_lock(lock->sub1);
      break;
    case BOOLEXP_CONST:
      if (lock->thing < (dbref) 0 || lock->thing >= db_top)
	lock->thing = HOME;
	/* well, it was better than NOTHING */
      break;
    case BOOLEXP_PROP:
      break;
    default:
      log_status("PANIC: sanitize_lock: Error in boolexp!\n");
      abort();
   }
}