cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
#ifndef _UTILS_H
#define _UTILS_H

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#ifndef _OLD_LINUX_
  #include <crypt.h>
#endif
#include "kernel.h"
#include "utils.h"
#include "errno.h"
#include "log.h"

int makesock(char *addr, int port) {
  int s /*, opt */;
  struct sockaddr_in client;
  
  client.sin_family = AF_INET;
  client.sin_port = htons(port);
  client.sin_addr.s_addr = inet_addr(addr);

  if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    return(-1);
  fcntl(s, F_SETFL, O_NONBLOCK);

 /* opt = 1;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); */

  if (connect(s, (struct sockaddr *) &client, sizeof(client)) == -1)
    if (errno != EINPROGRESS) {
      close(s);
      return(-1);
    }
  return(s);
}

void read_line(char *target, int len, FILE *file) {
  int i;

  fgets( target, len, file );
  for( i = 0; i < len && target[i] != '\n'; i++ )
	;
  target[i] = '\0';
  return;
}

char *strcasestr (char *s1, char *s2) {
  static char n1[MAX_COM_LEN * 2], n2[MAX_COM_LEN * 2];
  int j;

  for (j = 0 ; s1[j] != '\0' ; j++)
    n1[j] = tolower (s1[j]);
  n1[j] = '\0';

  for (j = 0 ; s2[j] != '\0' ; j++)
    n2[j] = tolower (s2[j]);
  n2[j] = '\0';

  return (strstr (n1, n2));
}

int fnumlines (char file[200]) {
  FILE *fp;
  char tmp[300];
  int num = 0;

  if ((fp = fopen(file, "rt")) == NULL)
    return -1;

  while (fgets (tmp, sizeof (tmp), fp))
    num++;
  fclose (fp);
  return num;
}

void fileseek (FILE * file, int lines) {
  char tmp[300];
  int loc;

  fseek (file, 0L, SEEK_SET);
  for (loc = 0; loc < lines; loc++)
    fgets (tmp, sizeof (tmp), file);
}

/* is this a valid filename? (letters only, no ..'s to change path) */

Boolean valid_fname(char *name) {
  char *ptr;

  if (!(*name))
    return(False);

  for (ptr = name ; isalpha(*ptr) ; ptr++);
  if (!(*ptr))
    return(True);
  else
    return (False);
}

void add_tree(T_elemptr *tree, char *s, int num) {
  T_elemptr newptr, ptr;

  newptr = (T_elemptr) NEW(T_elem, 1);
  newptr->num = num;
  newptr->str = (char *) NEW(char, (strlen(s) + 1));
  strcpy(newptr->str, s);
  newptr->right = newptr->left = NULL;

  if (*tree == NULL)                             /* make root node */
    *tree = newptr;
  else {
    ptr = *tree;
    while (1) {
      if (strcmp(s, ptr->str) < 0) {
	if (ptr->left == NULL) {              /* a left leaf on the tree */
            ptr->left = newptr;
            break;
	}
          else
            ptr = ptr->left;
      }
      else if (strcmp(s, ptr->str) > 0) {
	if (ptr->right == NULL) {            /* a right leaf on the tree */
            ptr->right = newptr;
            break;
	}
          else
            ptr = ptr->right;
      }
        else                                   /* node already exists */
          return;
    }
  }
}

int tree_lookup(T_elemptr tree, char *s) {
  T_elemptr ptr = tree;

  while (ptr != NULL) {
    if (strncmp(s, ptr->str, strlen(s)) < 0)
      ptr = ptr->left;
    else if (strncmp(s, ptr->str, strlen(s)) > 0)
      ptr = ptr->right;
    else                                      /* ptr == s */
      return ptr->num;
  }
  return -1;
}


Boolean int_is_on_table(int *table, int object) {
  int i;

  for (i = 0; table[i] != -1; i++) 
    if (table[i] == object)
      return True;

  return False;
}

/* matches wildcards on p in the form of <*blah> and <blah*> */

Boolean match (char *a, const char *b) {
  char *ptr, p[100], q[100];
  int len;

  strcpy(p, a);                               /* ignore case */
  strcpy(q, b);
  for (ptr = p ; *ptr ; ptr++)
    *ptr = tolower(*ptr);
  for (ptr = q ; *ptr ; ptr++)
    *ptr = tolower(*ptr);

  len = strlen(p);
  if (*(p + len - 1) == '\n') {               /* remove newline */
    *(p + len - 1) = 0;
    len--;
  }
  if (*p == '*') {                            /* (*blah) */
    ptr = strstr(q, p + 1);
    if (ptr && strlen(ptr) == len - 1)        /* lengths match */
      return True;
  }
  else if (*(p + len - 1) == '*') {           /* (blah*) */
    *(p + len) = 0;
    if (!strncmp(q, p, len - 1))
      return True;
  }
  else if (!strcmp(q, p))
    return True;
  return False;
}

#ifdef SYS_EQBUG
/*
 * Copyright (c) 1987 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of California at Berkeley. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific written prior permission. This software
 * is provided ``as is'' without express or implied warranty.
 */

/*
 * This array is designed for mapping upper and lower case letter
 * together for a case independent comparison.  The mappings are
 * based upon ascii character sequences.
 */
static u_char charmap[] =
{
  '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
  '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
  '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
  '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
  '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
  '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
  '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
  '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
  '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
  '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
  '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
  '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
  '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
  '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
  '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
  '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
  '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
  '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
  '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
  '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};

int
strcasecmp (char *s1, char *s2)
{
  register u_char *cm = charmap, *us1 = (u_char *) s1, *us2 = (u_char *) s2;

  while (cm[*us1] == cm[*us2++])
    if (*us1++ == '\0')
      return (0);
  return (cm[*us1] - cm[*--us2]);
}

int
strncasecmp (const char *s1, const char *s2, register size_t n)
{
  register u_char *cm = charmap, *us1 = (u_char *) s1, *us2 = (u_char *) s2;

  while (--n >= 0 && cm[*us1] == cm[*us2++])
    if (*us1++ == '\0')
      return (0);
  return (n < 0 ? 0 : cm[*us1] - cm[*--us2]);
}

/*
 * **  END OF BERKELEY INCLUDE
 */
#endif


int glookup (char *elem, int n, char **table,
	     int (*strcmpfun) (const char *s1, const char *s2, size_t n)) {
  char **t;
  int x;

  for (t = table, x = 0; *t != TABLE_END; ++t, ++x) {
    if (*t == NULL)
      continue;
    if (strcmpfun (elem, *t, n) == 0)
      return x;
  }
  return (-1);
}

int xstrcasecmp (const char *s1, const char *s2, size_t n) {
  return strcasecmp (s1, s2);
}

char *lowercase (char *str) {
  char *p;

  for (p = str; *p; p++)
    if (isupper(*p))
      *p = tolower(*p);
  return str;
}

char *uppercase (char *str) {
  char *p;

  for (p = str; *p; p++)
    if (islower (*p))
      *p = toupper (*p);
  return str;
}

void *xmalloc (int nelem, int elem_size) {
  void *p;

  if ((p = calloc (nelem, elem_size)) == NULL) {
    printf ("No room to allocate bytes.\n");
    exit(1);
  }
  return p;
}

/* Should be identical to the one in config.c */

char *my_crypt (char *buf, char *pw) {
  char *s = crypt (pw, "Mu");
  *(s + PASSWD_LEN - strlen(PASSWD_PREFIX) - 1) = 0;
  sprintf(buf, "%s%s", PASSWD_PREFIX, s);
  return(buf);
}

void *resize_array (void *start, int elem_size, int oldlen, int newlen) {
  void *p = NULL;

  if (oldlen < 0 || newlen < 0)
    return(NULL);

  if (newlen != 0)
    p = calloc(newlen, elem_size);

  if (start != NULL) {
    if (newlen != 0)
      memcpy (p, start, min (oldlen, newlen) * elem_size);
    FREE (start);
  }
  return p;
}

void init_intset (int_set * p, int len) {
  p->len = 0;
  p->list = NEW(int, len);
  p->maxlen = len;
}

void free_intset (int_set * p) {
  if (p->list != NULL)
    FREE (p->list);
}

Boolean add_int (int n, int_set * p) {
  int i;

  check_for_possible_resize(p);

  for (i = 0; i < p->len; i++)
    if (p->list[i] == n)
      return(False);

  p->list[p->len] = n;
  p->len++;
  return(True);
}

Boolean remove_int(int n, int_set * p) {
  int i;

  if (p->list == NULL || p->len == 0)
    return False;

  for (i = 0; p->list[i] != n; i++)
    if (i == p->len)                  /* no int found */
      return(False);

  p->list[i] = p->list[p->len - 1];   /* copy last elem to deleted elem */
  (p->len)--;                         /* make list shorter */

  check_for_possible_resize(p);
  return(True);
}


int find_int (int n, int_set * p) {
  int i;

  if (p->list == NULL)
    return -1;

  for (i = 0; i < p->len && p->list[i] != n; i++) ;

  return i < p->len ? i + 1 : 0;
}

int foreach_int (int_set * p, int (*func) (int)) {
  int i;
  int n = 0;

  for (i = 0; i < p->len; i++)
    if (func (p->list[i]))
      n++;

  return n;
}

Boolean check_for_possible_resize (int_set * p) {
  int oldlen = p->maxlen;

  if (p->len == p->maxlen)
    p->maxlen = p->len < 20 ? 2 * (p->len + 1) : p->len + 25;
  else if (p->maxlen > 0 && p->len < p->maxlen / 5)
    p->maxlen /= 2;
  else
    return False;

  p->list = resize_array (p->list, sizeof (int), oldlen, p->maxlen);

  return True;
}


void init_inttable (int_table * p, int size) {
  p->table = NEW (table_entry *, p->len = size);

  while (--size >= 0)
    p->table[size] = NULL;
}


static table_entry *new_entry (long int key, long int value, table_entry * next)
{
  table_entry *p = NEW (table_entry, 1);

  p->key = key;
  p->value = value;
  p->next = next;

  return p;
}

static void unlink_entry (table_entry ** entry) {
  table_entry *tmp;

  tmp = *entry;
  *entry = (*entry)->next;

  FREE (tmp);
}


/* Return a pointer to the pointer to the entry that represents 'key',
 * starting the search at the entry to which *p points.
 * If it does not exist, return a pointer to the pointer to the entry that
 * would succede 'key', had it existed.
 */

static table_entry **find_position (long int key, table_entry ** p) {
  while (*p != NULL && (*p)->key > key)
    p = &(*p)->next;

  return p;
}

static table_entry *find_entry (long int key, int_table * p) {
  table_entry **r = find_position (key, &p->table[hash (key, p->len)]);

  return (*r != NULL && (*r)->key == key) ? *r : NULL;
}

Boolean insert_entry (long int key, long int value, int_table * p) {
  table_entry **q = find_position (key, &p->table[hash (key, p->len)]);

  if ((*q) == NULL) {
    *q = new_entry (key, value, NULL);
  } else if ((*q)->key < key) {
    *q = new_entry (key, value, *q);
  } else
    return False;

  return True;
}


Boolean remove_entry (long int key, int_table * p) {
  table_entry **q = find_position (key, &p->table[hash (key, p->len)]);

  if ((*q) != NULL && (*q)->key == key) {
    unlink_entry (q);
    return True;
  } 
  else
    return False;
}

long int lookup_entry (long int key, int_table * p) {
  table_entry *q = find_entry (key, p);

  return (q != NULL) ? (q)->value : NOT_IN_TABLE;
}

long int change_entry (long int key, long int new_value, int_table * p) {
  table_entry *q = find_entry (key, p);

  if (q != NULL) {
    long int v = q->value;

    q->value = new_value;
    return v;
  }
  else
    return NOT_IN_TABLE;
}
#endif

void ht_add(HASH_TABLE ht[], char *key, int val) {
  HASH_TABLE *ptr;

  if (!(*key)) {
    printf("ht_add: Storing an empty string is not allowed.\n");
    return;
  }

  for (ptr = &ht[hashfun(key)] ; ptr->next ; ptr = ptr->next);

  if (ptr->key) {
    ptr->next = (HASH_TABLE *) NEW(HASH_TABLE, 1);
    ptr->next->key = COPY(key);
    ptr->next->val = val;
  }
  else {                       /* first item added */
    ptr->key = COPY(key);
    ptr->val = val;
  }
}

void ht_remove(HASH_TABLE ht[], char *key, int val) {
  HASH_TABLE *ptr;
  int bucket;

  bucket = hashfun(key);
  for (ptr = &ht[bucket] ; ptr ; ptr = ptr->next)
    if (EQ(ptr->key, key) && (ptr->val == val)) {
      FREE(ptr->key);                               /* silly i know */
      ptr->key = COPY("");
    }
}

int hashfun(char *str) {
  char *p;
  int sum;

  for (p = str, sum = 0 ; *p ; p++)
    sum += tolower(*p);

  return(sum % BASE_SIZE);
}

int ht_lookup(HASH_TABLE ht[], char *key, int n, int z,
              int (eqfun) (int a, int b)) {
  HASH_TABLE *ptr;
  int bucket;

  bucket = hashfun(key);
  for (ptr = &ht[bucket] ; ptr ; ptr = ptr->next)
    if (ptr->key && EQ(ptr->key, key)) {
      if (eqfun(ptr->val, z))
        if (n-- == 0)
          return(ptr->val);
    }

  return(-1);
}

/* converts an integer to a unified game index, where 1, 4, 7 are MOBS, *
 * 2, 5, 8 are LOCS, and 3, 6, 9 are OBJS                               */

int int2idx(int i, int type) {

  switch(type) {
    case MOB:
      return((3 * i) + 1 + i/3);
    case LOC:
      return((3 * i) + 2 + i/3);
    case OBJ:
      return((3 * i) + 3 + i/3);
    default:
      return(-1);
  }
}


int idtxt2int(char *number, int type) {
  char *p;
  int n;

  if (isdigit(*number)) {
    for (p = number ; *p ; p++) {
      if (!isdigit(*p))
        return(-1);
    }
    if (p - number > INT_LEN)
      return(-1);

    n = atoi(number);
    return(idx2int(n, type));
  }
  return(-1);
}

/* converts a mob, loc, or obj number (unified format) to the proper int */

int idx2int(int n, int type) {
  int z, x;

  z = n % 10;                    /* z is last digit */
  x /= 10;                       /* round off last digit */
  x *= 10;
  x = ((n - 1)  - n/10) / 3;     /* calculate index */

  switch (z) {
    case 3: case 6: case 9:
      if (type == OBJ && x > -1 && x < numobs)
        return(x);
      break;
    case 2: case 5: case 8:
      if (type == LOC && x > -1 && x < numloc)
        return(x);
      break;
    case 1: case 4: case 7:
      if (type == MOB && x > -1 && x < numchars)
        return(x);
      break;
    default:
      break;
  }
  return(-1);
}