pennmush/game/data/
pennmush/game/log/
pennmush/game/save/
pennmush/game/txt/evt/
pennmush/game/txt/nws/
pennmush/os2/
pennmush/po/
pennmush/win32/msvc.net/
pennmush/win32/msvc6/
/**
 * \file unparse.c
 *
 * \brief Convert lots of things into strings for PennMUSH.
 *
 *
 */

#include "copyrite.h"
#include "config.h"

#include <string.h>
#include "conf.h"
#include "externs.h"
#include "mushdb.h"
#include "dbdefs.h"
#include "flags.h"
#include "lock.h"
#include "attrib.h"
#include "ansi.h"
#include "pueblo.h"
#include "parse.h"
#include "confmagic.h"

/* Hack added by Thorvald for object_header Pueblo */
static int couldunparse;

/** Format an object's name (and dbref and flags).
 * This is a wrapper for real_unparse() that conditionally applies
 * pueblo xch_cmd tags to make the object's name a hyperlink to examine
 * it.
 * \param player the looker.
 * \param loc the object being looked at.
 * \return static formatted object name string.
 */
const char *
unparse_object(dbref player, dbref loc)
{
  static PUEBLOBUFF;
  const char *result;
  result = real_unparse(player, loc, 0, 0, 0);
  if (couldunparse) {
    PUSE;
    tag_wrap("A", tprintf("XCH_CMD=\"examine #%d\"", loc), result);
    PEND;
    return pbuff;
  } else {
    return result;
  }
}

/** Format an object's name, obeying MYOPIC/ownership rules.
 * This is a wrapper for real_unparse() that conditionally applies
 * pueblo xch_cmd tags to make the object's name a hyperlink to examine
 * it.
 * \param player the looker.
 * \param loc the object being looked at.
 * \return static formatted object name string.
 */
const char *
unparse_object_myopic(dbref player, dbref loc)
{
  static PUEBLOBUFF;
  const char *result;
  result = real_unparse(player, loc, 1, 0, 1);
  if (couldunparse) {
    PUSE;
    tag_wrap("A", tprintf("XCH_CMD=\"examine #%d\"", loc), result);
    PEND;
    return pbuff;
  } else {
    return result;
  }
}

/** Format an object's name, obeying MYOPIC/ownership and NAMEFORMAT.
 * \verbatim
 * Like unparse_object, but tell real_unparse to use @NAMEFORMAT if present
 * This should only be used if we're looking at our container, to prevent
 * confusion in matching, since you can't match containers with their
 * names anyway, but only with 'here'.
 * \endverbatim
 * \param player the looker.
 * \param loc the object being looked at.
 * \return static formatted object name string.
 */
const char *
unparse_room(dbref player, dbref loc)
{
  static PUEBLOBUFF;
  const char *result;
  result = real_unparse(player, loc, 1, 1, 1);
  if (couldunparse) {
    PUSE;
    tag_wrap("A", tprintf("XCH_CMD=\"examine #%d\"", loc), result);
    PEND;
    return pbuff;
  } else {
    return result;
  }
}

/** Format an object's name in several ways.
 * This function does the real work of converting a dbref to a
 * name, possibly including the dbref and flags, possibly using
 * a nameformat or nameaccent if present.
 * \param player the looker.
 * \param loc dbref of the object being looked at.
 * \param obey_myopic if 0, always show Name(#xxxFLAGS); if 1, don't
 * do so if player is MYOPIC or doesn't own loc.
 * \param use_nameformat if 1, apply a NAMEFORMAT attribute if available.
 * \param use_nameaccent if 1, apply a NAMEACCENT attribute if available.
 * \return address of a static buffer containing the formatted name.
 */
const char *
real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat,
	     int use_nameaccent)
{
  static char buf[BUFFER_LEN], *bp;
  static char tbuf1[BUFFER_LEN];
  char *p;
  int got_nameformat = 0;

  couldunparse = 0;
  if (!(GoodObject(loc) || (loc == NOTHING) || (loc == AMBIGUOUS) ||
	(loc == HOME)))
    return T("*NOTHING*");
  switch (loc) {
  case NOTHING:
    return T("*NOTHING*");
  case AMBIGUOUS:
    return T("*VARIABLE*");
  case HOME:
    return T("*HOME*");
  default:
    if (use_nameformat && nameformat(player, loc, buf)) {
      strcpy(tbuf1, buf);
      got_nameformat = 1;
    } else {
      /* Not using @nameformat or couldn't get one */
      if (use_nameaccent)
	strcpy(tbuf1, accented_name(loc));
      else
	strcpy(tbuf1, Name(loc));
    }
    if (IsExit(loc) && obey_myopic) {
      if ((p = strchr(tbuf1, ';')))
	*p = '\0';
    }
    if ((Can_Examine(player, loc) || can_link_to(player, loc) ||
	 JumpOk(loc) || ChownOk(loc) || DestOk(loc)) &&
	(!Myopic(player) || !obey_myopic) &&
	!(use_nameformat && got_nameformat)) {
      /* show everything */
      if (SUPPORT_PUEBLO)
	couldunparse = 1;
      bp = buf;
      if (ANSI_NAMES && ShowAnsi(player) && !got_nameformat)
	safe_format(buf, &bp, "%s%s%s(#%d%s)", ANSI_HILITE, tbuf1,
		    ANSI_NORMAL, loc, unparse_flags(loc, player));
      else
	safe_format(buf, &bp, "%s(#%d%s)", tbuf1, loc,
		    unparse_flags(loc, player));
      *bp = '\0';
      return buf;
    } else {
      /* show only the name */
      if (ANSI_NAMES && ShowAnsi(player) && !got_nameformat) {
	bp = buf;
	safe_format(buf, &bp, "%s%s%s", ANSI_HILITE, tbuf1, ANSI_NORMAL);
	*bp = '\0';
	return buf;
      } else
	return tbuf1;
    }
  }
}

/** Build the name of loc as seen by a player inside it, but only
 * if it has a NAMEFORMAT.
 * This function needs to avoid using a static buffer, so pass in 
 * a pointer to an allocated BUFFER_LEN array.
 * \param player the looker.
 * \param loc dbref of location being looked at.
 * \param tbuf1 address to store formatted name of loc.
 * \retval 1 a NAMEFORMAT was found, and tbuf1 contains formatted name.
 * \retval 0 no NAMEFORMAT on loc, tbuf1 is undefined.
 */
int
nameformat(dbref player, dbref loc, char *tbuf1)
{
  ATTR *a;
  char *wsave[10], *rsave[NUMQ];
  char *arg, *bp;
  char const *sp, *save;

  int j;
  a = atr_get(loc, "NAMEFORMAT");
  if (a) {
    arg = (char *) mush_malloc(BUFFER_LEN, "string");
    if (!arg)
      mush_panic("Unable to allocate memory in nameformat");
    save_global_regs("nameformat", rsave);
    for (j = 0; j < 10; j++) {
      wsave[j] = global_eval_context.wenv[j];
      global_eval_context.wenv[j] = NULL;
    }
    for (j = 0; j < NUMQ; j++)
      global_eval_context.renv[j][0] = '\0';
    strcpy(arg, unparse_dbref(loc));
    global_eval_context.wenv[0] = arg;
    sp = save = safe_atr_value(a);
    bp = tbuf1;
    process_expression(tbuf1, &bp, &sp, loc, player, player,
		       PE_DEFAULT, PT_DEFAULT, NULL);
    *bp = '\0';
    free((Malloc_t) save);
    for (j = 0; j < 10; j++) {
      global_eval_context.wenv[j] = wsave[j];
    }
    restore_global_regs("nameformat", rsave);
    mush_free((Malloc_t) arg, "string");
    return 1;
  } else {
    /* No @nameformat attribute */
    return 0;
  }
}

/** Give a string representation of a dbref.
 * \param num value to stringify
 * \return address of static buffer containing stringified value.
 */
char *
unparse_dbref(dbref num)
{
  /* Not BUFFER_LEN, but no dbref will come near this long */
  static char str[SBUF_LEN];
  char *strp;

  strp = str;
  safe_dbref(num, str, &strp);
  *strp = '\0';
  return str;
}

/** Give a string representation of an integer.
 * \param num value to stringify
 * \return address of static buffer containing stringified value.
 */
char *
unparse_integer(int num)
{
  static char str[SBUF_LEN];
  char *strp;

  strp = str;
  safe_integer_sbuf(num, str, &strp);
  *strp = '\0';
  return str;
}

/** Give a string representation of an unsigned integer.
 * \param num value to stringify
 * \return address of static buffer containing stringified value.
 */
char *
unparse_uinteger(unsigned int num)
{
  static char str[16];

  sprintf(str, "%u", num);
  return str;
}


/** Give a string representation of a number.
 * \param num value to stringify
 * \return address of static buffer containing stringified value.
 */
char *
unparse_number(NVAL num)
{
  static char str[100];		/* Should be large enough for even the HUGE floats */
  char *p;
  sprintf(str, "%.*f", FLOAT_PRECISION, num);

  if ((p = strchr(str, '.'))) {
    p += strlen(p);
    while (p[-1] == '0')
      p--;
    if (p[-1] == '.')
      p--;
    *p = '\0';
  }
  return str;
}

/** Return the name of an object, applying NAMEACCENT if set.
 * \param thing dbref of object.
 * \return address of static buffer containing object name, with accents
 * if object has a valid NAMEACCENT attribute.
 */
const char *
accented_name(dbref thing)
{
  ATTR *na;
  static char fbuf[BUFFER_LEN];

  na = atr_get(thing, "NAMEACCENT");
  if (!na)
    return Name(thing);
  else {
    char tbuf[BUFFER_LEN];
    char *bp = fbuf;
    size_t len;

    strcpy(tbuf, atr_value(na));

    len = strlen(Name(thing));

    if (len != strlen(tbuf))
      return Name(thing);

    safe_accent(Name(thing), tbuf, len, fbuf, &bp);
    *bp = '\0';

    return fbuf;
  }
}