Implement NOEVAL object flag and attribute flag (#11).

Add NOEVAL object flag (FLAG_WORD3) and AF_NOEVAL attribute flag so that
attribute contents can be stored as literal data without evaluation.
When either flag is set, u(), ulocal(), get_eval(), @trigger, did_it()
messages/actions, @function, modSpeech, check_filter, make_prefix,
process_hook, sortby comparison, eval_boolexp, and format attributes
(EXITFORMAT/CONFORMAT/NAMEFORMAT/DESCFORMAT) all return raw text with
no function calls, %-substitutions, or escape processing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Stephen Dennis 2026-03-04 18:04:14 -07:00
parent 920b0b9417
commit 4cb904fcc2
18 changed files with 823 additions and 519 deletions

View file

@ -4921,6 +4921,13 @@ ATTRIBUTE FLAGS (continued)
& ATTRIBUTE FLAGS3
ATTRIBUTE FLAGS (continued)
no_eval (E) - The attribute contents are not evaluated when
retrieved via u(), ulocal(), get_eval(), @trigger,
or other evaluation callsites. The raw text is
returned with no function calls, no %-substitutions,
and no escape processing. Useful for storing
player-submitted text safely.
visual (V) - The attribute is visible to anyone who examines
you. Note that the predefined attributes DESC,
SEX, and LAST are always VISUAL
@ -7272,7 +7279,8 @@ FLAG LIST
t - TRANSPARENT| u - SUSPECT | v - VERBOSE | w - STAFF
x - SLAVE | $ - SITEMON | z - OPEN_OK | ? - HEAD
- - NOBLEED | | - VACATION | ~ - ASCII | ( - HTML
| COLOR256 | TALKMODE | UNICODE
| COLOR256 | NOEVAL | TALKMODE
| UNICODE | |
------------------------------------------------------------------------
(*) Note that these 'flags' are really types. Also notice that THING
@ -10786,6 +10794,31 @@ NOBLEED
Related Topics:
& NOEVAL
NOEVAL
FLAG: NOEVAL ()
When set on an object, all attributes on that object are treated as
literal data: u(), ulocal(), get_eval(), @trigger, did_it() messages,
and other evaluation callsites return the raw attribute text without
performing function calls, %-substitutions, or escape processing.
This is useful for objects that store player-submitted text (such as
job trackers, bulletin boards, or mail systems) where evaluating the
content would be a security risk.
The same effect can be applied to individual attributes using the
no_eval attribute flag (see 'help attribute flags3').
Example:
@set myobj=NOEVAL
&DATA myobj=[delete(me)]
say u(myobj/DATA)
You say "[delete(me)]"
Related Topics: ATTRIBUTE FLAGS, hasflag().
& NOSPOOF
NOSPOOF

View file

@ -27,6 +27,7 @@ constexpr int AF_NOCLONE = 0x00010000; // Don't copy this attr when cloning.
constexpr int AF_CONST = 0x00020000; // No one can change it (set by server).
constexpr int AF_CASE = 0x00040000; // Regexp matches are case-sensitive.
constexpr int AF_TRACE = 0x00080000; // Trace evaluation of this attribute.
constexpr int AF_NOEVAL = 0x00100000; // Don't evaluate attribute contents.
constexpr int AF_NONAME = 0x00400000; // Supress name in oattr cases.
constexpr int AF_NODECOMP = 0x00800000; // Do not include in @decomp.
constexpr int AF_ISUSED = 0x10000000; // Used to make efficient sweeps of stale

View file

@ -187,20 +187,27 @@ bool eval_boolexp(dbref player, dbref thing, dbref from, BOOLEXP *b)
if (bCheck)
{
reg_ref** preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
if ((aflags & AF_NOEVAL) || NoEval(source))
{
bCheck = !string_compare(buff, reinterpret_cast<UTF8*>(b->sub1));
}
else
{
reg_ref** preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
buff2 = bp = alloc_lbuf("eval_boolexp");
mux_exec(buff, LBUF_SIZE-1, buff2, &bp, source, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_FCHECK|EV_TOP),
nullptr, 0);
*bp = '\0';
buff2 = bp = alloc_lbuf("eval_boolexp");
mux_exec(buff, LBUF_SIZE-1, buff2, &bp, source, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_FCHECK|EV_TOP),
nullptr, 0);
*bp = '\0';
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
bCheck = !string_compare(buff2, reinterpret_cast<UTF8*>(b->sub1));
free_lbuf(buff2);
bCheck = !string_compare(buff2, reinterpret_cast<UTF8*>(b->sub1));
free_lbuf(buff2);
}
}
free_lbuf(buff);
return bCheck;

View file

@ -1193,24 +1193,31 @@ static bool process_hook(dbref executor, CMDENT *cmdp, int key, bool save_flg)
hk_attr->number, &aowner, &aflags);
if (atext[0] && !(aflags & AF_NOPROG))
{
reg_ref **preserve = nullptr;
if (save_flg)
if ((aflags & AF_NOEVAL) || NoEval(mudconf.hook_obj))
{
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
// NOEVAL hook content is data, not code -- treat as true.
}
UTF8 *buff, *bufc;
bufc = buff = alloc_lbuf("process_hook");
mux_exec(atext, LBUF_SIZE-1, buff, &bufc, mudconf.hook_obj, executor,
executor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), nullptr, 0);
*bufc = '\0';
if (save_flg)
else
{
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
reg_ref **preserve = nullptr;
if (save_flg)
{
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
}
UTF8 *buff, *bufc;
bufc = buff = alloc_lbuf("process_hook");
mux_exec(atext, LBUF_SIZE-1, buff, &bufc, mudconf.hook_obj, executor,
executor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), nullptr, 0);
*bufc = '\0';
if (save_flg)
{
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
}
retval = xlate(buff);
free_lbuf(buff);
}
retval = xlate(buff);
free_lbuf(buff);
}
free_lbuf(atext);
}
@ -3066,6 +3073,7 @@ NAMETAB indiv_attraccess_nametab[] =
{T("html"), 2, CA_PUBLIC, AF_HTML},
{T("no_command"), 4, CA_PUBLIC, AF_NOPROG},
{T("no_inherit"), 4, CA_PUBLIC, AF_PRIVATE},
{T("no_eval"), 4, CA_PUBLIC, AF_NOEVAL},
{T("no_name"), 4, CA_PUBLIC, AF_NONAME},
{T("no_parse"), 4, CA_PUBLIC, AF_NOPARSE},
{T("regexp"), 1, CA_PUBLIC, AF_REGEXP},

View file

@ -1566,6 +1566,13 @@ void mux_exec( const UTF8 *pStr, size_t nStr, UTF8 *buff, UTF8 **bufc, dbref exe
i = executor;
}
if ((aflags & AF_NOEVAL) || NoEval(ufp->obj))
{
size_t nLen = strlen((const char *)tbuf);
safe_copy_buf(tbuf, nLen, buff, &oldp);
}
else
{
reg_ref **preserve = nullptr;
if (ufp->flags & FN_PRES)
@ -1583,6 +1590,7 @@ void mux_exec( const UTF8 *pStr, size_t nStr, UTF8 *buff, UTF8 **bufc, dbref exe
PopRegisters(preserve, MAX_GLOBAL_REGS);
preserve = nullptr;
}
}
free_lbuf(tbuf);
}
else

View file

@ -389,7 +389,7 @@ extern CLogFile Log;
/* From look.cpp */
void look_in(dbref,dbref, int);
void show_vrml_url(dbref, dbref);
#define NUM_ATTRIBUTE_CODES 12
#define NUM_ATTRIBUTE_CODES 13
size_t decode_attr_flags(int aflags, UTF8 buff[NUM_ATTRIBUTE_CODES+1]);
void decode_attr_flag_names(int aflags, UTF8 *buf, UTF8 **bufc);

View file

@ -399,6 +399,7 @@ static FLAGBITENT fbeAlone = { ALONE, ' ', FLAG_WORD3, 0,
static FLAGBITENT fbeNoExamine = { NOEXAMINE, 'E', FLAG_WORD3, 0, fh_wizroy};
static FLAGBITENT fbeNoModify = { NOMODIFY, ' ', FLAG_WORD3, 0, fh_wizroy};
static FLAGBITENT fbeIndestructible = { INDESTRUCTIBLE, ' ', FLAG_WORD3, 0, fh_wizroy};
static FLAGBITENT fbeNoEval = { NOEVAL, ' ', FLAG_WORD3, 0, fh_any};
static FLAGBITENT fbeSitemon = { SITEMON, '$', FLAG_WORD3, 0, fh_wiz};
#ifdef WOD_REALMS
static FLAGBITENT fbeFae = { FAE, '0', FLAG_WORD3, CA_STAFF, fh_wizroy};
@ -487,6 +488,7 @@ FLAGNAMEENT gen_flag_names[] =
{T("NO_COMMAND"), true, &fbeNoCommand },
{T("NO_EXAMINE"), true, &fbeNoExamine },
{T("NOBLEED"), true, &fbeNoBleed },
{T("NOEVAL"), true, &fbeNoEval },
{T("NOEXAMINE"), true, &fbeNoExamine },
{T("NOMODIFY"), true, &fbeNoModify },
{T("NO_MODIFY"), true, &fbeNoModify },

View file

@ -109,6 +109,7 @@ constexpr unsigned int ALONE = 0x00002000; // Suppress inter-player
constexpr unsigned int NOEXAMINE = 0x00004000; // Blocks examine and @decompile.
constexpr unsigned int NOMODIFY = 0x00008000; // Blocks all modifications.
constexpr unsigned int INDESTRUCTIBLE = 0x00010000; // Cannot be destroyed.
constexpr unsigned int NOEVAL = 0x00020000; // Attribute contents not evaluated.
constexpr unsigned int MARK_0 = 0x00400000; // User-defined flags.
constexpr unsigned int MARK_1 = 0x00800000;
constexpr unsigned int MARK_2 = 0x01000000;
@ -345,6 +346,7 @@ UTF8 *MakeCanonicalFlagName
#define NoExamine(x) ((Flags3(x) & NOEXAMINE) != 0)
#define NoModify(x) ((Flags3(x) & NOMODIFY) != 0)
#define Indestructible(x) ((Flags3(x) & INDESTRUCTIBLE) != 0)
#define NoEval(x) ((Flags3(x) & NOEVAL) != 0)
#define CmdCheck(x) ((Flags3(x) & CMDCHECK) != 0)
#if defined(WOD_REALMS) || defined(REALITY_LVLS)
#define isObfuscate(x) ((Flags3(x) & OBF) != 0)

View file

@ -314,6 +314,11 @@ static int u_comp(ucomp_context *pctx, const void *s1, const void *s2)
return 0;
}
if ((pctx->aflags & AF_NOEVAL) || NoEval(pctx->executor))
{
return 0;
}
const UTF8 *elems[2] = { T(s1), T(s2) };
UTF8 *tbuf = alloc_lbuf("u_comp");

View file

@ -2066,8 +2066,18 @@ static void get_handler(UTF8 *buff, UTF8 **bufc, dbref executor, UTF8 *fargs[],
if ( key == GET_EVAL
|| key == GET_GEVAL)
{
mux_exec(atr_gotten, nLen, buff, bufc, thing, executor, executor,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL), nullptr, 0);
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
if (nLen)
{
safe_copy_buf(atr_gotten, nLen, buff, bufc);
}
}
else
{
mux_exec(atr_gotten, nLen, buff, bufc, thing, executor, executor,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL), nullptr, 0);
}
}
else
{
@ -2186,9 +2196,17 @@ static void do_ufun(UTF8 *buff, UTF8 **bufc, dbref executor, dbref caller,
// Evaluate it using the rest of the passed function args.
//
mux_exec(atext, LBUF_SIZE-1, buff, bufc, thing, executor, enactor,
AttrTrace(aflags, EV_FCHECK|EV_EVAL),
(const UTF8 **)&(fargs[1]), nfargs - 1);
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
size_t nLen = strlen((const char *)atext);
safe_copy_buf(atext, nLen, buff, bufc);
}
else
{
mux_exec(atext, LBUF_SIZE-1, buff, bufc, thing, executor, enactor,
AttrTrace(aflags, EV_FCHECK|EV_EVAL),
(const UTF8 **)&(fargs[1]), nfargs - 1);
}
free_lbuf(atext);
// If we're evaluating locally, restore the preserved registers.
@ -4965,6 +4983,7 @@ static ATR_HAS_FLAG_ENTRY atr_has_flag_table[] =
{ T("html"), AF_HTML },
{ T("locked"), AF_LOCK },
{ T("no_command"), AF_NOPROG },
{ T("no_eval"), AF_NOEVAL },
{ T("no_name"), AF_NONAME },
{ T("no_parse"), AF_NOPARSE },
{ T("regexp"), AF_REGEXP },

View file

@ -454,9 +454,17 @@ static bool check_filter(dbref object, dbref player, int filter, const UTF8 *msg
UTF8 *nbuf = alloc_lbuf("check_filter");
UTF8 *dp = nbuf;
mux_exec(buf, LBUF_SIZE-1, nbuf, &dp, object, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP),
nullptr, 0);
if ((aflags & AF_NOEVAL) || NoEval(object))
{
mux_strncpy(nbuf, buf, LBUF_SIZE-1);
dp = nbuf + strlen((const char *)nbuf);
}
else
{
mux_exec(buf, LBUF_SIZE-1, nbuf, &dp, object, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP),
nullptr, 0);
}
*dp = '\0';
strip_fancy_quotes(nbuf);
dp = nbuf;
@ -550,20 +558,27 @@ static UTF8 *make_prefix(dbref object, dbref player, int prefix, const UTF8 *dfl
}
else
{
reg_ref **preserve = nullptr;
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
if ((aflags & AF_NOEVAL) || NoEval(object))
{
cp = buf + strlen((const char *)buf);
}
else
{
reg_ref **preserve = nullptr;
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
nbuf = cp = alloc_lbuf("add_prefix");
mux_exec(buf, LBUF_SIZE-1, nbuf, &cp, object, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP),
nullptr, 0);
free_lbuf(buf);
nbuf = cp = alloc_lbuf("add_prefix");
mux_exec(buf, LBUF_SIZE-1, nbuf, &cp, object, player, player,
AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP),
nullptr, 0);
free_lbuf(buf);
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
restore_global_regs(preserve);
PopRegisters(preserve, MAX_GLOBAL_REGS);
buf = nbuf;
buf = nbuf;
}
}
if (cp != buf)
{

View file

@ -470,9 +470,17 @@ static void look_exits(dbref player, dbref loc, const UTF8 *exit_name)
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_and_clear_global_regs(preserve);
mux_exec(ExitFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
(const UTF8 **)&VisibleObjectList, 1);
if ((aflags & AF_NOEVAL) || NoEval(loc))
{
mux_strncpy(FormatOutput, ExitFormat, LBUF_SIZE-1);
tPtr = FormatOutput + strlen((const char *)FormatOutput);
}
else
{
mux_exec(ExitFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
(const UTF8 **)&VisibleObjectList, 1);
}
*tPtr = '\0';
restore_global_regs(preserve);
@ -647,9 +655,17 @@ static void look_contents(dbref player, dbref loc, const UTF8 *contents_name, in
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_and_clear_global_regs(preserve);
mux_exec(ContentsFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
ParameterList, 2);
if ((aflags & AF_NOEVAL) || NoEval(loc))
{
mux_strncpy(FormatOutput, ContentsFormat, LBUF_SIZE-1);
tPtr = FormatOutput + strlen((const char *)FormatOutput);
}
else
{
mux_exec(ContentsFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
ParameterList, 2);
}
*tPtr = '\0';
restore_global_regs(preserve);
@ -755,6 +771,7 @@ static ATTR_DECODE_ENTRY attr_decode_table[NUM_ATTRIBUTE_CODES+1] =
{ AF_CASE, 'C', T("CASE") },
{ AF_HTML, 'H', T("HTML") },
{ AF_PRIVATE, 'I', T("NO_INHERIT") },
{ AF_NOEVAL, 'E', T("NO_EVAL") },
{ AF_NONAME, 'N', T("NO_NAME") },
{ AF_NOPARSE, 'P', T("NO_PARSE") },
{ AF_REGEXP, 'R', T("REGEXP") },
@ -1054,9 +1071,16 @@ static bool show_a_desc(dbref player, dbref loc)
//
mux_strncpy(temp, tbuf1, LBUF_SIZE-1);
#else
mux_exec(tbuf1, LBUF_SIZE-1, temp, &bp, loc, player, player,
AttrTrace(aflags2, EV_FCHECK|EV_EVAL|EV_TOP),
nullptr, 0);
if ((aflags2 & AF_NOEVAL) || NoEval(loc))
{
mux_strncpy(temp, tbuf1, LBUF_SIZE-1);
}
else
{
mux_exec(tbuf1, LBUF_SIZE-1, temp, &bp, loc, player, player,
AttrTrace(aflags2, EV_FCHECK|EV_EVAL|EV_TOP),
nullptr, 0);
}
*bp = '\0';
#endif
@ -1068,9 +1092,17 @@ static bool show_a_desc(dbref player, dbref loc)
const UTF8 *ParameterList[] =
{ temp, attrname };
mux_exec(DescFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags1, EV_FCHECK|EV_EVAL|EV_TOP),
ParameterList, 2);
if ((aflags1 & AF_NOEVAL) || NoEval(loc))
{
mux_strncpy(FormatOutput, DescFormat, LBUF_SIZE-1);
tPtr = FormatOutput + strlen((const char *)FormatOutput);
}
else
{
mux_exec(DescFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags1, EV_FCHECK|EV_EVAL|EV_TOP),
ParameterList, 2);
}
*tPtr = '\0';
notify(player, FormatOutput);
@ -1205,10 +1237,18 @@ static void look_simple(dbref player, dbref thing, bool obey_terse)
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_and_clear_global_regs(preserve);
mux_exec(NameFormat, LBUF_SIZE-1, FormatOutput, &tPtr, thing,
player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
0, 0);
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
mux_strncpy(FormatOutput, NameFormat, LBUF_SIZE-1);
tPtr = FormatOutput + strlen((const char *)FormatOutput);
}
else
{
mux_exec(NameFormat, LBUF_SIZE-1, FormatOutput, &tPtr, thing,
player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
0, 0);
}
*tPtr = '\0';
restore_global_regs(preserve);
@ -1327,9 +1367,17 @@ void look_in(dbref player, dbref loc, int key)
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_and_clear_global_regs(preserve);
mux_exec(NameFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
0, 0);
if ((aflags & AF_NOEVAL) || NoEval(loc))
{
mux_strncpy(FormatOutput, NameFormat, LBUF_SIZE-1);
tPtr = FormatOutput + strlen((const char *)FormatOutput);
}
else
{
mux_exec(NameFormat, LBUF_SIZE-1, FormatOutput, &tPtr, loc, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP),
0, 0);
}
*tPtr = '\0';
restore_global_regs(preserve);

View file

@ -2568,27 +2568,36 @@ void did_it(dbref player, dbref thing, int what, const UTF8 *def, int owhat,
d = atr_pget(thing, what, &aowner, &aflags);
if (*d)
{
need_pres = true;
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
buff = bp = alloc_lbuf("did_it.1");
mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, player, player,
AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_FCHECK|EV_TOP),
args, nargs);
*bp = '\0';
if ( (aflags & AF_HTML)
&& Html(player))
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
safe_str(T("\r\n"), buff, &bp);
*bp = '\0';
notify_html(player, buff);
// Output raw text with no substitutions.
//
notify(player, d);
}
else
{
notify(player, buff);
need_pres = true;
preserve = PushRegisters(MAX_GLOBAL_REGS);
save_global_regs(preserve);
buff = bp = alloc_lbuf("did_it.1");
mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, player, player,
AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_FCHECK|EV_TOP),
args, nargs);
*bp = '\0';
if ( (aflags & AF_HTML)
&& Html(player))
{
safe_str(T("\r\n"), buff, &bp);
*bp = '\0';
notify_html(player, buff);
}
else
{
notify(player, buff);
}
free_lbuf(buff);
}
free_lbuf(buff);
}
else if (def)
{
@ -2610,6 +2619,34 @@ void did_it(dbref player, dbref thing, int what, const UTF8 *def, int owhat,
d = atr_pget(thing, owhat, &aowner, &aflags);
if (*d)
{
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
// Output raw text with no substitutions.
//
#ifdef REALITY_LVLS
if (aflags & AF_NONAME)
{
notify_except2_rlevel(loc, player, player, thing, d);
}
else
{
notify_except2_rlevel(loc, player, player, thing,
tprintf(T("%s %s"), Moniker(player), d));
}
#else
if (aflags & AF_NONAME)
{
notify_except2(loc, player, player, thing, d);
}
else
{
notify_except2(loc, player, player, thing,
tprintf(T("%s %s"), Moniker(player), d));
}
#endif // REALITY_LVLS
}
else
{
if (!need_pres)
{
need_pres = true;
@ -2646,6 +2683,7 @@ void did_it(dbref player, dbref thing, int what, const UTF8 *def, int owhat,
#endif // REALITY_LVLS
}
free_lbuf(buff);
} // else (not NOEVAL)
}
else if (odef)
{
@ -2744,12 +2782,15 @@ void did_it(dbref player, dbref thing, int what, const UTF8 *def, int owhat,
}
}
free_lbuf(charges);
CLinearTimeAbsolute lta;
wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta,
NOTHING, 0,
act,
nargs, args,
mudstate.global_regs);
if (!((aflags & AF_NOEVAL) || NoEval(thing)))
{
CLinearTimeAbsolute lta;
wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta,
NOTHING, 0,
act,
nargs, args,
mudstate.global_regs);
}
}
free_lbuf(act);
}

View file

@ -2179,9 +2179,16 @@ void do_trigger(dbref executor, dbref caller, dbref enactor, int eval, int key,
free_lbuf(charges);
if (bRun)
{
process_command(thing, executor, executor,
AttrTrace(aflags, 0), false, act,
(const UTF8 **)argv, nargs);
if ((aflags & AF_NOEVAL) || NoEval(thing))
{
// NOEVAL content is data, not code -- skip execution.
}
else
{
process_command(thing, executor, executor,
AttrTrace(aflags, 0), false, act,
(const UTF8 **)argv, nargs);
}
}
}
free_lbuf(act);

View file

@ -24,11 +24,19 @@ UTF8 *modSpeech(dbref player, const UTF8 *message, bool bWhich, const UTF8 *comm
UTF8 *new_message = alloc_lbuf("modspeech");
UTF8 *t_ptr = new_message;
const UTF8 *args[2];
args[0] = message;
args[1] = command;
mux_exec(mod, LBUF_SIZE-1, new_message, &t_ptr, player, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), args, 2);
if ((aflags & AF_NOEVAL) || NoEval(player))
{
mux_strncpy(new_message, mod, LBUF_SIZE-1);
t_ptr = new_message + strlen((const char *)new_message);
}
else
{
const UTF8 *args[2];
args[0] = message;
args[1] = command;
mux_exec(mod, LBUF_SIZE-1, new_message, &t_ptr, player, player, player,
AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), args, 2);
}
*t_ptr = '\0';
free_lbuf(mod);
return new_message;

73
testcases/noeval_fn.mux Normal file
View file

@ -0,0 +1,73 @@
#
# noeval_fn.mux - Test Cases for NOEVAL flag and AF_NOEVAL attribute flag.
#
@create test_noeval_fn
-
@set test_noeval_fn=INHERIT QUIET
-
#
# Beginning of Test Cases
#
&tr.tc000 test_noeval_fn=
@log smoke=Beginning noeval test cases.
-
#
# Test Case #1 - NOEVAL attribute flag and object flag behavior.
#
# Tests:
# - AF_NOEVAL attr + u() returns literal text
# - NOEVAL object flag + u() returns literal text
# - get_eval() respects AF_NOEVAL
# - get() still returns raw (it always does)
# - hasflag() detects both flags
# - Without NOEVAL, u() evaluates normally
#
&tr.tc001 test_noeval_fn=
@pemit me=TC001: Creating test objects.;
@create test_noeval_tgt;
@set test_noeval_tgt=INHERIT QUIET;
&TESTATTR test_noeval_tgt=[add(1,2)];
@set test_noeval_tgt/TESTATTR=no_eval;
@create test_noeval_tgt2;
@set test_noeval_tgt2=INHERIT QUIET NOEVAL;
&TESTATTR test_noeval_tgt2=[add(1,2)];
@create test_noeval_tgt3;
@set test_noeval_tgt3=INHERIT QUIET;
&TESTATTR test_noeval_tgt3=[add(1,2)];
@wait 0=
{
@if strmatch(
setr(0,sha1(
[u(test_noeval_tgt/TESTATTR)]
[u(test_noeval_tgt2/TESTATTR)]
[get_eval(test_noeval_tgt/TESTATTR)]
[get(test_noeval_tgt/TESTATTR)]
[hasflag(test_noeval_tgt/TESTATTR,no_eval)]
[hasflag(test_noeval_tgt2,NOEVAL)]
[u(test_noeval_tgt3/TESTATTR)]
)
),
EDBF1A113545E1AB8AE20F6574BE7157DA8EA52D
)=
{
@log smoke=TC001: noeval flag and attr flag. Succeeded.
},
{
@log smoke=TC001: noeval flag and attr flag. Failed (%q0).
};
@destroy/override test_noeval_tgt;
@destroy/override test_noeval_tgt2;
@destroy/override test_noeval_tgt3;
@trig me/tr.done
}
-
&tr.done test_noeval_fn=
@log smoke=End noeval test cases.;
@notify smoke
-
drop test_noeval_fn
-
#
# End of Test Cases
#

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@
ladd_fn land_fn last_fn lcstr_fn ldelete_fn ljust_fn lmax_fn lmin_fn
ln_fn lnum_fn lock_fn log_fn lor_fn lpad_fn lpos_fn lt_fn lte_fn
match_fn matchall_fn max_fn member_fn merge_fn mid_fn min_fn mod_fn mul_fn
neq_fn not_fn objid_fn oemit_fn or_fn orbool_fn ord_fn
neq_fn noeval_fn not_fn objid_fn oemit_fn or_fn orbool_fn ord_fn
parenmatch_fn pi_fn pickrand_fn pos_fn power_fn
remainder_fn remove_fn repeat_fn replace_fn rest_fn reverse_fn revwords_fn
right_fn rjust_fn roman_fn round_fn rpad_fn