muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* db.c */
/* $Id: db.c,v 1.33 1993/10/18 02:29:09 nils Exp $ */

#include "credits.h"

#include <stdio.h>
#include <ctype.h>

#include "nalloc.h"
#include "db.h"
#include "config.h"
#include "externs.h"
#include "interface.h"
#include "hash.h"

long getlong();

struct object *db = 0;
dbref db_top = 0;
NALLOC *db_strings=NULL;
#ifdef TEST_MALLOC
int malloc_count = 0;
#endif /* TEST_MALLOC */

dbref db_size = DB_INITIAL_SIZE;

extern char ccom[];

struct builtinattr {
  ATTR definition;
  int number;
};

/* if you're going to add things to this, please contact me and
   get a range of numbers to use so you don't interfere with
   attributes used by future versions of muse. 
   -nils@pc2.pc.maricopa.edu */
struct builtinattr attr[]={
#if 0
  {{"Osucc",  INH                               ,NOTHING,1}, 1},
  {{"Ofail",  INH                               ,NOTHING,1}, 2},
  {{"Fail",   INH                               ,NOTHING,1}, 3},
  {{"Succ",   INH                               ,NOTHING,1}, 4},
  {{"Xyxxy",      AF_WIZARD|AF_DARK             ,NOTHING,1}, 5},
  {{"Desc",   INH                               ,NOTHING,1}, 6},
  {{"Sex",    INH|AF_OSEE                       ,NOTHING,1}, 7},
  {{"Odrop",  INH                               ,NOTHING,1}, 8},
  {{"Drop",   INH                               ,NOTHING,1}, 9},
  {{"Okill",  INH                               ,NOTHING,1}, 10},
  {{"Kill",   INH                               ,NOTHING,1}, 11},
  {{"Asucc",  INH                               ,NOTHING,1}, 12},
  {{"Afail",  INH                               ,NOTHING,1}, 13},
  {{"Adrop",  INH                               ,NOTHING,1}, 14},
  {{"Akill",  INH                               ,NOTHING,1}, 15},
  {{"Does"  , INH                               ,NOTHING,1}, 16},
  {{"Charges",INH                               ,NOTHING,1}, 17},
  {{"Runout", INH                               ,NOTHING,1}, 18},
  {{"Startup",INH|AF_WIZARD                     ,NOTHING,1}, 19},
  {{"Aclone", INH                               ,NOTHING,1}, 20},
  {{"Apay",   INH                               ,NOTHING,1}, 21},
  {{"Opay",   INH                               ,NOTHING,1}, 22},
  {{"Pay",    INH                               ,NOTHING,1}, 23},
  {{"Cost",   INH                               ,NOTHING,1}, 24},
  {{"Listen", INH                               ,NOTHING,1}, 26},
  {{"Aahear", INH                               ,NOTHING,1}, 27},
  {{"Amhear", INH                               ,NOTHING,1}, 28},
  {{"Ahear",  INH                               ,NOTHING,1}, 29},
  {{"Last",       AF_WIZARD | AF_DATE | AF_OSEE ,NOTHING,1}, 30},
  {{"Queue",      AF_WIZARD |AF_UNIMP           ,NOTHING,1}, 31},
  {{"Idesc",  INH                               ,NOTHING,1}, 32},
  {{"Enter",  INH                               ,NOTHING,1}, 33},
  {{"Oenter", INH                               ,NOTHING,1}, 34},
  {{"Aenter", INH                               ,NOTHING,1}, 35},
  {{"Adesc",  INH                               ,NOTHING,1}, 36},
  {{"Odesc",  INH                               ,NOTHING,1}, 37},
  {{"Rquota",     AF_DARK | AF_NOMOD | AF_WIZARD,NOTHING,1}, 38},
  {{"Idle",       AF_DARK | AF_WIZARD           ,NOTHING,1}, 39},
  {{"Away",       AF_DARK | AF_WIZARD           ,NOTHING,1}, 40},
  {{"Mailk", AF_DARK|AF_NOMOD|AF_WIZARD|AF_UNIMP,NOTHING,1}, 41},
  {{"Alias",      AF_OSEE                       ,NOTHING,1}, 42},
  {{"Efail",  INH                               ,NOTHING,1}, 43},
  {{"Oefail", INH                               ,NOTHING,1}, 44},
  {{"Aefail", INH                               ,NOTHING,1}, 45},
  {{"It",         AF_UNIMP                      ,NOTHING,1}, 46},
  {{"Leave",  INH                               ,NOTHING,1}, 47},
  {{"Oleave", INH                               ,NOTHING,1}, 48},
  {{"Aleave", INH                               ,NOTHING,1}, 49},
  {{"Channel",    AF_WIZARD                     ,NOTHING,1}, 50},
  {{"Quota",      AF_DARK|AF_NOMOD|AF_UNIMP|AF_WIZARD,NOTHING,1}, 51},
  {{"Pennies",    AF_WIZARD | AF_DARK | AF_NOMOD,NOTHING,1}, 52},
  {{"Huhto",      AF_WIZARD                     ,NOTHING,1}, 53},
  {{"Haven",      AF_WIZARD | AF_DARK           ,NOTHING,1}, 54},
  {{"Alogin", INH                               ,NOTHING,1}, 55},
  {{"Alogout",INH                               ,NOTHING,1}, 56},
  {{"TZ",     INH                               ,NOTHING,1}, 57},
  {{"Doomsday",   AF_WIZARD                     ,NOTHING,1}, 58},
#ifdef EMAIL_CREATE
  {{"Email",      AF_WIZARD                     ,NOTHING,1}, 59},
#endif
#ifdef USE_SPACE  /*  Attributes added by Michael Majere  */
  {{"Aship",  AF_SPACE | INH                   ,NOTHING,1}, 60},
  {{"Sector", AF_SPACE                         ,NOTHING,1}, 61},
  {{"Mass",   AF_SPACE                         ,NOTHING,1}, 62},
  {{"Radius", AF_SPACE                         ,NOTHING,1}, 63},
  {{"Thrust", AF_SPACE                         ,NOTHING,1}, 64},
  {{"Rating", AF_SPACE                         ,NOTHING,1}, 65},
  {{"Efficiency", AF_SPACE                     ,NOTHING,1}, 66}, 
  {{"Fuel",   AF_SPACE                         ,NOTHING,1}, 67},
  {{"Acceleration", AF_SPACE                   ,NOTHING,1}, 68},
  {{"Vismult", AF_SPACE                        ,NOTHING,1}, 69},
  {{"Pwrgen",  AF_SPACE                        ,NOTHING,1}, 70},
  {{"Pwrfuel", AF_SPACE                        ,NOTHING,1}, 71},
  {{"SprStr",  AF_SPACE                        ,NOTHING,1}, 72},
  {{"Hull",    AF_SPACE                        ,NOTHING,1}, 73},
  {{"Recover", AF_SPACE | AF_DARK | AF_NOMOD   ,NOTHING,1}, 74}, 
  {{"Type",    AF_SPACE | AF_OSEE              ,NOTHING,1}, 75},
  {{"Energy",  AF_SPACE | AF_UNIMP             ,NOTHING,1}, 76},
  {{"LinposX", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 80},
  {{"LinposY", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 81},
  {{"LinposZ", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 82},
  {{"LinvelX", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 83},
  {{"LinvelY", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 84},
  {{"LinvelZ", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 85},
  {{"LinaccX", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 86},
  {{"LinaccY", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 87},
  {{"LinaccZ", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 88},
  {{"AngposX", AF_SPACE                        ,NOTHING,1}, 89},
  {{"AngposY", AF_SPACE                        ,NOTHING,1}, 90},
  {{"AngposZ", AF_SPACE                        ,NOTHING,1}, 91},
  {{"AngvelX", AF_SPACE                        ,NOTHING,1}, 92},
  {{"AngvelY", AF_SPACE                        ,NOTHING,1}, 93},
  {{"AngvelZ", AF_SPACE                        ,NOTHING,1}, 94},
  {{"AngaccX", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 95},
  {{"AngaccY", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 96},
  {{"AngaccZ", AF_SPACE | AF_UNIMP             ,NOTHING,1}, 97},
#endif
  {{"Talent", INH| AF_OSEE                     ,NOTHING,1}, 98},
  {{"Race",   INH|AF_WIZARD | AF_OSEE          ,NOTHING,1}, 99},
  {{"Va",     INH                              ,NOTHING,1}, 100+0},
  {{"Vb",     INH                              ,NOTHING,1}, 100+1},
  {{"Vc",     INH                              ,NOTHING,1}, 100+2},
  {{"Vd",     INH                              ,NOTHING,1}, 100+3},
  {{"Ve",     INH                              ,NOTHING,1}, 100+4},
  {{"Vf",     INH                              ,NOTHING,1}, 100+5},
  {{"Vg",     INH                              ,NOTHING,1}, 100+6},
  {{"Vh",     INH                              ,NOTHING,1}, 100+7},
  {{"Vi",     INH                              ,NOTHING,1}, 100+8},
  {{"Vj",     INH                              ,NOTHING,1}, 100+9},
  {{"Vk",     INH                              ,NOTHING,1}, 100+10},
  {{"Vl",     INH                              ,NOTHING,1}, 100+11},
  {{"Vm",     INH                              ,NOTHING,1}, 100+12},
  {{"Vn",     INH                              ,NOTHING,1}, 100+13},
  {{"Vo",     INH                              ,NOTHING,1}, 100+14},
  {{"Vp",     INH                              ,NOTHING,1}, 100+15},
  {{"Vq",     INH                              ,NOTHING,1}, 100+16},
  {{"Vr",     INH                              ,NOTHING,1}, 100+17},
  {{"Vs",     INH                              ,NOTHING,1}, 100+18},
  {{"Vt",     INH                              ,NOTHING,1}, 100+19},
  {{"Vu",     INH                              ,NOTHING,1}, 100+20},
  {{"Vv",     INH                              ,NOTHING,1}, 100+21},
  {{"Vw",     INH                              ,NOTHING,1}, 100+22},
  {{"Vx",     INH                              ,NOTHING,1}, 100+23},
  {{"Vy",     INH                              ,NOTHING,1}, 100+24},
  {{"Vz",     INH                              ,NOTHING,1}, 100+25},
  {{"Move",   INH                              ,NOTHING,1}, 126},
  {{"Omove",  INH                              ,NOTHING,1}, 127},
  {{"Amove",  INH                              ,NOTHING,1}, 128},
  {{"Lock",   AF_LOCK                          ,NOTHING,1}, 129},
  {{"Elock",  AF_LOCK                          ,NOTHING,1}, 130},
  {{"Ulock",  AF_LOCK                          ,NOTHING,1}, 131},
  {{"Ufail",  INH                              ,NOTHING,1}, 132},
  {{"Oufail", INH                              ,NOTHING,1}, 133},
  {{"Aufail", INH                              ,NOTHING,1}, 134},
  {{"Oconnect", INH                            ,NOTHING,1}, 135},
  {{"Aconnect", INH                            ,NOTHING,1}, 136},
  {{"Odisconnect", INH                         ,NOTHING,1}, 137},
  {{"Adisconnect", INH                         ,NOTHING,1}, 138},
  {{"Columns", INH                             ,NOTHING,1}, 139},
  {{"who_flags", INH                           ,NOTHING,1}, 140},
  {{"who_names", INH                           ,NOTHING,1}, 141},
  {{"Apage", INH                               ,NOTHING,1}, 142},
  {{"Apemit", INH                              ,NOTHING,1}, 143},
  {{"Awhisper", INH                            ,NOTHING,1}, 144},
#ifdef USE_SPACE  /* Registers added by Michael Majere  */
  {{"S0",     AF_SPACE                         ,NOTHING,1}, 145+0},
  {{"S1",     AF_SPACE                         ,NOTHING,1}, 145+1},
  {{"S2",     AF_SPACE                         ,NOTHING,1}, 145+2},
  {{"S3",     AF_SPACE                         ,NOTHING,1}, 145+3},
  {{"S4",     AF_SPACE                         ,NOTHING,1}, 145+4},
  {{"S5",     AF_SPACE                         ,NOTHING,1}, 145+5},
  {{"S6",     AF_SPACE                         ,NOTHING,1}, 145+6},
  {{"S7",     AF_SPACE                         ,NOTHING,1}, 145+7},
  {{"S8",     AF_SPACE                         ,NOTHING,1}, 145+8},
  {{"S9",     AF_SPACE                         ,NOTHING,1}, 145+9},
#endif
  {{"Use",    INH                              ,NOTHING,1}, 155},
  {{"OUse",    INH                             ,NOTHING,1}, 156},
  {{"AUse",    INH                             ,NOTHING,1}, 157},
  {{"LHide",   AF_LOCK                          ,NOTHING,1}, 158},
  {{"LPage",   AF_LOCK                          ,NOTHING,1}, 159},
  {{"Llock",   AF_LOCK                          ,NOTHING,1}, 161},
  {{"Lfail",   INH                              ,NOTHING,1}, 162},
  {{"Olfail",  INH                              ,NOTHING,1}, 163},
  {{"Alfail",  INH                              ,NOTHING,1}, 164},
  {{"Slock",   AF_LOCK                          ,NOTHING,1}, 165},
  {{"Sfail",   INH                              ,NOTHING,1}, 166},
  {{"Osfail",  INH                              ,NOTHING,1}, 167},
  {{"Asfail",  INH                              ,NOTHING,1}, 168},
  {{"Doing",   INH|AF_OSEE                      ,NOTHING,1}, 169},
  {{"Users",   INH|AF_WIZARD                    ,NOTHING,1}, 170},
  {{"Defown",  INH                              ,NOTHING,1}, 171},
  {{"Warnings",INH                              ,NOTHING,1}, 172},
  {{"WInhibit",INH                              ,NOTHING,1}, 173},
  {{"ANews",   INH                              ,NOTHING,1}, 174},
#endif
#define DOATTR(var, name, flags, num) \
  {{name, flags, NOTHING, 1}, num},
#include "attrib.h"
#undef DOATTR
  {{0,		0				,0,0}	 , 0}

};
#define NUM_BUILTIN_ATTRS ((sizeof(attr)/sizeof(struct builtinattr))-1)
#define MAX_ATTRNUM 256 /* less than this, but this will do. */

ATTR *builtin_atr(num)
     int num;
{
  static int initted=0;
  static ATTR *numtable[MAX_ATTRNUM];
  
  if (!initted) {
    /* we need to init. */
    int i;

    initted = 1;

    for (i=0; i<MAX_ATTRNUM; i++) {
      int a=0;
      
      while((a<NUM_BUILTIN_ATTRS)&&(attr[a].number!=i))
	a++;
      if(a<NUM_BUILTIN_ATTRS)
	numtable[i] = &(attr[a].definition);
      else
	numtable[i] = NULL;
    }
  }
  if (num>=0 && num<MAX_ATTRNUM)
    return numtable[num];
  else
    return NULL;
}
static char *attr_disp (atr)
     void *atr;
{
  return tprintf("#%d, flags #%d",((struct builtinattr *)atr)->number, ((struct builtinattr *)atr)->definition.flags);
}

ATTR *builtin_atr_str (str)
     char *str;
{
  static struct hashtab *attrhash=NULL;

  if (!attrhash)
    attrhash = make_hashtab(207, attr, sizeof(struct builtinattr), "attr", attr_disp);

  return &((struct builtinattr *)lookup_hash (attrhash, hash_name(str), str))->definition;
/*  for (a=0; a<NUM_BUILTIN_ATTRS; a++)
    if (!string_compare (str, attr[a].definition.name))
      return &(attr[a].definition);
  return NULL;*/
}

ATTR *atr_defined_on_str (obj, str)
     dbref obj;
     char *str;
{
  ATRDEF *k;

  if (obj < 0 || obj >= db_top)
    return NULL; /* sanity check */
  
  for (k=db[obj].atrdefs; k; k=k->next)
    if (!string_compare (k->a.name, str))
      return &(k->a);
  return NULL;
}

ATTR *atr_find_def_str (obj, str)
     dbref obj;
     dbref str;
{
  ATTR *k;
  int i;
  if ((k=atr_defined_on_str (obj, str)))
    return k;
  for (i=0; db[obj].parents && db[obj].parents[i]!=NOTHING; i++)
    if ((k=atr_find_def_str (db[obj].parents[i], str)))
      return k;
  return NULL;
}

ATTR *atr_str(player, obj, s)
     dbref player;
     dbref obj;
     char *s;
{
  ATTR *a;
  char *t;    

  if ((t=strchr(s,'.'))) { /* definately a user defined attribute. */
    dbref onobj;
    static char mybuf[1000];

    if (t == s)         /* first thing too! make it global. */
      return builtin_atr_str(s+1);
    strcpy(mybuf, s);
    mybuf[t-s] = '\0';
    init_match (player, mybuf, NOTYPE);
    match_everything ();
    onobj = match_result();
    if (onobj == AMBIGUOUS) onobj = NOTHING;
    if (onobj != NOTHING) {
      a = atr_defined_on_str (onobj, t+1);
/*      if (is_a (player, a->obj))
        return a; */
      if (a) return a;
    }
  }
  if (player != NOTHING) {
    a = atr_find_def_str (player, s);
    if (a && is_a(obj, a->obj)) 
      return a;
  }
  
  a= builtin_atr_str (s);
  if (a) return a;
  a = atr_find_def_str (obj, s);
  return a;                     /* if everything else fails, use the one on the
                                   obj. */
}                               

/* routines to handle object attribute lists */

/* single attribute cache */
static dbref atr_obj= -1;
static ATTR *atr_atr= NULL;
static char *atr_p;

/* clear an attribute in the list */
void atr_clr(thing,atr)
     dbref thing;
     ATTR *atr;
{
  ALIST *ptr=db[thing].list;

  atr_obj = -1;
  while(ptr) {
    if (AL_TYPE(ptr)==atr) {
      if (AL_TYPE(ptr)) unref_atr(AL_TYPE(ptr));
      AL_DISPOSE(ptr);
      return;
    }
    ptr=AL_NEXT(ptr);
  }
}

ALIST *AL_MAKE();


/* add attribute of type atr to list */
void atr_add(thing,atr,s)
     dbref thing;
     ATTR *atr;
     char *s;             
{       
  ALIST *ptr;
  char *d;

  if (atr == 0) return;
  
  if (!s)
    s="";   
  if (atr == NULL) return;
  for(ptr=db[thing].list; ptr && (AL_TYPE(ptr)!=atr); ptr=AL_NEXT(ptr))
    ;
  if (!*s) {
    if (ptr) {
      unref_atr(AL_TYPE(ptr));
      AL_DISPOSE(ptr);
    } else
      return;
  }
  s=(char *)compress(s);
  if (!ptr || (strlen(s)>strlen(d=(char *)AL_STR(ptr)))) {
    /* allocate room for the attribute */
    if (ptr) {
      AL_DISPOSE(ptr);
      db[thing].list=AL_MAKE(atr,db[thing].list,s);
    } else {
      ref_atr(AL_TYPE((db[thing].list=AL_MAKE(atr,db[thing].list,s))));
    }
  } else
    strcpy(d,s);
  atr_obj= -1;
}

/* used internally by defines */    
#ifdef SMALL     
ALIST *AL_GETPTR(alist)
     ALIST *alist;
{
  int a;
  ALIST *res;
  unsigned char *s,*d;
  
  for((a=0),(s=Astr(alist)),d=(unsigned char *)&res; a<sizeof(ALIST *); a++)
    *d++= *s++;     
  if (res)
    a= *((char *)res);
  return(res);
}         
#endif

static char *atr_get_internal (thing, atr)
     dbref thing;
     ATTR *atr;
{
  int i;
  ALIST *ptr;
  char *k;

  for(ptr=db[thing].list; ptr; ptr=AL_NEXT(ptr))
    if (ptr && (AL_TYPE(ptr)==atr))
      return((char *)uncompress(AL_STR(ptr)));
  for (i=0; db[thing].parents && db[thing].parents[i] != NOTHING; i++)
    if ((k = atr_get_internal (db[thing].parents[i], atr)))
      if (*k)
        return k;
  return "";
}

char *atr_get(thing,atr)
     dbref thing;
     ATTR *atr;
{
  ALIST *ptr;

  if (thing < 0 || thing >= db_top || !atr)
    return ""; /* sanity check */
  
  if ((thing==atr_obj) && (atr==atr_atr))
    return(atr_p);
  atr_obj=thing;
  atr_atr=atr;    
  for(ptr=db[thing].list; ptr; ptr=AL_NEXT(ptr))
    if (ptr && AL_TYPE(ptr)==atr)
      return(atr_p=(char *)uncompress(AL_STR(ptr)));
  if (atr->flags & AF_INHERIT)
    return (atr_p = atr_get_internal (thing, atr));
  else
    return(atr_p="");
}

void atr_free(thing)
     dbref thing;
{    
  ALIST *ptr,*next;
  
  if (thing < 0 || thing >= db_top)
    return; /* sanity check */
  
  for(ptr=db[thing].list;ptr;ptr=next) {
    next=AL_NEXT(ptr);
    free(ptr);
  }       
  db[thing].list=NULL;
  atr_obj= -1;
}             

ALIST *AL_MAKE(type,next,string)
     ATTR *type;
     ALIST *next;
     char *string;
{         
#ifdef SMALL
  ALIST *ptr;       
  int a;
  
  /* allocate maximum possibly needed */
  if (type>127) {
    log_error("Type out of range");
    report(); 
  } 
  ptr= (ALIST *)
    malloc(sizeof(ALIST)+sizeof(ALIST *)+strlen(string)+1);
  ptr->al_type=type;
  if (((a=((char *)ptr)-((char *)next))<256) && (a>0)) {
    ptr->al_type|=128;
    *Astr(ptr)=a;
    /* give back a lousy 3 bytes? With 100K objects each with
       multiple attributes that amounts to a $&!^load of memory! */
    nza_giveback(db_strings,sizeof(ALIST *)-1);
    strcpy(Astr(ptr)+1,string);
  }
  else {         
    unsigned char *s,*d;
    for((a=0),(s=(unsigned char *)&next),d=Astr(ptr);a<sizeof(ALIST *);a++)
      *d++= *s++;
    strcpy(Astr(ptr)+sizeof(ALIST *),string);
  }
  return(ptr);
#else 
  ALIST *ptr;
  
  ptr=(ALIST *) malloc(sizeof(ALIST)+strlen(string)+1);
  AL_TYPE(ptr) = type;
  ptr->next=next;
  strcpy(AL_STR(ptr),string);
  return(ptr);
#endif  
}                    

/* garbage collect an attribute list */                
void atr_collect(thing)
     dbref thing;
{              
  ALIST *ptr,*next;
  
  if (thing < 0 || thing >= db_top)
    return; /* sanity check */
  
  ptr=db[thing].list;
  db[thing].list=NULL;
  while(ptr) { 
    if (AL_TYPE(ptr))
      db[thing].list=AL_MAKE(AL_TYPE(ptr),db[thing].list,AL_STR(ptr));
    next=AL_NEXT(ptr);
    free(ptr);
    ptr=next;
  }        
  atr_obj= -1;
} 

void atr_cpy_noninh(dest,source)
     dbref dest;
     dbref source;
{                 
  ALIST *ptr;
  
  ptr=db[source].list;
  db[dest].list=NULL;
  while(ptr) {
    if (AL_TYPE(ptr) && !(AL_TYPE(ptr)->flags&AF_INHERIT)) {
      db[dest].list=AL_MAKE(AL_TYPE(ptr),db[dest].list,AL_STR(ptr));
      ref_atr(AL_TYPE(ptr));
    }
    ptr=AL_NEXT(ptr);
  }
}

int db_init=0;                    

static void db_grow(newtop)
     dbref newtop;
{
  struct object *newdb;
  
  if(newtop > db_top) {
    db_top = newtop;
    if(!db) {
      /* make the initial one */
      db_size = (db_init) ? db_init : DB_INITIAL_SIZE;
      if((db = 5+(struct object *)
          bigalloc((db_size+5) * sizeof(struct object))) == 0) {
        abort();
      }
      memchr (db-5, 0, sizeof(struct object)*(db_size+5));
    }
    
    /* maybe grow it */
    if(db_top > db_size) {
      /* make sure it's big enough */
      while(db_top > db_size) db_size *= 2;
      if((newdb = 5+(struct object *)
          bigalloc((5+db_size) * sizeof(struct object))) == 0) {
        abort();
      } 
      memcpy(newdb,db,db_top*sizeof(struct object));
      memchr(newdb+db_top, 0, sizeof(struct object)*(db_size - db_top));
      bigfree(db-5);
      db = newdb;
    }
  }
}

dbref new_object()
{
  dbref newobj;
  struct object *o;
  
#ifdef DESTROY    
  /* if stuff in free list use it */
  if ((newobj=free_get())==NOTHING)
    /* allocate more space */
#endif /* DESTROY */    
    {
      newobj = db_top;
      db_grow(db_top + 1);
#ifdef DO_AGE
      db[newobj].num1=db[newobj].num2=newobj;
#endif DO_AGE
    }
  
  /* clear it out */
  o = db+newobj;
  o->name = 0;
  o->list = 0;
  o->location = NOTHING;
  o->contents = NOTHING;
  o->exits = NOTHING;
  o->parents = NULL;
  o->children = NULL;
  o->link = NOTHING;
  o->next = NOTHING;
  o->owner = NOTHING;
  /*    o->penn = 0;*/
  /* flags you must initialize yourself */
  o->mod_time = 0;
  o->create_time = time(NULL);
  o->zone = NOTHING;
  return newobj;
}

#define DB_MSGLEN 1040

void putref(f,ref)
     FILE *f;
     dbref ref;
{
  fprintf(f, "%d\n", ref);
}

void put_long(f,ref)
     FILE *f;
     long ref;
{
  fprintf(f, "%ld\n", ref);
}

void putstring(f,s)
     FILE *f;
 char *s;
{
  if (s) fputs(s, f);
  fputc('\n', f);
}

/* static char *atr_format P((ATTR *));
static char *atr_format (k)
     ATTR *k;
{
  static char opbuf[100];
  ATRDEF *def;
  int j;

  if (k->obj == NOTHING) {
    sprintf(opbuf,"%d",*(((int *)k)-1)); * get the atr number. kludgy. *
    return opbuf;
  }
  for (j=0,def=db[k->obj].atrdefs; def; def=def->next, j++)
    if (&(def->a) == k) {
      sprintf(opbuf,"%d.%d",k->obj, j);
      return opbuf;
    }
  sprintf(opbuf,"%d.%d",k->obj,0);
  return opbuf;
}
static ATTR *atr_unformat (o, str)
     dbref o;
     char *str;
{
  dbref obj;
  int num;
  int i;
  ATRDEF *atr;

  if (!strchr(str,'.'))
    return builtin_atr(atoi(str));
  *strchr(str,'.') = '\0';
  obj = atoi(str);
  num = atoi(str+strlen(str)+1);
  if (obj>=o) {
    db_grow (obj+1);
    if (!db[obj].atrdefs) {
      db[obj].atrdefs=malloc(sizeof(ATRDEF));
      db[obj].atrdefs->a.name=NULL;
      db[obj].atrdefs->next=NULL;
    }
    for (atr = db[obj].atrdefs, i=0; atr->next && i<num; atr=atr->next, i++)
      ;
    while (i < num) {
      atr->next = malloc( sizeof(ATRDEF));
      atr->next->a.name = NULL;
      atr->next->next = NULL;
      atr = atr->next;
      i++;
    }
  } else
    for (atr=db[obj].atrdefs, i=0; i<num; atr=atr->next, i++)
      ;
  return &(atr->a);
} */

int db_write_object(f,i)
     FILE *f;
     dbref i;
{
  struct object *o;
  ALIST *list;
  
  o = db + i;
  putstring(f, o->name);
  putref(f, o->location);
  putref(f, o->zone);
  putref(f, o->contents);
  putref(f, o->exits);
  putref(f, o->link);
  putref(f, o->next);
  putref(f, o->owner);
  /*    putref(f, Pennies(i));*/
  putref(f, o->flags);
  putref(f, o->mod_time);
  putref(f, o->create_time);
  if(Typeof(i)==TYPE_PLAYER)
    put_powers(f,i);
  /* write the attribute list */
  for(list=o->list;list;list=AL_NEXT(list)) {     
    if (AL_TYPE(list)) { 
      ATTR *x;
      x=AL_TYPE(list);
      if(x && !(x->flags&AF_UNIMP)) {
        if (x->obj == NOTHING) {        /*  builtin attribute. */
          fputc ('>',f);
	  putref (f, ((struct builtinattr *)x)->number); /* kludgy. fix this. xxxx */
          putref (f, NOTHING);
        } else {
          ATRDEF *m;
          int j;
          
          fputc ('>', f);
          
          for (m=db[AL_TYPE(list)->obj].atrdefs, j=0;
               m; m=m->next, j++)
            if ((&(m->a)) == AL_TYPE(list)) {
              putref (f, j);
              break;
            }
          if (!m) {
            putref (f, 0);
            putref (f, NOTHING);
          } else
            putref(f,AL_TYPE(list)->obj);
        }
        putstring (f, uncompress(AL_STR (list)));
      }
    }
  }
  fprintf(f,"<\n");
  putlist(f,o->parents);
  putlist(f, o->children);
  put_atrdefs(f, o->atrdefs);
  return 0;
}

dbref db_write(f)
     FILE *f;
{
  dbref i;
  
  fprintf(f,"@%d\n",DB_VERSION);
  fprintf(f,"~%d\n",db_top);
  for(i = 0; i < db_top; i++) {
    fprintf(f, "&%d\n", i);
    db_write_object(f, i);
  }
  fputs("***END OF DUMP***\n", f);
  write_mail(f);
  fflush(f);
  return(db_top);
}

dbref parse_dbref(s)
 char *s;
{
 char *p;
  long x;
  
  x = atol(s);
  if(x > 0)
    return x;
  else if(x == 0)
    /* check for 0 */
    for(p = s; *p; p++) {
      if(*p == '0') return 0;
      if(!isspace(*p)) break;
    }
  
  /* else x < 0 or s != 0 */
  return NOTHING;
}

dbref getref(f)
     FILE *f;
{
  static char buf[DB_MSGLEN];
  
  fgets(buf, sizeof(buf), f);
  return(atoi(buf));
}

long getlong(f)
     FILE *f;
{
  static char buf[DB_MSGLEN];
  
  fgets(buf, sizeof(buf), f);
  return(atol(buf));
}

 char *getstring_noalloc(f)
     FILE *f;
{
  static char buf[DB_MSGLEN];
  char *p;
  
  fgets(buf, sizeof(buf), f);
  for(p = buf; *p; p++)
    if(*p == '\n') {
      *p = '\0';
      break;
    }
  
  return buf;
}

/*#define getstring(x) alloc_string(getstring_noalloc(x))*/
#define getstring(x,p) {p=NULL;SET(p,getstring_noalloc(x));}

#define getstring_compress(x,p) getstring(x,p)

/* just return the string, for now, we need to convert attrs later */
void getboolexp(i, f)
     dbref i;
     FILE *f;
{
  char buffer[DB_MSGLEN];
  char *p = buffer;
  int c;

  while ((c = getc(f)) != '\n') {
    if (c == ':') { /* snarf up the attribute */
      *p++ = c;
      while ((c = getc(f)) != '\n') *p++ = c;
    } else *p++ = c;
  }
  *p = '\0';
  atr_add(i, A_LOCK, buffer);
}

char *b;

void get_num(s, i)
     char **s;
     int *i;
{
  *i = 0;
  while (**s && isdigit(**s)) {
    *i = (*i * 10) + **s - '0';
    (*s)++;
  }
  return;
}

#define RIGHT_DELIMITER(x) ((x == AND_TOKEN) || (x == OR_TOKEN) || \
                            (x == ':') || (x == '.') || (x == ')') || \
                            (x == '=') || (!x))

void grab_dbref(p)
     char *p;
{
  int num, n;
  dbref thing;
  ATRDEF *atr;
  ATTR *attr;

  get_num(&b, &num);
  switch (*b) {
  case '.':
    b++;
    sprintf(p, "#%d", num);
    p += strlen(p);
    *p++ = '.';
    thing = (dbref) num;
    get_num(&b, &num);
    for (atr=db[thing].atrdefs, n=0; n<num; atr=atr->next, n++);
    strcpy(p, atr->a.name);
    p += strlen(p);
    *p++ = *b++;
    while (!RIGHT_DELIMITER(*b)) *p++ = *b++;
    *p = '\0';
    break;
  case ':':
    b++;
    attr = builtin_atr(num);
    strcpy(p, attr->name);
    p += strlen(p);
    *p++ = ':';
    while (!RIGHT_DELIMITER(*b)) *p++ = *b++;
    *p = '\0';
    break;
  default:
    sprintf(p, "#%d", num);
    break;
  }
  return;
}

int convert_sub(p, outer)
     char *p;
     int outer;
{
  int inner;

  if (!*b) {
    *p = '\0';
    return 0;
  }
  switch (*b) {
  case '(':
    b++;
    inner = convert_sub(p,outer);
    if (*b == ')') b++;
    else {
      p += strlen(p);
      goto part2;
    }
    return inner;
  case NOT_TOKEN:
    *p++ = *b++;
    if ((inner = convert_sub(p+1,outer)) > 0) {
      *p = '(';
      p += strlen(p);
      *p++ = ')';
      *p = '\0';
    } else {
      p++;
      while(*p) *(p-1) = *p++;
      *--p = '\0';
    }
    return inner;
  default:
    /* a dbref of some sort */
    grab_dbref(p);
    p += strlen(p);
  }
 part2:
  switch (*b) {
  case AND_TOKEN:
    *p++ = *b++;
    if ((inner = convert_sub(p+1, 1)) == 2) {
      *p = '(';
      p += strlen(p);
      *p++ = ')';
      *p = '\0';
    } else {
      p++;
      while(*p) *(p-1) = *p++;
      *--p = '\0';
    }
    return 1;
  case OR_TOKEN:
    *p++ = *b++;
    inner = convert_sub(p, 2);
    p += strlen(p);
    return 2;
  default:
    return 0;
  }
}

int is_zone(i)
     dbref i;
{
  dbref j;
  
  for (j = 0; j < db_top; j++)
    if (db[j].zone == i) return 1;
  return 0;
}

void convert_boolexp()
{
  dbref i;
  char buffer[BUFFER_LEN], *p;

  for (i = 0; i < db_top; i++) {
    p = buffer;
    b = atr_get(i, A_LOCK);
    convert_sub(p, 0);
    if ((db[i].flags & ENTER_OK) && (!is_zone(i))) {
      atr_add(i, A_ELOCK, buffer);
      sprintf(buffer,"#%d",db[i].owner);
      atr_add(i, A_LOCK, buffer);
    } else atr_add(i, A_LOCK, buffer);
  }
  return;
}
            

void db_free()
{
  dbref i;
  struct object *o;
  
  if(db) {
    for(i = 0; i < db_top; i++) {
      o = &db[i];
      SET(o->name,NULL);
      atr_free(i);
      /* Everything starts off very old */
    }
    bigfree(db-5);
    db = 0;
    db_init=db_top = 0;
  }
/*  if (db_strings)
    nza_close(db_strings);
  db_strings=nza_open(sizeof(char *));*/
}

/* read attribute list */
int get_list(f, obj, vers)
     FILE *f;
     dbref obj;
     int vers;
{
  ATRDEF *atr;
  int atrnum;
  dbref atrobj;
  dbref old_db_top;
  char *s;
  int c;
  int i;
  
  while(1)
    switch(c=fgetc(f)) { 
    case '>': /* read # then string */
      atrnum = getref(f);
      if (vers <= 7) {
        if (builtin_atr(atrnum) && !(builtin_atr(atrnum)->flags&AF_UNIMP))
          atr_add (obj, builtin_atr(atrnum), s=getstring_noalloc(f));
        else getstring_noalloc(f);
      } else {
        atrobj = getref(f);
        if (atrobj == NOTHING) {
          if (builtin_atr(atrnum) && !(builtin_atr(atrnum)->flags&AF_UNIMP))
            atr_add (obj, builtin_atr(atrnum), s=getstring_noalloc(f));
          else getstring_noalloc(f);
        } else
          if (atrobj >= obj) {  /* ergh, haven't read it in yet. */
            old_db_top = db_top;
            db_grow (atrobj+1);
            db_top = old_db_top;
            if (!db[atrobj].atrdefs) {
              db[atrobj].atrdefs=malloc( sizeof(ATRDEF));
              db[atrobj].atrdefs->a.name = NULL;
              db[atrobj].atrdefs->next = NULL;
            }
            for (atr = db[atrobj].atrdefs, i=0;
                 atr->next && i<atrnum;
                 atr=atr->next, i++)
              ;                 /* check to see if it's already there. */
            while (i < atrnum) {
              atr->next = malloc( sizeof(ATRDEF));
              atr->next->a.name = NULL;
              atr->next->next = NULL;
              atr = atr->next;
              i++;
            }
            atr_add (obj, &(atr->a), s=getstring_noalloc (f));
          } else {
            for (atr=db[atrobj].atrdefs, i=0;
                 i<atrnum; atr=atr->next, i++);
            atr_add (obj, &(atr->a), s=getstring_noalloc (f));
          }
      }
      break;
    case '<': /* end of list */
      if ('\n'!=fgetc(f)) {
        log_error(tprintf("no line feed on object %d",obj));
        return(0);
      }
      return(1);
    default:
      log_error(tprintf("Bad character %c on object %d",c,obj));
      return(0);
    }       
}

object_flag_type upgrade_flags(version, player, flags)
     int version;
     dbref player;
     object_flag_type flags;
{
  long type;
  int iskey, member, chown_ok, link_ok, iswizard;
  
  /* only modify version 1 */
  if ( version > 1 )
    return flags;
  
  /* record info from old bits */
  iskey = (flags & 0x8);        /* if was THING_KEY */
  link_ok = (flags & 0x20);     /* if was LINK_OK */
  chown_ok = (flags & 0x40000); /* if was CHOWN_OK */
  member = (flags & 0x2000);    /* if player was a member */
  iswizard = (flags & 0x10);    /* old wizard bit flag */
  type = flags & 0x3;           /* yank out old object type */
  
  /* clear out old bits */
  flags &= ~TYPE_MASK;  /* set up for 4-bit encoding */
  flags &= ~THING_KEY;  /* clear out thing key bit */
  flags &= ~INHERIT_POWERS;     /* clear out new spec pwrs bit */
  flags &= ~CHOWN_OK;
  flags &= ~LINK_OK;
  
  /* put these bits in their new positions */
  flags |= (iskey)    ? THING_KEY : 0;
  flags |= (link_ok)  ? LINK_OK   : 0;
  flags |= (chown_ok) ? CHOWN_OK  : 0;
#define TYPE_GUEST 0x8
#define TYPE_TRIALPL 0x9
#define TYPE_MEMBER 0xA
#define TYPE_ADMIN 0xE
#define TYPE_DIRECTOR 0xF
  /* encode type under 4-bit scheme */
  /* nonplayers */
  if ( type != 3 )  {
    flags |= type;
    if ( iswizard )
      flags |= INHERIT_POWERS;
  }
  /* god */
  else if ( player == 1 )
    flags |= TYPE_DIRECTOR;
  /* wizards */
  else if ( iswizard )
    flags |= TYPE_ADMIN;
  /* members */
  else if ( member )
    flags |= TYPE_MEMBER;
  /* guests */
  else if ( (flags & PLAYER_MORTAL) )  {
    flags &= ~PLAYER_MORTAL;
    flags |= TYPE_GUEST;
  }
  /* trial players */
  else
    flags |= TYPE_TRIALPL;
#undef TYPE_DIRECTOR
#undef TYPE_GUEST
#undef TYPE_TRIALPL
#undef TYPE_MEMBER
#undef TYPE_ADMIN  
  return flags;
}
void scramble_to_link()
{
  dbref i,j;
  for(i=0;i<db_top;i++) {
    if(Typeof(i) == TYPE_ROOM || Typeof(i)== TYPE_EXIT) {
      db[i].link = db[i].location;
      db[i].location = i;
    } else if(Typeof(i)==TYPE_THING || Typeof(i)>=TYPE_PLAYER) {
      db[i].link = db[i].exits;
      db[i].exits = -1;
    }
  }
  for (i=0;i<db_top;i++) {
    if(Typeof(i)==TYPE_ROOM)
      for(j=db[i].exits;j!= NOTHING;j=db[j].next)
        db[j].location = i;
  }
}

void db_check() /* put quotas in! */
{
  dbref i;
  for(i=0;i<db_top;i++)
    if(Typeof(i)==TYPE_PLAYER) {
      dbref j;
      int cnt=(-1);
      for(j=0;j<db_top;j++)
        if(db[j].owner == i)
          cnt++;
      atr_add(i,A_QUOTA,tprintf("%d",atoi(atr_get(i,A_RQUOTA))+cnt));
    }
}

static int db_read_object P((dbref, FILE *));

void count_atrdef_refcounts P((void))
{
  int i;
  ATRDEF *k;
  ALIST *l;
  for (i=0; i<db_top; i++)
    for (k=db[i].atrdefs; k; k=k->next) {
      k->a.refcount = 1;
    }
  for (i=0; i<db_top; i++)
    for (l=db[i].list; l; l=AL_NEXT(l)) {
      if (AL_TYPE(l))
        ref_atr(AL_TYPE(l));
    }
}

static FILE *db_read_file=NULL;

void db_set_read(f)
     FILE *f;
{
  db_read_file = f;
}
int loading_db = 0;
void run_startups()
{
  dbref i;
  for (i=0; i<db_top; i++) {
    if (*atr_get(i,A_STARTUP))
      parse_que (i, atr_get(i,A_STARTUP), i);
    if (IS(i,TYPE_PLAYER,PLAYER_CONNECT))
      announce_disconnect(i);
  }
}
void load_more_db()
{
  static dbref i = NOTHING;
  int j;

  if (loading_db) return;

  if (i == NOTHING) {
    clear_players();
    db_free();
    i = 0;
  }
  for (j=0; j<123 && i >=0; j++,i++) {
    if (i%1000 == 0) {
      struct descriptor_data *d;
      char buf[1024];
      sprintf(buf,"Please wait: Database loading still in progress. Now loading object #%d of %d.\n",i,db_init*2/3);
      for (d=descriptor_list; d; d=d->next) {
        queue_string(d,buf);
      }
    }
    i = db_read_object (i,db_read_file);
  }
  if (i == -2) {
    loading_db = 1;
    read_mail(db_read_file);
    count_atrdef_refcounts();
    run_startups();
    return;
  }
  if (i == -1) {
    log_error("Couldn't load database; shutting down the muse.");
    exit_nicely(136);
  }
}

dbref db_read(f)
     FILE *f;
{
  dbref i;
  
  clear_players();
  
  db_free();
  for(i = 0;i>=0; i++)
    i = db_read_object (i,f);

  read_mail(f);

  if (i == -2) {
    count_atrdef_refcounts();
    return db_top;              /* it worked! */
  }
  return -1;
}

int dozonetemp;

static int db_read_object (i,f)
     dbref i;
     FILE *f;
{
  int c;
  struct object *o;
 char *end;
  static int db_version = 1;           /* old db's default to v1 */

  c = getc(f);
  switch(c) {     
    /* read version number */
  case '@':
    db_version = getref(f);
    if ( db_version != DB_VERSION )
      log_important(tprintf("Converting DB from v%d to v%d",
                            db_version, DB_VERSION));
    break;
    
    /* make sure database is at least this big *1.5 */
  case '~':
    db_init=(getref(f)*3)/2;
    break;
    
    /* TinyMUSH old object storage definition */
  case '#':
    /* another entry, yawn */
    if(i != getref(f))
      return -2;  /* we blew it */
    
    /* make space */
    db_grow(i+1);
    
    /* read it in */
    o = db+i;
    o->list=NULL;
    getstring(f,o->name);
    s_Desc(i,getstring_noalloc(f));
    o->location = getref(f);
    o->zone = NOTHING;
    o->contents = getref(f);
    o->exits = getref(f);
    o->link = NOTHING;        /* atleast until we scramble_to_link */
    o->next = getref(f);
    o->mod_time = o->create_time = 0;
    getboolexp(i, f);
    s_Fail(i,getstring_noalloc(f));
    s_Succ(i,getstring_noalloc(f));
    s_Ofail(i,getstring_noalloc(f));
    s_Osucc(i,getstring_noalloc(f));
    o->owner = getref(f);
    o->flags = getref(f);     /* temp storage for pennies */
    s_Pennies(i,o->flags);
    o->flags = upgrade_flags(db_version, i, getref(f));
#ifdef DO_AGE
    o->num1=o->num2=i;
#endif
    s_Pass(i,getstring_noalloc(f));
    o->atrdefs = 0;
    o->parents = NULL;
    o->children = NULL;
    o->atrdefs = NULL;
    /* check to see if it's a player */
    if(Typeof(i) == TYPE_PLAYER)
      add_player(i);
    break;
    
    /* TinyMUSH new version object storage definition */
  case '!': /* non-zone oriented database */
  case '&': /* zone oriented database */
    
    
    /* make space */
    i=getref(f);
    db_grow(i+1);
    /* read it in */
    o = db+i;
    getstring(f,o->name);
    o->location = getref(f);
    if ( c == '!' )
      o->zone = NOTHING;
    else if ( db_version >= 3 )
      o->zone = getref(f);
    o->contents = getref(f);
    o->exits = getref(f);
    if(db_version < 5)
      o->link = NOTHING;
    else
      o->link = getref(f);
    o->next = getref(f);
    o->list = NULL;
    if (db_version <= 8) getboolexp(i, f);
    o->owner = getref(f);
    if(db_version<=3) {
      int k;
      k=getref(f);
      s_Pennies(i,k);
    }
    
    o->flags = upgrade_flags(db_version, i, getref(f));
    if (db_version >= 10) {
      o->mod_time = getref(f);
      o->create_time = getref(f);
    } else
      o->mod_time = o->create_time = 0;
    if (db_version <= 10) {
      if (i == 0 && o->zone == NOTHING)
	/* ack. */
	log_error("no #0 zone");
      else if (Typeof(i) == TYPE_ROOM && o->zone == NOTHING)
	o->zone = db[0].zone;
      else if (Typeof(i) != TYPE_ROOM)
	o->zone = NOTHING;
    }
    
    if(db_version >= 6)
      if (Typeof(i) == TYPE_PLAYER) {
        get_powers(i,getstring_noalloc(f));
      } else {
        if(db_version == 6)
          get_powers(i,getstring_noalloc(f));
        o->pows=NULL;
      }
    else {
      o->pows=NULL;           /* we'll fiddle with it later. */
    }
#ifdef DO_AGE
    o->num1=o->num2=i;
#endif
    
    /* read attribute list for item */ 
    if (!get_list (f, i, db_version)) {
      log_error(tprintf("bad attribute list object %d",i));
      return -2;
    }
    if (db_version >7) {
      o->parents = getlist (f);
      o->children = getlist (f);
      o->atrdefs = get_atrdefs (f, o->atrdefs);
    } else {
      o->parents = NULL;
      o->children = NULL;
      o->atrdefs = NULL;
    }
    /* check to see if it's a player */
    if(Typeof(i) == TYPE_PLAYER ||
       (db_version<6 && Typeof(i)>TYPE_PLAYER))  { /* ack! */
      add_player(i);
    }
    break;
    
  case '*':
    end = getstring_noalloc(f);
    if(strcmp(end, "**END OF DUMP***")) {
      /*                  free((void *) end);*/             
      log_error(tprintf("no end of dump %d",i));
      return -2;
    } else {
      extern void zero_free_list P((void));
      /*                  free((void *) end);*/
      log_important("done loading database.");
      zero_free_list();
      db_check();
      if(db_version <6) {
        dbref i;
        atr_add(GOD,A_QUEUE,"-999999"); /* hope we don't have enough players to overflow that. */
        for(i=0;i<db_top;i++) {
          if((db[i].flags&TYPE_MASK) >= TYPE_PLAYER) {
            parse_que(GOD,tprintf("@class #%d=%s",i,
                                  class_to_name(old_to_new_class(db[i].flags&TYPE_MASK))),
                      GOD);
            db[i].flags&=~TYPE_MASK;
            db[i].flags|=TYPE_PLAYER;
            db[i].pows=malloc(2*sizeof(ptype));;
            db[i].pows[1]=0;  /* don't care about the [0]... */
          }
        }
      }
      if (db_version <= 4) scramble_to_link();
      if (db_version <= 8) convert_boolexp();
      if (db_version <= 10 && db_version >= 3) {
	int j;
	/* make the zone heirarchy. */
	for (j=0; j<db_top; j++)
	  if (db[j].zone != NOTHING && db[db[j].zone].zone == NOTHING)
	    db[db[j].zone].zone = db[0].zone;
	if (db[0].zone != NOTHING)
	  db[db[0].zone].zone = NOTHING;
      }
      return -3;
    }
  default:
    log_error(tprintf("failed object %d",i));
    return -2;
  }
  return i;
}
dbref *getlist(f)
     FILE *f;
{
  dbref *op;
  int len;
  len = getref(f);
  if (len == 0) return NULL;
  op = malloc( sizeof(dbref)*(len+1));
  op[len] = NOTHING;
  for (len--;len>=0; len--)
    op[len] = getref(f);
  return op;
}

void putlist(f, list)
     FILE *f;
     dbref *list;
{
  int k;
  if ((!list) || (list[0] == NOTHING)) {
    putref (f, 0);
    return;
  }
  for (k=0; list[k]!=NOTHING; k++);
  putref (f, k);
  for (k--; k>=0; k--)
    putref (f,list[k]);
}

char *unparse_attr (atr, dep)
     ATTR *atr;
     int dep;
{
  static char buf[1000];
  buf[dep]=0;
  if (dep)
    for (dep--; dep>=0; dep--)
      buf[dep] = '+';
  if (atr->obj == NOTHING)
    strcat (buf, atr->name);
  else
    sprintf(buf+strlen(buf),"#%d.%s",atr->obj, atr->name);
  return buf;
}

#define DOATTR(var, name, flags, num) ATTR *var;
#define DECLARE_ATTR
#include "attrib.h"
#undef DECLARE_ATTR
#undef DOATTR

void init_attributes()
{
#define DOATTR(var, name, flags, num) var = builtin_atr(num);
#include "attrib.h"
#undef DOATTR
}

#if 0
ATTR *A_QUEUE;
ATTR *A_LISTEN;
ATTR *A_AHEAR;
ATTR *A_AMHEAR;
ATTR *A_AAHEAR;
ATTR *A_STARTUP;
ATTR *A_HUHTO;
ATTR *A_IT;
ATTR *A_LEAVE;
ATTR *A_OLEAVE;
ATTR *A_ALEAVE;
ATTR *A_ENTER;
ATTR *A_OENTER;
ATTR *A_AENTER;
ATTR *A_SUCC;
ATTR *A_OSUCC;
ATTR *A_ASUCC;
ATTR *A_DROP;
ATTR *A_ODROP;
ATTR *A_ADROP;
ATTR *A_FAIL;
ATTR *A_OFAIL;
ATTR *A_AFAIL;
ATTR *A_PENNIES;
ATTR *A_EFAIL;
ATTR *A_OEFAIL;
ATTR *A_AEFAIL;
ATTR *A_ALIAS;
ATTR *A_CHARGES;
ATTR *A_RUNOUT;
ATTR *A_RQUOTA;
ATTR *A_SEX;
ATTR *A_TZ;
ATTR *A_LAST;
ATTR *A_CHANNEL;
ATTR *A_DOOMSDAY;
ATTR *A_QUOTA;
ATTR *A_PASS;
ATTR *A_ACLONE;
ATTR *A_DESC;
ATTR *A_ODESC;
ATTR *A_ADESC;
ATTR *A_IDESC;
ATTR *A_KILL;
ATTR *A_OKILL;
ATTR *A_AKILL;
ATTR *A_COST;
ATTR *A_PAY;
ATTR *A_OPAY;
ATTR *A_APAY;
ATTR *A_HAVEN;
ATTR *A_IDLE;
ATTR *A_AWAY;
ATTR *A_USE;
ATTR *A_OUSE;
ATTR *A_AUSE;
ATTR *A_MAILK;
#ifdef USE_SPACE  /*  Registers added by Michael Majere  */
ATTR *A_ASHIP;
ATTR *A_SECTOR;
ATTR *A_MASS;
ATTR *A_RADIUS;
ATTR *A_THRUST;
ATTR *A_RATING;
ATTR *A_EFFICIENCY;
ATTR *A_FUEL;
ATTR *A_ACCELERATION;
ATTR *A_VISMULT;
ATTR *A_PWRGEN;
ATTR *A_PWRFUEL;
ATTR *A_SPRSTR;
ATTR *A_HULL;
ATTR *A_RECOVER;
ATTR *A_TYPE;
ATTR *A_ENERGY;
ATTR *A_LINPOSX;
ATTR *A_LINPOSY;
ATTR *A_LINPOSZ;
ATTR *A_LINVELX;
ATTR *A_LINVELY;
ATTR *A_LINVELZ;
ATTR *A_LINACCX;
ATTR *A_LINACCY;
ATTR *A_LINACCZ;
ATTR *A_ANGPOSX;
ATTR *A_ANGPOSY;
ATTR *A_ANGPOSZ;
ATTR *A_ANGVELX;
ATTR *A_ANGVELY;
ATTR *A_ANGVELZ;
ATTR *A_ANGACCX;
ATTR *A_ANGACCY;
ATTR *A_ANGACCZ;
ATTR *A_S0;
ATTR *A_S1;
ATTR *A_S2;
ATTR *A_S3;
ATTR *A_S4;
ATTR *A_S5;
ATTR *A_S6;
ATTR *A_S7;
ATTR *A_S8;
ATTR *A_S9;
#endif
ATTR *A_TALENT;
ATTR *A_DOING;
ATTR *A_RACE;
ATTR *A_MOVE;
ATTR *A_OMOVE;
ATTR *A_AMOVE;
#ifdef EMAIL_CREATE
ATTR *A_EMAIL;
#endif
ATTR *A_LOCK;
ATTR *A_ELOCK;
ATTR *A_ULOCK;
ATTR *A_LLOCK;
ATTR *A_UFAIL;
ATTR *A_OUFAIL;
ATTR *A_AUFAIL;
ATTR *A_OCONN;
ATTR *A_ACONN;
ATTR *A_ODISC;
ATTR *A_ADISC;
ATTR *A_COLUMNS;
ATTR *A_WHOFLAGS;
ATTR *A_WHONAMES;
ATTR *A_APAGE;
ATTR *A_APEMIT;
ATTR *A_AWHISPER;
#ifdef USE_DOING
ATTR *A_DOING;
#endif
ATTR *A_LFAIL;
ATTR *A_OLFAIL;
ATTR *A_ALFAIL;
ATTR *A_SLOCK;
ATTR *A_SFAIL;
ATTR *A_OSFAIL;
ATTR *A_ASFAIL;
ATTR *A_USERS;
ATTR *A_DEFOWN;

ATTR *A_LHIDE;
ATTR *A_LPAGE;

ATTR *A_WARNINGS;
ATTR *A_WINHIBIT;

ATTR *A_ANEWS;

void init_attributes()
{
  A_OSUCC = builtin_atr(1);
  A_OFAIL = builtin_atr(2);
  A_FAIL = builtin_atr(3);
  A_SUCC = builtin_atr(4);
  A_PASS = builtin_atr(5);
  A_DESC = builtin_atr(6);
  A_SEX = builtin_atr(7);
  A_ODROP = builtin_atr(8);
  A_DROP = builtin_atr(9);
  A_OKILL = builtin_atr(10);
  A_KILL = builtin_atr(11);
  A_ASUCC = builtin_atr(12);
  A_AFAIL = builtin_atr(13);
  A_ADROP = builtin_atr(14);
  A_AKILL = builtin_atr(15);
  A_USE = builtin_atr(155);
  A_OUSE = builtin_atr(156);
  A_AUSE = builtin_atr(157);
  A_CHARGES = builtin_atr(17);
  A_RUNOUT = builtin_atr(18);
  A_STARTUP = builtin_atr(19);
  A_ACLONE = builtin_atr(20);
  A_APAY = builtin_atr(21);
  A_OPAY = builtin_atr(22);
  A_PAY = builtin_atr(23);
  A_COST = builtin_atr(24);
  A_LISTEN = builtin_atr(26);
  A_AAHEAR = builtin_atr(27);
  A_AMHEAR = builtin_atr(28);
  A_AHEAR = builtin_atr(29);
  A_LAST = builtin_atr(30);
  A_QUEUE = builtin_atr(31);
  A_IDESC = builtin_atr(32);
  A_ENTER = builtin_atr(33);
  A_OENTER = builtin_atr(34);
  A_AENTER = builtin_atr(35);
  A_ADESC = builtin_atr(36);
  A_ODESC = builtin_atr(37);
  A_RQUOTA = builtin_atr(38);
  A_IDLE = builtin_atr(39);
  A_AWAY = builtin_atr(40);
  A_MAILK = builtin_atr(41);
  A_ALIAS = builtin_atr(42);
  A_EFAIL = builtin_atr(43);
  A_OEFAIL = builtin_atr(44);
  A_AEFAIL = builtin_atr(45);
  A_IT = builtin_atr(46);
  A_LEAVE = builtin_atr(47);
  A_OLEAVE = builtin_atr(48);
  A_ALEAVE = builtin_atr(49);
  A_CHANNEL = builtin_atr(50);
  A_QUOTA = builtin_atr(51);
  A_PENNIES = builtin_atr(52);
  A_HUHTO = builtin_atr(53);
  A_HAVEN = builtin_atr(54);
  A_TZ = builtin_atr(57);
  A_DOOMSDAY = builtin_atr(58);
  A_MOVE = builtin_atr(126);
  A_OMOVE = builtin_atr(127);
  A_AMOVE = builtin_atr(128);
#ifdef EMAIL_CREATE
  A_EMAIL = builtin_atr(59);
#endif
  A_LOCK = builtin_atr(129);
  A_ELOCK = builtin_atr(130);
  A_ULOCK = builtin_atr(131);                  
  A_UFAIL = builtin_atr(132);
  A_OUFAIL = builtin_atr(133);
  A_AUFAIL = builtin_atr(134);
  A_OCONN = builtin_atr(135);
  A_ACONN = builtin_atr(136);
  A_ODISC = builtin_atr(137);
  A_ADISC = builtin_atr(138);
  A_COLUMNS = builtin_atr(139);
  A_WHOFLAGS = builtin_atr(140);
  A_WHONAMES = builtin_atr(141);
  A_APAGE = builtin_atr(142);
  A_APEMIT = builtin_atr(143);
  A_AWHISPER = builtin_atr(144);
  A_LLOCK = builtin_atr(161);
  A_LFAIL = builtin_atr(162);
  A_OLFAIL= builtin_atr(163);
  A_ALFAIL= builtin_atr(164);
  A_SLOCK = builtin_atr(165);
  A_SFAIL = builtin_atr(166);
  A_OSFAIL= builtin_atr(167);
  A_ASFAIL= builtin_atr(168);
  A_USERS = builtin_atr(170);
  A_DEFOWN = builtin_atr(171);

#ifdef USE_SPACE  /*  Registers added by Michael Majere  */
  A_ASHIP  = builtin_atr(60);
  A_SECTOR = builtin_atr(61);
  A_MASS   = builtin_atr(62);
  A_RADIUS = builtin_atr(63);
  A_THRUST = builtin_atr(64);
  A_RATING = builtin_atr(65);
  A_EFFICIENCY = builtin_atr(66);
  A_FUEL   = builtin_atr(67);
  A_ACCELERATION = builtin_atr(68);
  A_VISMULT = builtin_atr(69); 
  A_PWRGEN  = builtin_atr(70);
  A_PWRFUEL = builtin_atr(71);
  A_SPRSTR  = builtin_atr(72);
  A_HULL    = builtin_atr(73);
  A_RECOVER = builtin_atr(74);
  A_TYPE    = builtin_atr(75);
  A_ENERGY  = builtin_atr(76);
  A_LINPOSX = builtin_atr(80);
  A_LINPOSY = builtin_atr(81);
  A_LINPOSZ = builtin_atr(82);
  A_LINVELX = builtin_atr(83);
  A_LINVELY = builtin_atr(84);
  A_LINVELZ = builtin_atr(85);
  A_LINACCX = builtin_atr(86);
  A_LINACCY = builtin_atr(87);
  A_LINACCZ = builtin_atr(88);
  A_ANGPOSX = builtin_atr(89);
  A_ANGPOSY = builtin_atr(90);
  A_ANGPOSZ = builtin_atr(91);
  A_ANGVELX = builtin_atr(92);
  A_ANGVELY = builtin_atr(93);
  A_ANGVELZ = builtin_atr(94);
  A_ANGACCX = builtin_atr(95);
  A_ANGACCY = builtin_atr(96);
  A_ANGACCZ = builtin_atr(97);
#endif

  A_TALENT = builtin_atr(98);
  A_RACE = builtin_atr(99);

  A_LHIDE = builtin_atr(158);
  A_LPAGE = builtin_atr(159);

#ifdef USE_SPACE  /* Registers added by Michael Majere  */
A_S0 = builtin_atr(145);
A_S1 = builtin_atr(146);
A_S2 = builtin_atr(147);
A_S3 = builtin_atr(148);
A_S4 = builtin_atr(149);
A_S5 = builtin_atr(150);
A_S6 = builtin_atr(151);
A_S7 = builtin_atr(152);
A_S8 = builtin_atr(153);
A_S9 = builtin_atr(154);
#endif
  A_DOING = builtin_atr(169);
  A_WARNINGS = builtin_atr(172);
  A_WINHIBIT = builtin_atr(173);
  A_ANEWS = builtin_atr(174);
}
#endif