pennmush/game/data/
pennmush/game/log/
pennmush/game/save/
pennmush/game/txt/evt/
pennmush/game/txt/nws/
pennmush/os2/
pennmush/po/
pennmush/win32/msvc.net/
pennmush/win32/msvc6/
/**
 * \file utils.c
 *
 * \brief Utility functions for PennMUSH.
 *
 *
 */

#include "copyrite.h"
#include "config.h"

#include <stdio.h>
#include <limits.h>
#ifdef sgi
#include <math.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef I_SYS_TYPES
#include <sys/types.h>
#endif
#ifdef I_SYS_STAT
#include <sys/stat.h>
#endif
#include <fcntl.h>
#ifdef I_UNISTD
#include <unistd.h>
#endif
#ifdef WIN32
#include <wtypes.h>
#include <winbase.h>		/* For GetCurrentProcessId() */
#endif
#include "conf.h"

#include "match.h"
#include "externs.h"
#include "mushdb.h"
#include "mymalloc.h"
#include "log.h"
#include "flags.h"
#include "dbdefs.h"
#include "attrib.h"
#include "lock.h"
#include "confmagic.h"

dbref find_entrance(dbref door);
void initialize_mt(void);
static unsigned long genrand_int32(void);
static long genrand_int31(void);
static void init_genrand(unsigned long);
static void init_by_array(unsigned long *, int);

/** A malloc wrapper that tracks type of allocation.
 * This should be used in preference to malloc() when possible,
 * to enable memory leak tracing with MEM_CHECK.
 * \param size bytes to allocate.
 * \param check string to label allocation with.
 * \return allocated block of memory or NULL.
 */
Malloc_t
mush_malloc(size_t size, const char *check)
{
  Malloc_t ptr;
  add_check(check);
  ptr = malloc(size);
  if (ptr == NULL)
    do_log(LT_ERR, 0, 0, "mush_malloc failed to malloc %lu bytes for %s",
	   (unsigned long) size, check);
  return ptr;
}

/** A free wrapper that tracks type of allocation.
 * If mush_malloc() gets the memory, mush_free() should free it
 * to enable memory leak tracing with MEM_CHECK.
 * \param ptr pointer to block of member to free.
 * \param check string to label allocation with.
 */
void
mush_free(Malloc_t RESTRICT ptr, const char *RESTRICT check
	  __attribute__ ((__unused__)))
{
  del_check(check);
  free(ptr);
  return;
}


/** Parse object/attribute strings into components.
 * This function takes a string which is of the format obj/attr or attr,
 * and returns the dbref of the object, and a pointer to the attribute.
 * If no object is specified, then the dbref returned is the player's.
 * str is destructively modified. This function is probably underused.
 * \param player the default object.
 * \param str the string to parse.
 * \param thing pointer to dbref of object parsed out of string.
 * \param attrib pointer to pointer to attribute structure retrieved.
 */
void
parse_attrib(dbref player, char *str, dbref *thing, ATTR **attrib)
{
  char *name;

  /* find the object */

  if ((name = strchr(str, '/')) != NULL) {
    *name++ = '\0';
    *thing = noisy_match_result(player, str, NOTYPE, MAT_EVERYTHING);
  } else {
    name = str;
    *thing = player;
  }

  /* find the attribute */
  *attrib = (ATTR *) atr_get(*thing, upcasestr(name));
}

/** Parse an attribute or anonymous attribute into dbref and pointer.
 * This function takes a string which is of the format #lambda/code, 
 * <obj>/<attr> or <attr>,  and returns the dbref of the object, 
 * and a pointer to the attribute.
 * \param player the executor, for permissions checks.
 * \param str string to parse.
 * \param thing pointer to address to return dbref parsed, or NOTHING
 * if none could be parsed.
 * \param attrib pointer to address to return ATTR * of attrib parsed,
 * or NULL if none could be parsed.
 */
void
parse_anon_attrib(dbref player, char *str, dbref *thing, ATTR **attrib)
{

  if (string_prefix(str, "#lambda/")) {
    unsigned char *t;
    str += 8;
    if (!*str) {
      *attrib = NULL;
      *thing = NOTHING;
    } else {
      *attrib = mush_malloc(sizeof(ATTR), "anon_attr");
      AL_CREATOR(*attrib) = player;
      AL_NAME(*attrib) = strdup("#lambda");
      t = compress(str);
      (*attrib)->data = chunk_create(t, (u_int_16) u_strlen(t), 0);
      AL_FLAGS(*attrib) = AF_ANON;
      AL_NEXT(*attrib) = NULL;
      *thing = player;
      return;
    }
  }
  parse_attrib(player, str, thing, attrib);
}

/** Free the memory allocated for an anonymous attribute.
 * \param attrib pointer to attribute.
 */
void
free_anon_attrib(ATTR *attrib)
{
  if (attrib && (AL_FLAGS(attrib) & AF_ANON)) {
    free((char *) AL_NAME(attrib));
    chunk_delete(attrib->data);
    mush_free(attrib, "anon_attr");
  }
}

/** Given an exit, find the room that is its source through brute force.
 * This is used in pathological cases where the exit's own source
 * element is invalid.
 * \param door dbref of exit to find source of.
 * \return dbref of exit's source room, or NOTHING.
 */
dbref
find_entrance(dbref door)
{
  dbref room;
  dbref thing;
  for (room = 0; room < db_top; room++)
    if (IsRoom(room)) {
      thing = Exits(room);
      while (thing != NOTHING) {
	if (thing == door)
	  return room;
	thing = Next(thing);
      }
    }
  return NOTHING;
}

/** Remove the first occurence of what in chain headed by first.
 * This works for contents and exit chains.
 * \param first dbref of first object in chain.
 * \param what dbref of object to remove from chain.
 * \return new head of chain.
 */
dbref
remove_first(dbref first, dbref what)
{
  dbref prev;
  /* special case if it's the first one */
  if (first == what) {
    return Next(first);
  } else {
    /* have to find it */
    DOLIST(prev, first) {
      if (Next(prev) == what) {
	Next(prev) = Next(what);
	return first;
      }
    }
    return first;
  }
}

/** Is an object on a chain?
 * \param thing object to look for.
 * \param list head of chain to search.
 * \retval 1 found thing on list.
 * \retval 0 did not find thing on list.
 */
int
member(dbref thing, dbref list)
{
  DOLIST(list, list) {
    if (list == thing)
      return 1;
  }

  return 0;
}


/** Is an object inside another, at any level of depth?
 * That is, we check if disallow is inside of from, i.e., if 
 * loc(disallow) = from, or loc(loc(disallow)) = from, etc., with a 
 * depth limit of 50.
 * Despite the name of this function, it's not recursive any more.
 * \param disallow interior object to check.
 * \param from check if disallow is inside of this object.
 * \param count depths of nesting checked so far.
 * \retval 1 disallow is inside of from.
 * \retval 0 disallow is not inside of from.
 */
int
recursive_member(dbref disallow, dbref from, int count)
{
  do {
    /* The end of the location chain. This is a room. */
    if (!GoodObject(disallow) || IsRoom(disallow))
      return 0;

    if (from == disallow)
      return 1;

    disallow = Location(disallow);
    count++;
  } while (count <= 50);

  return 1;
}

/** Is an object or its location unfindable?
 * \param thing object to check.
 * \retval 1 object or location is unfindable.
 * \retval 0 neither object nor location is unfindable.
 */
int
unfindable(dbref thing)
{
  int count = 0;
  do {
    if (!GoodObject(thing))
      return 0;
    if (Unfind(thing))
      return 1;
    if (IsRoom(thing))
      return 0;
    thing = Location(thing);
    count++;
  } while (count <= 50);
  return 0;
}


/** Reverse the order of a dbref chain.
 * \param list dbref at the head of the chain.
 * \return dbref at the head of the reversed chain.
 */
dbref
reverse(dbref list)
{
  dbref newlist;
  dbref rest;
  newlist = NOTHING;
  while (list != NOTHING) {
    rest = Next(list);
    PUSH(list, newlist);
    list = rest;
  }
  return newlist;
}


#define N 624 /**< PRNG constant */

/* We use the Mersenne Twister PRNG. It's quite good as PRNGS go,
 * much better than the typical ones provided in system libc's.
 *
 * The following two functions are based on the reference implementation,
 * with changes in the seeding function to use /dev/urandom as a seed
 * if possible.
 *
 * The Mersenne Twister homepage is:
 *  http://www.math.keio.ac.jp/~matumoto/emt.html
 *
 * You can get the reference code there.
 */


/** Wrapper to choose a seed and initialize the Mersenne Twister PRNG. */
void
initialize_mt(void)
{
#ifdef HAS_DEV_URANDOM
  int fd;
  unsigned long buf[N];

  fd = open("/dev/urandom", O_RDONLY);
  if (fd >= 0) {
    int r = read(fd, buf, sizeof buf);
    close(fd);
    if (r <= 0) {
      do_rawlog(LT_ERR,
		"Couldn't read from /dev/urandom! Resorting to normal seeding method.");
    } else {
      do_rawlog(LT_ERR, "Seeded RNG from /dev/urandom");
      init_by_array(buf, r / sizeof(unsigned long));
      return;
    }
  } else
    do_rawlog(LT_ERR,
	      "Couldn't open /dev/urandom to seed random number generator. Resorting to normal seeding method.");

#endif
  /* Default seeder. Pick a seed that's fairly random */
#ifdef WIN32
  init_genrand(GetCurrentProcessId() | (time(NULL) << 16));
#else
  init_genrand(getpid() | (time(NULL) << 16));
#endif
}


/* A C-program for MT19937, with initialization improved 2002/1/26.*/
/* Coded by Takuji Nishimura and Makoto Matsumoto.                 */

/* Before using, initialize the state by using init_genrand(seed)  */
/* or init_by_array(init_key, key_length).                         */

/* This library is free software.                                  */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of  */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.            */

/* Copyright (C) 1997, 2002 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome.                                   */
/* http://www.math.keio.ac.jp/matumoto/emt.html                    */
/* email: matumoto@math.keio.ac.jp                                 */

/* Period parameters */
#define M 397  /**< PRNG constant */
#define MATRIX_A 0x9908b0dfUL	/**< PRNG constant vector a */
#define UPPER_MASK 0x80000000UL	/**< PRNG most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL	/**< PRNG least significant r bits */

static unsigned long mt[N];	/* the array for the state vector  */
static int mti = N + 1;		/* mti==N+1 means mt[N] is not initialized */

/** initializes mt[N] with a seed.
 * \param a seed value.
 */
static void
init_genrand(unsigned long s)
{
  mt[0] = s & 0xffffffffUL;
  for (mti = 1; mti < N; mti++) {
    mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
    /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
    /* In the previous versions, MSBs of the seed affect   */
    /* only MSBs of the array mt[].                        */
    /* 2002/01/09 modified by Makoto Matsumoto             */
    mt[mti] &= 0xffffffffUL;
    /* for >32 bit machines */
  }
}

/** initialize by an array with array-length
 * \param init_key the array for initializing keys 
 * \param key_length the array's length 
 */
static void
init_by_array(unsigned long init_key[], int key_length)
{
  int i, j, k;
  init_genrand(19650218UL);
  i = 1;
  j = 0;
  k = (N > key_length ? N : key_length);
  for (; k; k--) {
    mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL))
      + init_key[j] + j;	/* non linear */
    mt[i] &= 0xffffffffUL;	/* for WORDSIZE > 32 machines */
    i++;
    j++;
    if (i >= N) {
      mt[0] = mt[N - 1];
      i = 1;
    }
    if (j >= key_length)
      j = 0;
  }
  for (k = N - 1; k; k--) {
    mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL))
      - i;			/* non linear */
    mt[i] &= 0xffffffffUL;	/* for WORDSIZE > 32 machines */
    i++;
    if (i >= N) {
      mt[0] = mt[N - 1];
      i = 1;
    }
  }

  mt[0] = 0x80000000UL;		/* MSB is 1; assuring non-zero initial array */
}

/* generates a random number on [0,0xffffffff]-interval */
static unsigned long
genrand_int32(void)
{
  unsigned long y;
  static unsigned long mag01[2] = { 0x0UL, MATRIX_A };
  /* mag01[x] = x * MATRIX_A  for x=0,1 */

  if (mti >= N) {		/* generate N words at one time */
    int kk;

    if (mti == N + 1)		/* if init_genrand() has not been called, */
      init_genrand(5489UL);	/* a default initial seed is used */

    for (kk = 0; kk < N - M; kk++) {
      y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
      mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
    }
    for (; kk < N - 1; kk++) {
      y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
      mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
    }
    y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
    mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];

    mti = 0;
  }

  y = mt[mti++];

  /* Tempering */
  y ^= (y >> 11);
  y ^= (y << 7) & 0x9d2c5680UL;
  y ^= (y << 15) & 0xefc60000UL;
  y ^= (y >> 18);

  return y;
}

/* generates a random number on [0,0x7fffffff]-interval */
static long
genrand_int31(void)
{
  return (long) (genrand_int32() >> 1);
}

/** Get a uniform random long between low and high values, inclusive.
 * Based on MUX's RandomINT32()
 * \param low lower bound for random number.
 * \param high upper bound for random number.
 * \return random number between low and high, or 0 or -1 for error.
 */
long
get_random_long(long low, long high)
{
  unsigned long x, n, n_limit;

  /* Validate parameters */
  if (high < low) {
    return 0;
  } else if (high == low) {
    return low;
  }

  x = high - low;
  if (LONG_MAX < x) {
    return -1;
  }
  x++;

  /* We can now look for an random number on the interval [0,x-1].
     //

     // In order to be perfectly conservative about not introducing any
     // further sources of statistical bias, we're going to call getrand()
     // until we get a number less than the greatest representable
     // multiple of x. We'll then return n mod x.
     //
     // N.B. This loop happens in randomized constant time, and pretty
     // damn fast randomized constant time too, since
     //
     //      P(UINT32_MAX_VALUE - n < UINT32_MAX_VALUE % x) < 0.5, for any x.
     //
     // So even for the least desireable x, the average number of times
     // we will call getrand() is less than 2.
   */

  n_limit = ULONG_MAX - (ULONG_MAX % x);

  do {
    n = genrand_int31();
  } while (n >= n_limit);

  return low + (n % x);
}

/** Return an object's name, but for exits, return just the first
 * component. We expect a valid object.
 * \param it dbref of object.
 * \return object's short name.
 */
char *
shortname(dbref it)
{
  static char n[BUFFER_LEN];	/* STATIC */
  char *s;

  strncpy(n, Name(it), BUFFER_LEN - 1);
  n[BUFFER_LEN - 1] = '\0';
  if (IsExit(it)) {
    if ((s = strchr(n, ';')))
      *s = '\0';
  }
  return n;
}

/** Return the absolute room (outermost container) of an object.
 * Return  NOTHING if it's in an invalid object or in an invalid
 * location or AMBIGUOUS if there are too many containers.
 * \param it dbref of object.
 * \return absolute room of object, NOTHING, or AMBIGUOUS.
 */
dbref
absolute_room(dbref it)
{
  int rec = 0;
  dbref room;
  if (!GoodObject(it))
    return NOTHING;
  room = Location(it);
  if (!GoodObject(room))
    return NOTHING;
  while (!IsRoom(room)) {
    room = Location(room);
    rec++;
    if (rec > 20)
      return AMBIGUOUS;
  }
  return room;
}


/** Can one object interact with/perceive another in a given way?
 * This funtion checks to see if 'to' can perceive something from
 * 'from'. The types of interactions currently supported include:
 * INTERACT_SEE (will light rays from 'from' reach 'to'?), INTERACT_HEAR
 * (will sound from 'from' reach 'to'?), INTERACT_MATCH (can 'to'
 * match the name of 'from'?), and INTERACT_PRESENCE (will the arrival/
 * departure/connection/disconnection/growing ears/losing ears of 
 * 'from' be noticed by 'to'?).
 * \param from object of interaction.
 * \param to subject of interaction, attempting to interact with from.
 * \param type type of interaction.
 * \retval 1 to can interact with from in this way.
 * \retval 0 to can not interact with from in this way.
 */
int
can_interact(dbref from, dbref to, int type)
{
  int lci;

  /* This shouldn't even be checked for rooms and garbage, but we're
   * paranoid. Trying to stop interaction with yourself will not work 99%
   * of the time, so we don't allow it anyway. */
  if (IsGarbage(from) || IsGarbage(to))
    return 0;

  if ((from == to) || IsRoom(from) || IsRoom(to))
    return 1;

  /* This function can override standard checks! */
  lci = local_can_interact_first(from, to, type);
  if (lci != NOTHING)
    return lci;

  /* Standard checks */

  /* If it's an audible message, it must pass your Interact_Lock
   * (or be from a privileged speaker)
   */
  if ((type == INTERACT_HEAR) && !Pemit_All(from)
      && !eval_lock(from, to, Interact_Lock))
    return 0;

  /* You can interact with the object you are in or any objects
   * you're holding.
   * You can interact with objects you control, but not
   * specifically the other way around
   */
  if ((from == Location(to)) || (to == Location(from)) || controls(to, from))
    return 1;


  lci = local_can_interact_last(from, to, type);
  if (lci != NOTHING)
    return lci;

  return 1;
}