dbm/
misc/
old-docs/
/* dbmcmds.c */

#include "copyright.h"
#include "config.h"

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

#include "teeny.h"
#include "dbm.h"

void            text_dump2();
void            putlock2();

#ifdef COMPRESS
extern char    *uncompress();
#endif

extern int      atoi();

/*
 * Implements the other db manager commands.
 */


struct nuked {
  int             obj;
  struct nuked   *next;
};

int             lists_handle(z, ex, req)
  char           *z;
  char           *ex;
  char           *req;
{
  register int    i;
  int             loc;
  int             flags;

  /* first we nuke all the lists in the db. what fun.. */

  printf("Spamming...\n");
  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;
    if (set_int_elt(i, EXITS, -1) == -1)
      printf("Object #%d has a bad exits pointer.\n", i);
    if (set_int_elt(i, CONTENTS, -1) == -1)
      printf("Object #%d has a bad contents pointer.\n", i);
    if (set_int_elt(i, NEXT, -1) == -1)
      printf("Object #%d has a bad next pointer.\n", i);
  }

  /* now we rebuild everything. loc had better have been correct... */

  printf("Rebuilding...\n");
  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;
    if (get_int_elt(i, LOC, &loc) == -1) {
      printf("Object #%d has a bad location reference. Destroy it.\n", i);
      continue;
    }
    if (get_int_elt(i, FLAGS, &flags) == -1) {
      printf("Object #%d has a bad flags reference. Destroy it.\n", i);
      continue;
    }
    switch (flags & TYPE_MASK) {
    case TYP_THING:
    case TYP_PLAYER:
      list_add(i, loc, CONTENTS_LIST);
      break;
    case TYP_EXIT:
      list_add(i, loc, EXITS_LIST);
      break;
    case TYP_ROOM:
      list_add(i, loc, ROOMS_LIST);
      break;
    default:
      printf("Object #%d has a bad type. Destroy it.\n", i);
    }
  }

  printf("Done.\n");
}

int             pur_handle(p, ex, req)
  char           *p;
  atom           *ex;
  int            *req;
{
  int             i;
  int             flags;
  int             ptr;		/* home, dest or dropto */

  struct nuked   *nuked_list = NULL;
  struct nuked   *tmp, *nuked_this;

  printf("Purging.\n");

  /* Make one pass over the db killing stuff, and keeping track */
  /* of what's been killed so far.                              */

  for (i = 0; i < db_top(); i++) {
    if (exists_object(i) && eval_expr(i, ex, *req)) {
      recycle_obj(i, &nuked_list);
      nuked_this = (struct nuked *)
	ty_malloc(sizeof(struct nuked), "purge");
      nuked_this->next = nuked_list;
      nuked_this->obj = i;
      nuked_list = nuked_this;
    }
  }

  /* Another pass over the DB, checking destinations, and */
  /* Handling them as best we can. Reset homes to 0 and   */
  /* simply unlink exits/rooms pointed at nuked things.   */

  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;

    /* This depends heavily on the fact that */
    /* Destination, Home, and DropTo are all */
    /* The same element of an object.        */

    if (get_int_elt(i, DESTINATION, &ptr) == -1)
      goto dropthru;

    /* See if the destination has been nuked. */

    for (tmp = nuked_list; tmp != NULL; tmp = tmp->next) {
      if (tmp->obj == ptr)
	break;
    }
    if (tmp == NULL)
      continue;

    /* If we get here, the dest HAS been nuked. */

    if (get_int_elt(i, FLAGS, &flags) == -1)
      goto dropthru;

    switch (flags & TYPE_MASK) {
    case TYP_PLAYER:
      if (set_int_elt(i, DESTINATION, STARTING_LOC) == -1)
	goto dropthru;
      break;
    case TYP_THING:
      {
	int             home, owner;

	if (get_int_elt(i, OWNER, &owner) == -1)
	  goto dropthru;
	if (get_int_elt(owner, HOME, &home) == -1)
	  goto dropthru;
	if (set_int_elt(i, HOME, home) == -1)
	  goto dropthru;
      }
      break;
    case TYP_ROOM:
    case TYP_EXIT:
      if (set_int_elt(i, DESTINATION, -1) == -1)
	goto dropthru;
      break;
    }
  }
  free_nuked_list(nuked_list);
  return (0);
dropthru:
  printf("Bad DB reference in 2nd pass at object %d\n", i);
  free_nuked_list(nuked_list);
  return (-1);
}

free_nuked_list(nk)
  struct nuked   *nk;
{
  struct nuked   *tmp;

  if (nk == NULL) {
    return;
  }
  do {
    tmp = nk->next;
    free((char *) nk);
    nk = tmp;
  } while (tmp != NULL);
}

int             cho_handle(p, ex, req)
  char           *p;
  atom           *ex;
  int            *req;
{
  int             i, newowner;

  while (isspace(*p))
    p++;
  if (*p++ != '#') {
    printf("Invalid object number for new owner.\n");
    return (0);
  }
  newowner = atoi(p);

  printf("Chowning selected objects to #%d\n", newowner);

  for (i = 0; i < db_top(); i++) {
    if (exists_object(i) && eval_expr(i, ex, *req)) {
      if (set_int_elt(i, OWNER, newowner) == -1) {
	printf("Bad object ref at %d\n", i);
	return (-1);
      }
    }
  }
  return (0);
}

int             sum_handle(p, ex, req)
  char           *p;
  atom           *ex;
  int            *req;

{
  int             i;
  char           *name;
  int             owner;
  char           *ownername;
  int             flags;
  char           *q, ch = '\0', work[BUFFSIZ];

  for (i = 0; i < db_top(); i++) {
    if (exists_object(i) && eval_expr(i, ex, *req)) {

      /* Summarize the data for this guy */

      if (get_str_elt(i, NAME, &name) == -1) {
	printf("DB error at object #%d\n", i);
	continue;
      }
      if (get_int_elt(i, OWNER, &owner) == -1) {
	printf("DB error at object #%d\n", i);
	continue;
      }
      if (get_str_elt(owner, NAME, &ownername) == -1) {
	printf("DB error at object #%d\n", owner);
	continue;
      }
      if (get_int_elt(i, FLAGS, &flags) == -1) {
	printf("DB error at object #%d\n", i);
	continue;
      }
      /* We've got the data. Write it out. */

      if (isplayer(i)) {
	for (q = name; *q && *q != ' '; q++);
	ch = *q;
	*q = '\0';
      }
      printf("(#%d)  Name: %s\n", i, name);
      if (ch)
	*q = ch;

      if (isplayer(owner)) {
	for (q = ownername; *q && *q != ' '; q++);
	ch = *q;
	*q = '\0';
      }
      switch (flags & TYPE_MASK) {
      case TYP_EXIT:
	strcpy(work, "E/");
	break;
      case TYP_ROOM:
	strcpy(work, "R/");
	break;
      case TYP_PLAYER:
	strcpy(work, "P/");
	break;
      case TYP_THING:
	strcpy(work, "T/");
	break;
      default:
	strcpy(work, "U/");
      }
      if (flags & GOD)
	strcat(work, "G");
      if (flags & WIZARD)
	strcat(work, "W");
      if (flags & ROBOT)
	strcat(work, "R");
      if (flags & LINK_OK)
	strcat(work, "L");
      if (flags & JUMP_OK)
	strcat(work, "J");
      if (flags & ABODE)
	strcat(work, "A");
      if (flags & HAVEN)
	strcat(work, "H");
      if (flags & DARK)
	strcat(work, "D");

      printf("Flags: %s(%d)  Owner: %s\n", work, flags,
	     ownername);
      if (ch)
	*q = ch;
    }
  }
}

/*
 * First pass of recycling. This does one object.
 */

recycle_obj(obj, nuke_list)
  int             obj;
  struct nuked  **nuke_list;	/* So we can add things to it. */

{
  int             loc, flags, next, list;
  struct nuked   *tmp;

  if (obj == 0) {
    printf("Cannot recycle object Zero.\n");
    return;
  }
#if STARTING_LOC != 0
  if (obj == STARTING_LOC) {
    printf("Cannot recycle player start.\n");
    return;
  }
#endif				/* STARTING_LOC != 0 */
  if (get_int_elt(obj, FLAGS, &flags) == -1)
    goto bomb;
  if (get_int_elt(obj, LOC, &loc) == -1)
    goto bomb;

  switch (flags & TYPE_MASK) {

  case TYP_PLAYER:		/* Get the player off the contents list. */
    /* Otherwise it's just like a room. */
    list_drop(obj, loc, 1);
  case TYP_ROOM:

    /* Destroy all the exits in room/carried by player */

    if (get_int_elt(obj, EXITS, &list) == -1)
      goto bomb;
    while (list != -1) {
      if (get_int_elt(list, NEXT, &next) == -1)
	goto bomb;

      tmp = (struct nuked *) ty_malloc(sizeof(struct nuked),
				       "recycle_obj");
      tmp->next = *nuke_list;
      *nuke_list = tmp;
      tmp->obj = list;

      destroy_obj(list);
      list = next;
    }

    /* Try to send room contents/player inventory home. */

    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto bomb;
    while (list != -1) {
      if (get_int_elt(list, NEXT, &next) == -1)
	goto bomb;
      send_home(list, obj);
      list = next;
    }

    /* Now nuke everything left -- i.e. stuff homed here */

    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto bomb;
    while (list != -1) {
      if (get_int_elt(list, NEXT, &next) == -1)
	goto bomb;

      tmp = (struct nuked *) ty_malloc(sizeof(struct nuked),
				       "recycle_obj");
      tmp->next = *nuke_list;
      *nuke_list = tmp;
      tmp->obj = list;

      destroy_obj(list);
      list = next;
    }

    /* nuke the room/player itself. */

    destroy_obj(obj);
    break;
  case TYP_EXIT:
    list_drop(obj, loc, 0);
    destroy_obj(obj);
    break;
  case TYP_THING:
    list_drop(obj, loc, 1);
    destroy_obj(obj);
    break;
  default:
    printf("Eeek! Unknown object type!\n");
    return;
  }
  return;
bomb:
  printf("Something bad happened. Good luck.\n");
  return;
}


int             fix_handle()
{
  int             i, list, loc, flags;
  int             total = 0;

  printf("Scanning the database...\n");

  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;

    /* loop through the exits list first.. */
    if (get_int_elt(i, EXITS, &list) == -1)
      goto bomb;
    while (list != -1) {
      if (get_int_elt(list, LOC, &loc) == -1)
	goto bomb;
      if (loc != i) {
	if (set_int_elt(list, LOC, i) == -1)
	  goto bomb;
	total++;
      }
      if (get_int_elt(list, NEXT, &list) == -1)
	goto bomb;
    }

    /* now do the contents list. this is slightly more complex.. */
    if (get_int_elt(i, CONTENTS, &list) == -1)
      goto bomb;
    while (list != -1) {
      int             next;

      if (get_int_elt(list, NEXT, &next) == -1)
	goto bomb;
      if (get_int_elt(list, FLAGS, &flags) == -1)
	goto bomb;
      if ((flags & TYPE_MASK) == TYP_EXIT) {
	if (get_int_elt(list, LOC, &loc) == -1)
	  goto bomb;
	if (loc != i) {
	  if (set_int_elt(list, LOC, i) == -1)
	    goto bomb;
	}
	total++;
	list_drop(list, i, 1);
	list_add(list, i, 0);
	if (set_int_elt(list, DESTINATION, -1) == -1)
	  goto bomb;
      }
      list = next;
    }

    /* all done with that sucker... */
  }

  printf("Scan done. %d exits fixed.\n", total);
  return (0);

bomb:

  printf("Database corrupt. Scan aborted.\n");
  return (-1);
}

/*
 * Utility funtions.
 * 
 */


/* Sends an object home */

send_home(obj, loc)
  int             obj;
  int             loc;
{
  int             home;

  if (get_int_elt(obj, HOME, &home) == -1) {
    printf("Object #%d has a bad home reference.\n", obj);
    return;
  }
  list_drop(obj, loc, CONTENTS_LIST);	/* Drop it from contents list here */

  if (!exists_object(home)) {
    home = STARTING_LOC;	/* Fake it, eh? */
  }
  if (set_int_elt(obj, LOC, home) == -1) {
    printf("Could not set location for object #%d.\n", obj);
    return;
  }
  list_add(obj, home, CONTENTS_LIST);
}