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