/* 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));
}
}