pennmush/game/
pennmush/game/data/
pennmush/game/log/
pennmush/game/save/
pennmush/game/txt/evt/
pennmush/game/txt/nws/
pennmush/os2/
/* utils.c */

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

#include <stdio.h>
#include <limits.h>
#ifdef sgi
#include <math.h>
#endif
#ifdef HAS_SIGACTION
#include <signal.h>
#endif
#ifdef I_STDLIB
#include <stdlib.h>
#endif
#ifdef I_STRING
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>


#include "conf.h"
#include "intrface.h"
#ifdef MEM_CHECK
#include "memcheck.h"
#endif
#include "match.h"
#include "externs.h"
#include "mushdb.h"
#include "mymalloc.h"
#include "confmagic.h"


extern ATTR *atr_get _((dbref thing, const char *atr));
extern char *upcasestr _((char *s));

#ifdef HAS_SIGACTION
#ifdef signal
#undef signal
#endif
Sigfunc signal _((int signo, Sigfunc func));
#endif

void parse_attrib _((dbref player, char *str, dbref *thing, ATTR **attrib));
dbref find_entrance _((dbref door));
dbref remove_first _((dbref first, dbref what));
int member _((dbref thing, dbref list));
int recursive_member _((dbref disallow, dbref from, int count));
dbref reverse _((dbref list));
struct dblist *listcreate _((dbref ref));
void listadd _((struct dblist * head, dbref ref));
void listfree _((struct dblist * head));
int getrandom _((int x));
Malloc_t mush_malloc _((int size, const char *check));
void mush_free _((Malloc_t ptr, const char *check));
char *shortname _((dbref it));

Malloc_t
mush_malloc(size, check)
    int size;
    const char *check;
{
  Malloc_t ptr;
#ifdef MEM_CHECK
  add_check(check);
#endif
  ptr = malloc(size);
  if (ptr == NULL)
    do_log(LT_ERR, 0, 0, "mush_malloc failed to malloc %d bytes for %s",
	   size, check);
  return ptr;
}

void
mush_free(ptr, check)
    Malloc_t ptr;
    const char *check;
{
#ifdef MEM_CHECK
  del_check(check);
#endif
  free(ptr);
  ptr = NULL;
  return;
}


void
parse_attrib(player, str, thing, attrib)
    dbref player;
    char *str;
    dbref *thing;
    ATTR **attrib;
{
  /* 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.
   */

  char *name;

  /* find the object */

  if ((name = (char *) index(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));
}


dbref
find_entrance(door)
    dbref door;
{
  dbref room;
  dbref thing;
  for (room = 0; room < db_top; room++)
    if (Typeof(room) == TYPE_ROOM) {
      thing = db[room].exits;
      while (thing != NOTHING) {
	if (thing == door)
	  return room;
	thing = db[thing].next;
      }
    }
  return NOTHING;
}

/* remove the first occurence of what in list headed by first */
dbref
remove_first(first, what)
    dbref first;
    dbref what;
{
  dbref prev;
  /* special case if it's the first one */
  if (first == what) {
    return db[first].next;
  } else {
    /* have to find it */
    DOLIST(prev, first) {
      if (db[prev].next == what) {
	db[prev].next = db[what].next;
	return first;
      }
    }
    return first;
  }
}

int
member(thing, list)
    dbref thing;
    dbref list;
{
  DOLIST(list, list) {
    if (list == thing)
      return 1;
  }

  return 0;
}


/* Return 1 if disallow is inside of from, i.e., if loc(disallow) = from,
 * or loc(loc(disallow)) = from, etc.
 * Actually, it's not recursive any more.
 */
int
recursive_member(disallow, from, count)
    dbref disallow;
    dbref from;
    int count;
{
  do {
    /* The end of the location chain. This is a room. */
    if (!GoodObject(disallow) || (Typeof(disallow) == TYPE_ROOM))
      return 0;

    if (from == disallow)
      return 1;

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

  return 1;
}

dbref
reverse(list)
    dbref list;
{
  dbref newlist;
  dbref rest;
  newlist = NOTHING;
  while (list != NOTHING) {
    rest = db[list].next;
    PUSH(list, newlist);
    list = rest;
  }
  return newlist;
}

/* takes a dbref and returns a pointer to the head of a dblist */
struct dblist *
listcreate(ref)
    dbref ref;
{
  struct dblist *ptr;

  ptr = (struct dblist *) mush_malloc((unsigned) sizeof(struct dblist), "dblist");
  if (!ptr)
    panic("Out of memory.");
  ptr->obj = ref;
  ptr->next = NULL;
  return (ptr);
}

/*
 * takes a pointer to a dblist and a dbref and adds the dbref to the
 * end of the list.
 */
void
listadd(head, ref)
    struct dblist *head;
    dbref ref;
{
  struct dblist *ptr = head;


  while (ptr->next)
    ptr = ptr->next;

  ptr->next = listcreate(ref);
}

/* takes a pointer to a dblist and recursively frees it */
void
listfree(head)
    struct dblist *head;
{
  struct dblist *ptra = head, *ptrb;

  while (ptra->next) {
    ptrb = ptra->next;
    mush_free((Malloc_t) ptra, "dblist");
    ptra = ptrb;
  }
}


int
getrandom(x)
    int x;
{
  /* In order to be perfectly anal about not introducing any further sources
   * of statistical bias, we're going to call random() until we get a number
   * less than the greatest representable multiple of x. We'll then return
   * n mod x.
   */
  long n;
  if (x <= 0)
    return -1;
  do {
    n = random();
  } while (LONG_MAX - n < LONG_MAX % x);
  /* N.B. This loop happens in randomized constant time, and pretty damn
   * fast randomized constant time too, since P(LONG_MAX - n < LONG_MAX % x)
   * < 0.5 for any x, so for any X, the average number of times we should
   * have to call random() is less than 2.
   */
  return (n % x);
}



#ifdef HAS_SIGACTION
/* We're going to rewrite the signal() function in terms of
 * sigaction, where available, to ensure consistent semantics.
 * We want signal handlers to remain installed, and we want
 * signals (except SIGALRM) to restart system calls which they
 * interrupt. This is how bsd signals work, and what we'd like.
 * This function is essentially example 10.12 from Stevens'
 * _Advanced Programming in the Unix Environment_
 */
Sigfunc
signal(signo, func)
    int signo;
    Sigfunc func;
{
  struct sigaction act, oact;
  act.sa_handler = func;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
#ifdef NEVER
  /* In Steven's original routine, he didn't want to restart
   * system calls after sigalarm. That seems wrong for our
   * application.
   */
  if (signo = SIGALRM) {
#ifdef SA_INTERRUPT
    /* SunOS restarts signals by default unless you add this */
    act.sa_flags |= SA_INTERRUPT;
#endif
  } else {
#endif				/* NEVER */
#ifdef SA_RESTART
    act.sa_flags |= SA_RESTART;
#endif
#ifdef NEVER
  }
#endif				/* NEVER */
  if (sigaction(signo, &act, &oact) < 0)
    return (SIG_ERR);
  return (oact.sa_handler);
}
#endif				/* HAS_SIGACTION */


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

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