dmuck0.15-beta/docs/muf/
dmuck0.15-beta/game/
dmuck0.15-beta/game/logs/
dmuck0.15-beta/game/muf/
dmuck0.15-beta/game/muf/text/
#include <stdio.h>
#include <unistd.h>

#include "copyright.h"
#include "config.h"
#include "db.h"
#include "externs.h"
#include "params.h"
#include "lru.h"

#ifdef USE_DBP

#define BUFFER_LEN 1024

#define FREE_IT 1
#define SAVE_IT 0

#define END_MOVE    "***Property list end ***"    /* 24 */
#define BEGIN_MOVE  "***Property list start ***"  /* 26 */

#define MAXOBJS 256

#define FUDGE_FACTOR 32
#define PEROBJECT_FUDGE 55
#define PERLINE_FUDGE 3

/* change this variable on the fly to resize cache. */
/* make it < 1 and you are doomed.                  */
/* be afraid.  be very afraid                       */
int dbp_max_objects = MAXOBJS;

static int enable = 0;
static int lock = 0;

static FILE *map, *data;

/* calculate the disk space needed to store the property entries for a
   single object.  There's probably a more elegant solution, but this
   one is sure to work.
 */

static int calclen = 0;
static int totallen = 0;

static int digitsin(int x)
{
   int y = 1;

   while (x /= 10)
      y++;

   return y;
}

/* old one, it's buggy...  I'll buy you a pizza if you can tell me why
	-- Doran
static void calc_putprop_recurse(propdir *p)
{
  int end;  

  for (; p; p = p->next)
  {
    if (p->child)
    {
      end = calclen;
      calclen += strlen(p->name) + 1;
      calc_putprop_recurse(p->child);
      calclen = end;
    }
    if (p->data)
    {
      totallen += calclen + strlen(p->name) + 
         digitsin(p->perms) + strlen(p->data) + PERLINE_FUDGE;
    }
  }
}
*/

/* if this one doesn't work I'll hang it up right now. */

char buf[BUFFER_LEN * 16];
char buf2[BUFFER_LEN * 16];

void calc_putprop_recurse(propdir *p)
{
  char *end;

  for (; p; p = p->next)
  {
    if (p->child)
    {
      end = buf2 + strlen(buf2);
      strcat(buf2, p->name);
      strcat(buf2, "/");
      calc_putprop_recurse(p->child);
      *end = '\0';
    }
    if (p->data)
    {
      sprintf (buf, "%s%s:%d:%s\n", buf2, p->name, p->perms, p->data);
      /* fputs(buf, f); */
		totallen += strlen(buf);
    }
  }
}

static int calc_putprop(dbref obj)
{
  calclen = totallen = 0;
  calc_putprop_recurse(DBFETCHPROP(obj));
  return (totallen + PEROBJECT_FUDGE + digitsin(obj));
}

void dbp_lock(void)
{
   lock++;
}

void dbp_unlock(void)
{
   lock--;
}

int dbp_enable(char *name)
{
   char fname[BUFFER_LEN];

   sprintf(fname, "%s.map", name);

   map = fopen(fname, "r+");

   if (map == NULL)
   {
      fprintf(stderr, "Trouble opening map file %s.\n", fname);
      return 1;
   }

   sprintf(fname, "%s.dat", name);

   data = fopen(fname, "r+");

   if (data == NULL)
   {
      fprintf(stderr, "Trouble opening data file %s.\n", fname);
      return 1;
   }

   enable = 1;
        return 0;
}

void dbp_disable(void)
{
   if (enable != 1)
      return;

   fclose(map);
   fclose(data);

   enable = 0;
}

static void dbp_unload(long what, int freeflag)
{
   long tmp[2];
   int size;
   long start, end;

   if (enable == 0)
      return;

   if (lock > 0)
      return;
   lock++;

   size = calc_putprop(what);

   if (size <= DBFETCH(what)->dbp_size)
   {
      fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
      fread(tmp, sizeof(long), 2, map);
      fseek(data, tmp[1], SEEK_SET);
   }
   else
   {
      fseek(data, 0L, SEEK_END);
      /* we're bigger now, remember that */
      DBSTORE(what, dbp_size, size);
   }

   if(DBFETCH(what)->properties)
   {
      tmp[0] = what;
      tmp[1] = ftell(data);
   }
   else
   {
      tmp[0] = -1L;
      tmp[1] = -1L;
      DBSTORE(what, dbp_size, -1L);
      /* free me do me */
   }

   fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
   fwrite(tmp, sizeof(long), 2, map);
	fflush(map);

   if (DBFETCH(what)->properties)
   {
      start = ftell(data);
      fprintf(data, "%s - %ld\n", BEGIN_MOVE, what);
      putproperties(data, what);
      fprintf(data, "%s\n", END_MOVE);
		fflush(data);
      end = ftell(data);

      if ((end - start) != size)
      {
         /* oh shit, we've got a boo boo, spew errors like */
         /* a sunovabitch and exit (we're hopelessly       */
         /* screwed by this point)                         */

         fprintf(stderr, "DBP: Fatal Error!\n");
         fprintf(stderr, "   : %ld -> %d/%d\n", what, (end - start), size);
         fprintf(stderr, "%s - %ld\n", BEGIN_MOVE, what);
         putproperties(stderr, what);
         fprintf(stderr, "%s\n", END_MOVE);

         exit(0xbabe);
      }

      if (freeflag == FREE_IT)
      {
         burn_proptree(DBFETCH(what)->properties);
         DBFETCH(what)->properties = NULL;
      }
   }

   lock--;
}

void dbp_load(long what)
{
   long offset[2];

   if (enable == 0)
      return;

   if (lock > 0)
      return;
   lock++;

   if (lru_hasp(what) == 1)
   {
      lock--;
      return;
   }
   
   if (DBFETCH(what)->properties != NULL)
   {
      lock--;
      lru_use(what);
      return;
   }

   lru_use(what);

   offset[0] = sizeof(long) * 2 * (what + 1);

   fseek(map, offset[0], SEEK_SET);

   fread(offset, sizeof(long), 2, map);

   if (offset[0] == -1L || offset[1] == -1L)
	{
      offset[0] = -1L;
      offset[1] = -1L;
      fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
      fwrite(offset, sizeof(long), 2, map);
		fflush(map);
      DBSTORE(what, dbp_size, -1);
   }
   else if (offset[0] == what)
   {
      fseek(data, offset[1], SEEK_SET);
      getproperties(data, what, 1); /* check me do me */
      if (DBFETCH(what)->dbp_size == -1L)
         DBSTORE(what, dbp_size, calc_putprop(what));
   }

   while (lru_count() > dbp_max_objects)
      dbp_unload(lru_old(), FREE_IT);

   lock--;
}

void dbp_flush(void)
{
   if (enable == 0)
      return;

   while (lru_count() > 0)
      dbp_unload(lru_old(), FREE_IT);
}

void dbp_sync(void)
{
   dbref spot;

   if (enable == 0)
      return;

   for (spot = lru_head(); spot != NOTHING; spot = DBFETCH(spot)->lru_next)
   {
      dbp_unload(spot, SAVE_IT);
   }
}

void dbstoreprop(long what, propdir *p)
{
   dbp_load(what);
   DBSTORE(what, properties, p);
}

propdir *dbfetchprop(long what)
{
  dbp_load(what);
  return (DBFETCH(what)->properties);
}

#endif