/* $Header: /belch_a/users/rearl/tinymuck/include/RCS/db.h,v 1.10 90/09/28 12:15:15 rearl Exp $
 *
 * $Log:	db.h,v $
 * Revision 1.10  90/09/28  12:15:15  rearl
 * Added shared string structures to interp.c.
 * 
 * Revision 1.9  90/09/18  08:05:45  rearl
 * Took out FILTER, added INTERNAL.  Moved stuff to params.h
 * 
 * Revision 1.8  90/09/16  13:59:03  rearl
 * Disk based preparation code added.
 * 
 * Revision 1.7  90/09/13  06:33:20  rearl
 * MAX_VAR increased to 53 == 50 user variables.
 * 
 * Revision 1.6  90/09/01  06:03:46  rearl
 * Took out TEST_MALLOC references.
 * 
 * Revision 1.5  90/08/27  14:06:31  rearl
 * Disk-based MUF source code and added necessary locks.
 * 
 * Revision 1.4  90/08/15  03:50:57  rearl
 * Added some new macros and made others more useful...
 * 
 * Revision 1.3  90/07/29  17:16:43  rearl
 * Moved some things to config.h, minor change in programs to allow
 * locks to rooms, @# in rooms, etc.
 * 
 * Revision 1.2  90/07/19  23:06:07  casie
 * Removed comment log at top.
 * 
 * 
 */
#include "copyright.h"

#ifndef __DB_H
#define __DB_H

#include <stdio.h>

extern void *malloc(unsigned long);
extern void *realloc(void *, unsigned long);
extern void free(void *);

extern char match_args[BUFSIZ];

typedef int dbref;		/* offset into db */

#define getstring(x) alloc_string(getstring_noalloc(x))

#ifdef COMPRESS
#define alloc_compressed(x) alloc_string(compress(x))
#define getstring_compress(x) alloc_string(compress(getstring_noalloc(x)))
#define get_compress(x) compress(x)
#define get_uncompress(x) uncompress(x)
#else
#define alloc_compressed(x) alloc_string(x)
#define getstring_compress(x) getstring(x)
#define get_compress(x) (x)
#define get_uncompress(x) (x)
#endif /* COMPRESS */

#ifdef GDBM_DATABASE
#define DBFETCH(x)	dbfetch(x)
#define DBDIRTY(x)	dbdirty(x)
#else /* !GDBM_DATABASE */
#define DBFETCH(x)	(db + (x))
#define DBDIRTY(x)	/* nothing */
#endif
#define DBSTORE(x, y, z)    {DBFETCH(x)->y = z; DBDIRTY(x);}
#define NAME(x)		(db[x].name)
#define FLAGS(x)	(db[x].flags)
#define OWNER(x)	(db[x].owner)

#define TYPE_ROOM 	0x0
#define TYPE_THING 	0x1
#define TYPE_EXIT 	0x2
#define TYPE_PLAYER 	0x3
#define TYPE_PROGRAM    0x4     /* related structures */
#define TYPE_DAEMON     0x5     /* but not the same thing */
#define TYPE_GARBAGE	0x6
#define NOTYPE		0x7	/* no particular type */
#define TYPE_MASK 	0x7	/* room for expansion */
#define ANTILOCK	0x8	/* negates key (*OBSOLETE*) */
#define WIZARD		0x10	/* gets automatic control */
#define LINK_OK		0x20	/* anybody can link to this room */
#define DARK		0x40	/* contents of room are not printed */
#define INTERNAL        0x80    /* internal-use-only flag */
#define STICKY		0x100	/* this object goes home when dropped */

#define BUILDER		0x200	/* this player can use construction commands */

#ifdef PLAYER_CHOWN
#define	CHOWN_OK	0x400	/* this player can be @chowned to */
#endif /* PLAYER_CHOWN */

#define JUMP_OK		0x800	/* A room which can be Trumped from, or */
/* a player who can be Trumped to */
#define GENDER_MASK	0x3000	/* 2 bits of gender */
#define GENDER_SHIFT	12	/* 0x1000 is 12 bits over (for shifting) */
#define GENDER_UNASSIGNED	0x0	/* unassigned - the default */
#define GENDER_NEUTER	0x1	/* neuter */
#define GENDER_FEMALE	0x2	/* for women */
#define GENDER_MALE	0x3	/* for men */

#define BUSY_MACHINE	0x4000	/* Machine busy... commands are delayed */

#define PUPPET          0x8000  /* Owner hears everything. */

#define HALTED          0x10000
#ifdef HAVEN
#undef HAVEN
#define HAVEN HALTED
#endif /* HAVEN */

#define ARCHITECT       0x20000    /* super builder */
#ifdef ABODE
#undef ABODE
#define ABODE ARCHITECT
#endif /* ABODE */

#define MAGE            0x40000    /* programmer */
#define QUELL           0x80000
#define ENTER_OK	0x100000    /* Things can be given to it, and you can
				      'enter' it. */
#define INTERACTIVE     0x200000   /* when this is set, player is either
				    * editing a program or in a READ.
				    */
#define OPAQUE          0x400000   /* can't see into this player/room's
                                      /object's contents */
#define VISIBLE         0x800000   /* can be ex'd by other people */
typedef long object_flag_type;

#define GOD ((dbref) 1)
#define is_god(x) ((x) == (GOD))

#define DoNull(s) ((s) ? (s) : "")

#define Typeof(x) (x == HOME ? TYPE_ROOM : \
		   ((x >= db_top || x < 0) ? TYPE_GARBAGE : \
		    (FLAGS(x) & TYPE_MASK)))
#ifndef ABODE
#define Linkable(x) ((x) == HOME || ((FLAGS(x) & LINK_OK) != 0))
#else /* ABODE */
#define Linkable(x) ((x) == HOME || ((Typeof(x) == TYPE_ROOM ? \
                                      (FLAGS(x) & ABODE) : \
                                      (FLAGS(x) & LINK_OK)) != 0))
#endif /* ABODE */

/* Properties lists */
struct plist
{
  const char *type;              /* kind of property -- e.g. "sex" */
  const char *class;             /* value of this property  -- e.g. "male" */
  struct plist  *next;           /* next item on property list */
/*  struct plist *child; */      /* propdirs not implemented */
};

/* property lists are used thus:
   
   @set me=property:class
   
   As of right now, the value field is not used, but it is there for later
   expansion.
   
   SEX is no longer going to be a flag, it's going to be a property, so that
   locks can lock against the sex of the character.                         */

/* Boolean expressions, for locks */
typedef char boolexp_type;

#define BOOLEXP_AND 0
#define BOOLEXP_OR 1
#define BOOLEXP_NOT 2
#define BOOLEXP_CONST 3
#define BOOLEXP_PROP 4

struct boolexp {
  boolexp_type type;
  struct boolexp *sub1;
  struct boolexp *sub2;
  dbref thing;
  struct plist   *prop_check;
};

#define TRUE_BOOLEXP ((struct boolexp *) 0)

/* special dbref's */
#define NOTHING ((dbref) -1)		/* null dbref */
#define AMBIGUOUS ((dbref) -2)		/* multiple possibilities, for matchers */
#define HOME ((dbref) -3)		/* virtual room, represents mover's home */

/* editor data structures */

/* Line data structure */
struct line
{
  const char   *this_line;             /* the line itself */
  struct line *next, *prev;      /* the next line and the previous line */
};

/* stack and object declarations */
#define PROG_PRIMITIVE   1         /* forth primitives and hard-coded C routines */
#define PROG_STRING      2         /* string types */
#define PROG_INTEGER     3         /* integer types */
#define PROG_ADD         4         /* program address --- used in calls and jumps */
#define PROG_OBJECT      5         /* database objects */
#define PROG_VAR         6         /* variables */
#define PROG_CON         7         /* descriptors */
#define PROG_BOOLEXP     8         /* Boolexp... */

#define MAX_VAR         53         /* maximum number of variables including
				      the basic ME and LOC                */
#define RES_VAR          3         /* no of reserved variables */

#define STACK_SIZE       512       /* maximum size of stack */

struct shared_string		   /* for sharing strings in programs */
{
  int links;			   /* number of pointers to this struct */
  int length;			   /* length of string data */
  char data[1];		           /* shared string data */
};
#define CLEAR(C) { if ((C)->type == PROG_STRING && (C)->data.string && \
		       --(C)->data.string->links == 0) \
			 free((void *) (C)->data.string);}

struct inst                        /* instruction */
{
  short      type;
  union
    {
      struct shared_string *string;
      int      number;             /* used for both primitives and integers */
      dbref    objref;             /* object reference */
      struct descriptor_data *con;
      struct inst    *call;        /* use in IF and JMPs */
      struct boolexp *boolexp;	   /* for boolexp. (obvious) */
    } data;
};

struct stack
{
  int   top;
  struct inst    st[STACK_SIZE];
};

struct frame                       /* frame data structure necessary
				      for executing programs */
{
  struct stack    system;            /* system stack */
  struct stack    argument;          /* argument stack */
  struct inst     variables[MAX_VAR];/* variables */
  struct inst     *pc;             /* next executing instruction */
  int             writeonly;       /* This program should not do reads */
};

/* union of type-specific fields */

union specific {
  struct {
    dbref *dest;
    int ndest;
  } exit;
  struct {			/* THING-specific fields */
    int  value;
  } thing;
  struct {			/* PLAYER-specific fields */
    int  pennies;
    const char  *password;
  } player;
  struct {                    /* PROGRAM-specific fields */
    struct line *first;     /* first line */
    int    siz;             /* size of code */
    int    curr_line;       /* current-line */
    struct inst *code;      /* byte-compiled code */
    struct inst *start;     /* place to start executing */
  } program;
  struct {                    /* DAEMON-specific fields */
    struct line  *first;
    int    curr_line;
    int    siz;             /* size of code */
    struct inst *code;
    struct inst *start;     /* place to start executing */
    int    cycles;          /* execute per n cycles */
    struct frame *run;
  } daemon;
};

struct object {	
  const char *name;
  dbref link,exits;		/* link and exits */
  dbref location;		/* pointer to container */
  dbref owner;
  dbref contents;
  dbref next;			/* pointer to next in contents/exits chain */
  /* Program junk. */
  dbref  curr_prog;       /* program I'm currently editing */
  int    insert_mode;     /* in insert mode? */
  struct frame   *run;

  struct boolexp *key;	/* if not NOTHING, must have this to do op */
  struct plist *attributes;
  struct plist *properties;
  object_flag_type flags;
  union specific  sp;
};

struct macrotable {
  char *name;
  char *definition;
  dbref implementor;
  struct macrotable *left;
  struct macrotable *right;
};

/* Possible data types that may be stored in a hash table */
union u_hash_data {
  int ival;             /* Store compiler tokens here */
  dbref dbval;          /* Player hashing will want this */
  void *pval;           /* Can't hurt, we might need it someday */
};

/* The actual hash entry for each item */
struct t_hash_entry {
  struct t_hash_entry *next;   /* Pointer for conflict resolution */
  const char *name;                  /* The name of the item */
  union u_hash_data dat;       /* Data value for item */
};

typedef union u_hash_data   hash_data;
typedef struct t_hash_entry hash_entry;
typedef hash_entry          *hash_tab;

#define PLAYER_HASH_SIZE   (1 << 12) /* Table for player lookups */
#define COMP_HASH_SIZE     (1 << 6)  /* Table for compiler keywords */

extern struct object *db;
extern struct macrotable *macrotop;
extern dbref db_top;
extern dbref recyclable;

extern struct shared_string *alloc_prog_string(const char *);

extern dbref new_object();	/* return a new object */

extern dbref getref (FILE *);   /* Read a database reference from a file. */

extern void putref (FILE *, dbref); /* Write one ref to the file */

extern struct boolexp *getboolexp(FILE *); /* get a boolexp */
extern void putboolexp(FILE *, struct boolexp *); /* put a boolexp */

extern int db_write_object(FILE *, dbref); /* write one object to file */

extern dbref db_write(FILE *f);	/* write db to file, return # of objects */

extern dbref db_read(FILE *f);	/* read db from file, return # of objects */
/* Warning: destroys existing db contents! */

extern void free_boolexp(struct boolexp *);
extern void db_free(void);

extern dbref parse_dbref(const char *);	/* parse a dbref */

#define DOLIST(var, first) \
  for((var) = (first); (var) != NOTHING; (var) = DBFETCH(var)->next)
#define PUSH(thing, locative) \
{DBSTORE((thing), next, (locative)); (locative) = (thing);}
#define getloc(thing) (DBFETCH(thing)->location)

/*
  Usage guidelines:
  
  To obtain an object pointer use DBFETCH(i).  Pointers returned by DBFETCH
  may become invalid after a call to new_object().
  
  To update an object, use DBSTORE(i, f, v), where i is the object number,
  f is the field (after ->), and v is the new value.
  
  If you have updated an object without using DBSTORE, use DBDIRTY(i) before
  leaving the routine that did the update.
  
  When using PUSH, be sure to call DBDIRTY on the object which contains
  the locative (see PUSH definition above).
  
  Some fields are now handled in a unique way, since they are always memory
  resident, even in the GDBM_DATABASE disk-based muck.  These are: name,
  flags and owner.  Refer to these by NAME(i), FLAGS(i) and OWNER(i).
  Always call DBDIRTY(i) after updating one of these fields.
  
  The programmer is responsible for managing storage for string
  components of entries; db_read will produce malloc'd strings.  The
  alloc_string routine is provided for generating malloc'd strings
  duplicates of other strings.  Note that db_free and db_read will
  attempt to free any non-NULL string that exists in db when they are
  invoked.  
  */
#endif /* __DB_H */


#define MUCKER MAGE
extern char buf[8192]; /* change this if BUFFER_LEN is changed. */