/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* display.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.
 *
 */

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca	__builtin_alloca
#else	/* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else	/* not HAVE_ALLOCA_H */
#ifdef _AIX
 #pragma alloca
#endif	/* not _AIX */
#endif	/* not HAVE_ALLOCA_H */
#endif 	/* not __GNUC__ */

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

#include "conf.h"
#include "teeny.h"
#include "flaglist.h"
#include "attrs.h"
#include "externs.h"

/* routines for formatting object-related data for human viewing. */

char *display_name(player, cause, thing)
    int player, cause, thing;
{
  static char buff[MEDBUFFSIZ];
  char *name, *ptr;
  int flags[FLAGS_LEN], type;
  register FlagList *flist;
  int control, visible;

  /* do a couple of sanity checks. */
  if(thing == -2) {
    strcpy(buff, "*HOME*");
    return(buff);
  } else if(!exists_object(thing)) {
    strcpy(buff, "*NOTHING*");
    return(buff);
  }

  if((get_str_elt(thing, NAME, &name) == -1)
     || (get_flags_elt(thing, FLAGS, flags) == -1)) {
    logfile(LOG_ERROR,
	    "display_name: couldn't get name or flags of object #%d\n", thing);
    strcpy(buff, "*BAD NAME*");
    return(buff);
  }

  for(ptr = buff; name && *name
      && ((ptr - buff) < (MEDBUFFSIZ-64)); *ptr++ = *name++);
  *ptr = '\0';

  type = (flags[0] & TYPE_MASK);
  control = controls(player, cause, thing);
  visible = 0;

  if(!control) {
    for (flist = GenFlags; flist->name; flist++) {
      if ((flags[flist->word] & flist->code)
	  && (flist->perm & PERM_VISIBLE))
        visible++;
    }
    switch (type) {
    case TYP_ROOM:
      for(flist = RoomFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_PLAYER:
      for(flist = PlayerFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_EXIT:
      for(flist = ExitFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_THING:
      for(flist = ThingFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    }
  }

  if(control || visible) {
    sprintf(ptr, "(#%d%s%s)", thing,
    	    (type == TYP_PLAYER) ? "P" : (type == TYP_ROOM) ? "R" :
	    (type == TYP_EXIT) ? "E" : "", display_objflags(flags, control));
  }

  return(buff);
}

static int sort_flags(ptr1, ptr2)
    register const void *ptr1, *ptr2;
{
  register const char *chr1, *chr2;

  chr1 = (const char *)ptr1;
  chr2 = (const char *)ptr2;

  return(*chr1 - *chr2);
}

char *display_objflags(flags, showall)
    int *flags, showall;
{
  static char buff[FLAGS_MAX+1];
  register char *ptr = buff;
  register FlagList *flist;

  for (flist = GenFlags; flist->name; flist++) {
    if (flags[flist->word] & flist->code) {
      if(showall || (flist->perm & PERM_VISIBLE))
        *ptr++ = flist->chr;
    }
  }
  switch(flags[0] & TYPE_MASK) {
  case TYP_ROOM:
    for(flist = RoomFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_PLAYER:
    for(flist = PlayerFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_EXIT:
    for(flist = ExitFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_THING:
    for(flist = ThingFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  }
  *ptr = '\0';

  /* make it look pretty */
  qsort(buff, (ptr - buff), sizeof(char), sort_flags);

  return(buff);
}

char *display_attrflags(aflags)
    int aflags;
{
  static char buff[A_FLAGS_MAX+1];
  register char *ptr;
  AFlagList *Aflags;

  for (ptr = buff, Aflags = AFlags; Aflags->name; Aflags++) {
    if (aflags & Aflags->code) 
      *ptr++ = Aflags->chr;
  }
  *ptr = '\0';
  return (buff);
}

/*
 * Format, sort, and display the long list of object flags.
 *
 * XXX: Too much of this is hard coded.
 */

struct fl_sortbuf {
  char *name;	/* Long flag name */
  char chr;	/* Short flag name. */
};

static int sort_withbuf(ptr1, ptr2)
    register const void *ptr1, *ptr2;
{
  register const struct fl_sortbuf *s1, *s2;

  s1 = (const struct fl_sortbuf *)ptr1;
  s2 = (const struct fl_sortbuf *)ptr2;

  return(s1->chr - s2->chr);
}

void display_flags(player, cause, obj)
    int player, cause, obj;
{
  char buffer[MEDBUFFSIZ];
  struct fl_sortbuf bufptr[FLAGS_MAX];
  int flags[FLAGS_LEN], pindex = 0, bindex;
  register FlagList *flist;

  if (get_flags_elt(obj, FLAGS, flags) == -1) {
    notify_player(player, cause, player, "<Spammed flags>", 0);
  } else {
    strcpy(buffer, "Type: ");
    switch (flags[0] & TYPE_MASK) {
    case TYP_ROOM:
      strcat(buffer, "Room");
      break;
    case TYP_EXIT:
      strcat(buffer, "Exit");
      break;
    case TYP_PLAYER:
      strcat(buffer, "Player");
      break;
    case TYP_THING:
      strcat(buffer, "Thing");
      break;
    default:
      strcat(buffer, "*UNKNOWN TYPE*");
    }

    /*
     * We now assign pointers, so that we can sort them ala the short
     * flags display.
     */
    for (flist = GenFlags; flist->name; flist++) {
      if (flags[flist->word] & flist->code) {
	bufptr[pindex].chr = flist->chr;
	bufptr[pindex++].name = flist->name;
      }
    }
    switch(Typeof(obj)) {
    case TYP_ROOM:
      for(flist = RoomFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_PLAYER:
      for(flist = PlayerFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_THING:
      for(flist = ThingFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_EXIT:
      for(flist = ExitFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    }

    if(pindex > 0) {		/* Found some flags... */
      strcat(buffer, "  Flags: ");

      /* Sort bufptr. */
      qsort(bufptr, (pindex - 1), sizeof(struct fl_sortbuf), sort_withbuf);

      /* ..And now finish building the message. */
      for(bindex = 0; bindex < pindex; bindex++) {
        /* Space check. */
        if((strlen(buffer) + strlen(bufptr[bindex].name)) >= sizeof(buffer) - 3)
          break;

        strcat(buffer, bufptr[bindex].name);
        strcat(buffer, " ");
      }

      if (buffer[strlen(buffer) - 1] == ' ')
        buffer[strlen(buffer) - 1] = '\0';
    }
    
    /* Tell them about it. */
    notify_player(player, cause, player, buffer, 0);
  }
}

/*
 * Displays and possibly sorts attributes.
 */

static int sort_attr(ptr1, ptr2)
    register const void *ptr1, *ptr2;
{
  register const struct attr **s1, **s2;

  s1 = (const struct attr **)ptr1;
  s2 = (const struct attr **)ptr2;

  return(strcasecmp((*s1)->name, (*s2)->name));
}

static void display_attribute(player, cause, atptr, buf, bufsiz)
    int player, cause;
    struct attr *atptr;
    register char *buf;
    register int bufsiz;
{
  if (atptr->flags != (DEFATTR_FLGS)) {
    snprintf(buf, bufsiz, "%s(%s): ", atptr->name,
	     display_attrflags(atptr->flags));
    bufsiz -= strlen(buf);

    switch(atptr->type) {
    case ATTR_STRING:
      strncat(buf, (atptr->dat).str, bufsiz);
      break;
    case ATTR_LOCK:
      strncat(buf, unparse_boolexp(player, cause, (atptr->dat).lock), bufsiz);
      break;
    }
  } else {
    strcpy(buf, atptr->name);
    bufsiz -= strlen(buf);

    strncat(buf, ": ", bufsiz);
    bufsiz -= 2;

    switch(atptr->type) {
    case ATTR_STRING:
      strncat(buf, (atptr->dat).str, bufsiz);
      break;
    case ATTR_LOCK:
      strncat(buf, unparse_boolexp(player, cause, (atptr->dat).lock), bufsiz);
      break;
    }
  }
  notify_player(player, cause, player, buf, 0);
}

#if defined(__STDC__)
void display_attributes(int player, int cause, int obj, char *match, bool sort)
#else
void display_attributes(player, cause, obj, match, sort)
    int player, cause, obj;
    char *match;
    bool sort;
#endif
{
  struct attr *atptr, **atarray;
  struct asearch srch;
  char buf[MEDBUFFSIZ*2];
  int atsize, atindex, dindex;

  atindex = 0;
  if (sort) {
    atsize = attr_total(obj);
    if(atsize == -1) {
      logfile(LOG_ERROR,
	      "display_attributes: couldn't get attr total of #%d\n", obj);
      return;
    }
    if(atsize == 0)
      return;

    atarray = (struct attr **)alloca(sizeof(struct attr) * atsize);
    if(atarray == (struct attr **)NULL) {
      panic("display_attributes: stack allocation failed (%d bytes)\n",
	    atsize);
    }
  } else
    atarray = (struct attr **)NULL;

  for (atptr = attr_first(obj, &srch); atptr != (struct attr *)NULL;
       atptr = attr_next(obj, &srch)) {
    if (!can_see_attr(player, cause, obj, atptr->flags))
      continue;
    if ((match != (char *)NULL) && (match[0] != '\0')
        && !quick_wild_prefix(match, atptr->name))
      continue;

    if (!sort)		/* Just display. */
      display_attribute(player, cause, atptr, buf, sizeof(buf));
    else {		/* Put in the array. */
      atarray[atindex++] = atptr;
    }
  }

  if (sort && atindex) {
    /* Sort the array and display. */
    qsort(atarray, (atindex - 1), sizeof(struct attr *), sort_attr);

    for(dindex = 0; dindex < atindex; dindex++)
      display_attribute(player, cause, atarray[dindex], buf, sizeof(buf));
  }
}

#if defined(__STDC__)
void display_attributes_parent(int player, int cause, int obj, char *match,
			       bool sort)
#else
void display_attributes_parent(player, cause, obj, match, sort)
    int player, cause, obj;
    char *match;
    bool sort;
#endif
{
  int parent, depth;
  struct attr *atptr, **atarray;
  struct asearch srch;
  char buf[MEDBUFFSIZ*2];
  int atsize, atindex, dindex;

  atindex = 0;
  if (sort) {
    atsize = attr_total(obj);
    if(atsize == -1) {
      logfile(LOG_ERROR,
	      "display_attributes_parent: couldn't get attr total of #%d\n",
	      obj);
      return;
    }
    if(atsize == 0)
      return;

    atarray = (struct attr **)alloca(sizeof(struct attr) * atsize);
    if(atarray == (struct attr **)NULL) {
      panic("display_attributes_parent: stack allocation failed (%d bytes)\n",
	    atsize);
    }
  } else
    atarray = (struct attr **)NULL;

  depth = 0;
  parent = obj;
  do {
    for (atptr = attr_first(parent, &srch); atptr != (struct attr *)NULL;
         atptr = attr_next(parent, &srch)) {
      if ((atptr->flags & A_PRIVATE) && (parent != obj))
	continue;
      if ((atptr->flags & A_PICKY) && (Typeof(parent) != Typeof(obj)))
        continue;
      if (isPICKY(parent) && (Typeof(parent) != Typeof(obj)))
        continue;
      if (!can_see_attr(player, cause, obj, atptr->flags))
	continue;
      if ((match != (char *)NULL) && (match[0] != '\0')
          && !quick_wild_prefix(match, atptr->name))
	continue;
      if (attr_source(obj, atptr->name) != parent)
	continue;

      if (!sort)	/* Just display. */
        display_attribute(player, cause, atptr, buf, sizeof(buf));
      else {		/* Put in the array. */
        atarray[atindex++] = atptr;
      }
    }

    if (get_int_elt(parent, PARENT, &parent) == -1)
      break;
    depth++;
  } while ((parent != -1) && (depth <= mudconf.parent_depth));

  if (sort && atindex) {
    /* Sort the array and display. */
    qsort(atarray, (atindex - 1), sizeof(struct attr *), sort_attr);

    for(dindex = 0; dindex < atindex; dindex++)
      display_attribute(player, cause, atarray[dindex], buf, sizeof(buf));
  }
}