/
2.0.4beta/doc/
2.0.4beta/gnu/
2.0.4beta/sha/
/* attributes.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#include <ctype.h>

#include "conf.h"
#include "teeny.h"
#include "teenydb.h"
#include "externs.h"

/* user def'd attributes */

/* hash routine for attribute names */
int attr_hash(str)
    char *str;
{
  register unsigned int i = 0;

  if((str == (char *)NULL) || (str[0] == '\0'))
    return(0);

  while(str[0] != '\0') {
    i = (i * 10) + (to_lower(str[0]) - '0');
    str++;
  }
  return((i*1103515245 + 12345) % ATTR_WIDTH);
}

int attr_set(obj, name, flags)
    int obj;
    char *name;
    int flags;
{
  struct attr *attrs;
  struct obj_data *dat;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *) NULL)
    return (-1);

  for (attrs = dat->attributes[attr_hash(name)]; attrs != (struct attr *)NULL;
       attrs = attrs->next) {
    if (!strcasecmp(attrs->name, name)) {
      attrs->flags = flags;
      DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
      return (0);
    }
  }
  return (-2);
}

int attr_addlock(obj, name, data, flags)
    int obj;
    char *name;
    struct boolexp *data;
    int flags;
{
  register struct attr *curr, *new;
  struct obj_data *dat;
  int hashval;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *) NULL)
    return (-1);

  hashval = attr_hash(name);
  for (curr = dat->attributes[hashval]; curr != (struct attr *)NULL;
       curr = curr->next) {
    if (!strcasecmp(curr->name, name)) {
      if(curr->type != ATTR_LOCK) {
        ty_free((VOID *)(curr->dat).str);
	curr->type = ATTR_LOCK;
      } else
        boolexp_free((curr->dat).lock);
      (curr->dat).lock = data;
      strcpy(curr->name, name);
      if(islower(name[0]))
        (curr->name)[0] = to_upper((curr->name)[0]);
      curr->flags = flags;
      DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
      return (0);
    }
  }

  new = (struct attr *)ty_malloc(sizeof(struct attr), "attr_add.new");
  new->name = (char *) ty_strdup(name, "attr_add.name");
  if(islower(name[0]))
    (new->name)[0] = to_upper((new->name)[0]);
  (new->dat).lock = data;
  new->flags = flags;
  new->type = ATTR_LOCK;

  /* link it in, new style */
  new->next = dat->attributes[hashval];
  if(dat->attributes[hashval] == (struct attr *) NULL)
    new->prev = new;
  else {
    new->prev = (dat->attributes[hashval])->prev;
    (dat->attributes[hashval])->prev = new;
  }
  dat->attributes[hashval] = new;
  dat->attr_total++;

  DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
  DSC_SIZE(main_index[dat->objnum]) += strlen(name) + 1;
  mudstat.cache_usage += strlen(name) + 1;
  return (0);
}

int attr_add(obj, name, data, flags)
    int obj;
    char *name, *data;
    int flags;
{
  register struct attr *curr, *new;
  struct obj_data *dat;
  int oldsize, hashval;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *) NULL)
    return (-1);

  hashval = attr_hash(name);
  for (curr = dat->attributes[hashval]; curr != (struct attr *)NULL;
       curr = curr->next) {
    if (!strcasecmp(curr->name, name)) {
      if(curr->type != ATTR_STRING) {
        oldsize = 0;
	boolexp_free((curr->dat).lock);
	curr->type = ATTR_STRING;
      } else {
        oldsize = strlen((curr->dat).str) + 1;
        ty_free((VOID *) (curr->dat).str);
      }
      (curr->dat).str = (char *) ty_strdup(data, "attr_add.data");
      strcpy(curr->name, name);
      if(islower(name[0]))
        (curr->name)[0] = to_upper((curr->name)[0]);
      curr->flags = flags;
      DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
      DSC_SIZE(main_index[dat->objnum]) =
	  (DSC_SIZE(main_index[dat->objnum]) - oldsize) + strlen(data) + 1;
      mudstat.cache_usage = (mudstat.cache_usage - oldsize) + strlen(data) + 1;
      return (0);
    }
  }
  new = (struct attr *)ty_malloc(sizeof(struct attr), "attr_add.new");
  new->name = (char *) ty_strdup(name, "attr_add.name");
  if(islower(name[0]))
    (new->name)[0] = to_upper((new->name)[0]);
  (new->dat).str = (char *) ty_strdup(data, "attr_add.data");
  new->flags = flags;
  new->type = ATTR_STRING;

  /* link it in, new style */
  new->next = dat->attributes[hashval];
  if(dat->attributes[hashval] == (struct attr *) NULL)
    new->prev = new;
  else {
    new->prev = (dat->attributes[hashval])->prev;
    (dat->attributes[hashval])->prev = new;
  }
  dat->attributes[hashval] = new;
  dat->attr_total++;

  DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
  DSC_SIZE(main_index[dat->objnum]) += strlen(name) + strlen(data) + 2;
  mudstat.cache_usage += strlen(name) + strlen(data) + 2;
  return (0);
}

int attr_delete(obj, name)
    int obj;
    char *name;
{
  register struct attr *curr;
  struct obj_data *dat;
  int oldsize, hashval;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *) NULL)
    return (-1);

  hashval = attr_hash(name);
  for (curr = dat->attributes[hashval]; curr != (struct attr *)NULL;
       curr = curr->next) {
    if (!strcasecmp(curr->name, name)) {
      oldsize = strlen(curr->name) + 1;
      if (curr == dat->attributes[hashval]) {
	dat->attributes[hashval] = curr->next;
	if (dat->attributes[hashval] != (struct attr *)NULL)
	  (dat->attributes[hashval])->prev = dat->attributes[hashval];
      } else {
	(curr->prev)->next = curr->next;
      }
      if (curr->next != (struct attr *)NULL) {
	(curr->next)->prev = curr->prev;
      } else if (dat->attributes[hashval] != (struct attr *)NULL) {
        /* last thing in the list */
	(dat->attributes[hashval])->prev = curr->prev;
      }
      ty_free((VOID *) curr->name);
      switch(curr->type) {
      case ATTR_STRING:
        oldsize += strlen((curr->dat).str) + 1;
        ty_free((VOID *) (curr->dat).str);
	break;
      case ATTR_LOCK:
        boolexp_free((curr->dat).lock);
	break;
      }
      dat->attr_total--;
      ty_free((VOID *)curr);
      DSC_FLAG2(main_index[dat->objnum]) |= DIRTY;
      DSC_SIZE(main_index[dat->objnum]) -= oldsize;
      mudstat.cache_usage -= oldsize;
      break;
    }
  }
  return (0);
}

int attr_source(obj, name)
    int obj;
    char *name;
{
  register struct attr *attrs;
  struct obj_data *dat;
  int parent, depth, hashval;

  depth = 0;
  parent = obj;
  hashval = attr_hash(name);
  do {
    if (!_exists_object(parent))
      return (-1);
    if ((dat = lookup_obj(parent)) == (struct obj_data *) NULL)
      return (-1);
    for (attrs = dat->attributes[hashval]; attrs != (struct attr *)NULL;
         attrs = attrs->next) {
      if ((attrs->flags & A_PRIVATE) && (parent != obj))
	continue;
      if ((attrs->flags & A_PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
	continue;
      if ((DSC_FLAG2(main_index[parent]) & PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
	continue;
      if (!strcasecmp(attrs->name, name))
	return (parent);
    }
    parent = DSC_PARENT(main_index[dat->objnum]);
    depth++;
  } while ((parent != -1) && (depth <= mudconf.parent_depth));
  return(-1);
}

int attr_getlock_parent(obj, name, ret, flags, source)
    int obj;
    char *name;
    struct boolexp **ret;
    int *flags, *source;
{
  register struct attr *attrs;
  struct obj_data *dat;
  int parent, depth, hashval;

  depth = 0;
  parent = obj;
  hashval = attr_hash(name);
  do {
    if (!_exists_object(parent))
      return (-1);
   if ((dat = lookup_obj(parent)) == (struct obj_data *)NULL)
     return (-1);
   for (attrs = dat->attributes[hashval]; attrs != (struct attr *)NULL;
   	attrs = attrs->next) {
      if ((attrs->flags & A_PRIVATE) && (parent != obj))
        continue;
      if ((attrs->flags & A_PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
        continue;
      if ((DSC_FLAG2(main_index[parent]) & PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
        continue;
      if (!strcasecmp(attrs->name, name)) {
        if(attrs->type != ATTR_LOCK) {
	  *ret = (struct boolexp *)NULL;
	  *flags = -1;
	  *source = -1;
	} else {
	  *ret = (attrs->dat).lock;
	  *flags = attrs->flags;
	  *source = parent;
	}
	return (0);
      }
    }
    parent = DSC_PARENT(main_index[dat->objnum]);
    depth++;
  } while ((parent != -1) && (depth <= mudconf.parent_depth));

  *ret = (struct boolexp *) NULL;
  *flags = -1;
  *source = -1;
  return (0);
}

int attr_get_parent(obj, name, ret, flags, source)
    int obj;
    char *name, **ret;
    int *flags, *source;
{
  register struct attr *attrs;
  struct obj_data *dat;
  int parent, depth, hashval;

  depth = 0;
  parent = obj;
  hashval = attr_hash(name);
  do {
    if (!_exists_object(parent))
      return (-1);
    if ((dat = lookup_obj(parent)) == (struct obj_data *) NULL)
      return (-1);
    for (attrs = dat->attributes[hashval]; attrs != (struct attr *)NULL;
         attrs = attrs->next) {
      if ((attrs->flags & A_PRIVATE) && (parent != obj))
	continue;
      if ((attrs->flags & A_PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
        continue;
      if ((DSC_FLAG2(main_index[parent]) & PICKY)
          && (DSC_TYPE(main_index[parent]) != DSC_TYPE(main_index[obj])))
        continue;
      if (!strcasecmp(attrs->name, name)) {
        if(attrs->type != ATTR_STRING) {
	  *ret = (char *)NULL;
	  *flags = -1;
	  *source = -1;
	} else {
	  *ret = (attrs->dat).str;
	  *flags = attrs->flags;
	  *source = parent;
	}
	return (0);
      }
    }
    parent = DSC_PARENT(main_index[dat->objnum]);
    depth++;
  } while ((parent != -1) && (depth <= mudconf.parent_depth));

  *ret = (char *) NULL;
  *flags = -1;
  *source = -1;
  return (0);
}

int attr_getlock(obj, name, ret, flags)
    int obj;
    char *name;
    struct boolexp **ret;
    int *flags;
{
  register struct attr *attrs;
  struct obj_data *dat;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *)NULL)
    return (-1);

  for (attrs = dat->attributes[attr_hash(name)]; attrs != (struct attr *)NULL;
      attrs = attrs->next) {
    if(!strcasecmp(attrs->name, name)) {
      if(attrs->type != ATTR_LOCK) {
        *ret = (struct boolexp *)NULL;
	*flags = -1;
      } else {
        *ret = (attrs->dat).lock;
        *flags = attrs->flags;
      }
      return (0);
    }
  }

  *ret = (struct boolexp *)NULL;
  *flags = -1;
  return(0);
}

int attr_get(obj, name, ret, flags)
    int obj;
    char *name, **ret;
    int *flags;
{
  register struct attr *attrs;
  struct obj_data *dat;

  if (!_exists_object(obj))
    return (-1);
  if ((dat = lookup_obj(obj)) == (struct obj_data *) NULL)
    return (-1);

  for (attrs = dat->attributes[attr_hash(name)]; attrs != (struct attr *)NULL;
       attrs = attrs->next) {
    if (!strcasecmp(attrs->name, name)) {
      if(attrs->type != ATTR_STRING) {
        *ret = (char *)NULL;
	*flags = -1;
      } else {
        *ret = (attrs->dat).str;
        *flags = attrs->flags;
      }
      return (0);
    }
  }

  *ret = (char *) NULL;
  *flags = -1;
  return (0);
}

/* attribute search routines */
struct attr *attr_first(obj, search)
    int obj;
    struct asearch *search;
{
  struct obj_data *dat;
  register int idx;

  if(!_exists_object(obj))
    return((struct attr *)NULL);
  if((dat = lookup_obj(obj)) == (struct obj_data *)NULL)
    return((struct attr *)NULL);

  /* loop through the table, looking for the first attribute */
  for(idx = 0; idx < ATTR_WIDTH; idx++) {
    if(dat->attributes[idx] != (struct attr *)NULL) {
      search->elem = idx;
      search->curr = dat->attributes[idx];
      return(dat->attributes[idx]);
    }
  }
  return((struct attr *)NULL);
}

struct attr *attr_next(obj, search)
    int obj;
    struct asearch *search;
{
  struct obj_data *dat;
  
  if(!_exists_object(obj))
    return((struct attr *)NULL);
  if((dat = lookup_obj(obj)) == (struct obj_data *)NULL)
    return((struct attr *)NULL);

  /* find the next attribute */
  if(search->curr != (struct attr *)NULL) {
    if((search->curr)->next != (struct attr *)NULL) {
      /* elem is still correct */
      search->curr = (search->curr)->next;
      return(search->curr);
    }
    /* the current bucket is empty. find the next one. */
    while(search->elem < (ATTR_WIDTH-1)) {
      (search->elem)++;
      if(dat->attributes[search->elem] != (struct attr *)NULL) {
        search->curr = dat->attributes[search->elem];
	return(search->curr);
      }
    }
  }
  return((struct attr *)NULL);
}

/* attributes and list allocation */
void free_attributes(attrs)
    struct attr *attrs[];
{
  register struct attr *curr, *next;
  register int idx;

  for(idx = 0; idx < ATTR_WIDTH; idx++) {
    for(curr = attrs[idx]; curr != (struct attr *)NULL; curr = next) {
      next = curr->next;
      ty_free((VOID *)curr->name);
      switch(curr->type) {
      case ATTR_STRING:
        ty_free((VOID *)(curr->dat).str);
	break;
      case ATTR_LOCK:
        boolexp_free((curr->dat).lock);
	break;
      }
      ty_free((VOID *)curr);
    }
  }
}