mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
43 static scratch-buffer arrays across 21 files (5 in mux/src, 38 in mux/modules/) changed from `static` to `thread_local`. Under the current single-threaded evaluator this is a zero-behavior-change swap — `thread_local` storage has the same lifetime and zero-allocation properties as `static` — but each thread gets its own copy, which makes these functions safe for a future multi-threaded evaluator without any locking. Read-only constant tables (`aRadix64`, `aRadixPenn36`, `aRadixPenn64`, `Empty`) left as `static` because they are immutable shared data. Affected areas: net.cpp — queue_string co_buf, trimmed_site, dump_users NameField signals.cpp — signal_desc stubslave.cpp — Stub_PipePump attrcache.cpp — sqlite_attr_buf boolexp.cpp — parsestore command.cpp — preserve_cmd, SpaceCompressCommand, LowerCaseCommand comsys.cpp — NewTitle, Buffer, temp db.cpp — tbuff, Buffer (x2) flags.cpp — buff funceval.cpp — textbuff functions.cpp — TimeBuffer64, TimeBuffer80, Buffer help.cpp — Line, Buffer mail.cpp — aFolders, Buffer, res, szFittedMailAliasDesc match.cpp — buffer player.cpp — szSalt, buf (x2), buff plusemail.cpp — buf predicates.cpp — Buf (x2), pName session.cpp — szFittedDoing set.cpp — pRestrictedKeyText unparse.cpp — buf, boolexp_buf mail_mod.cpp — result, res, buf All 21 files verified with g++ -std=c++17 -fsyntax-only. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
257 lines
7 KiB
C++
257 lines
7 KiB
C++
/*! \file unparse.cpp
|
|
* \brief Produces human-readable key info from boolexps.
|
|
*
|
|
*/
|
|
|
|
#include "copyright.h"
|
|
#include "autoconf.h"
|
|
#include "config.h"
|
|
#include "externs.h"
|
|
|
|
// Boolexp decompile formats
|
|
//
|
|
#define F_EXAMINE 1 // Normal
|
|
#define F_QUIET 2 // Binary for db dumps
|
|
#define F_DECOMPILE 3 // @decompile output
|
|
#define F_FUNCTION 4 // [lock()] output
|
|
|
|
/*
|
|
* Take a dbref (loc) and generate a string. -1, -3, or (#loc) Note, this
|
|
* will give players object numbers of stuff they don't control, but it's
|
|
* only internal currently, so it's not a problem.
|
|
*/
|
|
|
|
static UTF8 *unparse_object_quiet(dbref player, dbref loc)
|
|
{
|
|
UNUSED_PARAMETER(player);
|
|
|
|
thread_local UTF8 buf[SBUF_SIZE];
|
|
|
|
mux_sprintf(buf, SBUF_SIZE, T("(#%d)"), loc);
|
|
return buf;
|
|
}
|
|
|
|
thread_local UTF8 boolexp_buf[LBUF_SIZE];
|
|
static UTF8 *buftop;
|
|
|
|
static void unparse_boolexp1(dbref player, BOOLEXP *b, UTF8 outer_type, int format)
|
|
{
|
|
if (TRUE_BOOLEXP == b)
|
|
{
|
|
if (format == F_EXAMINE)
|
|
{
|
|
safe_str(T("*UNLOCKED*"), boolexp_buf, &buftop);
|
|
}
|
|
return;
|
|
}
|
|
switch (b->type)
|
|
{
|
|
case BOOLEXP_AND:
|
|
if (outer_type == BOOLEXP_NOT)
|
|
{
|
|
safe_chr('(', boolexp_buf, &buftop);
|
|
}
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
safe_chr(AND_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub2, b->type, format);
|
|
if (outer_type == BOOLEXP_NOT)
|
|
{
|
|
safe_chr(')', boolexp_buf, &buftop);
|
|
}
|
|
break;
|
|
case BOOLEXP_OR:
|
|
if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND)
|
|
{
|
|
safe_chr('(', boolexp_buf, &buftop);
|
|
}
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
safe_chr(OR_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub2, b->type, format);
|
|
if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND)
|
|
{
|
|
safe_chr(')', boolexp_buf, &buftop);
|
|
}
|
|
break;
|
|
case BOOLEXP_NOT:
|
|
safe_chr('!', boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
break;
|
|
case BOOLEXP_INDIR:
|
|
safe_chr(INDIR_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
if (b->thing != A_LOCK)
|
|
{
|
|
// Reverse-lookup lock name from lock_sw[].
|
|
//
|
|
for (NAMETAB *nt = lock_sw; nt->name; nt++)
|
|
{
|
|
if (nt->flag == static_cast<unsigned int>(b->thing))
|
|
{
|
|
safe_chr('/', boolexp_buf, &buftop);
|
|
safe_str(nt->name, boolexp_buf, &buftop);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case BOOLEXP_IS:
|
|
safe_chr(IS_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
break;
|
|
case BOOLEXP_CARRY:
|
|
safe_chr(CARRY_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
break;
|
|
case BOOLEXP_OWNER:
|
|
safe_chr(OWNER_TOKEN, boolexp_buf, &buftop);
|
|
unparse_boolexp1(player, b->sub1, b->type, format);
|
|
break;
|
|
case BOOLEXP_CONST:
|
|
|
|
if (mudstate.bStandAlone)
|
|
{
|
|
safe_str(unparse_object_quiet(player, b->thing),
|
|
boolexp_buf, &buftop);
|
|
}
|
|
else
|
|
{
|
|
switch (format)
|
|
{
|
|
case F_QUIET:
|
|
|
|
// Quiet output - for dumps and internal use. Always #Num.
|
|
//
|
|
safe_str(unparse_object_quiet(player, b->thing),
|
|
boolexp_buf, &buftop);
|
|
break;
|
|
|
|
case F_EXAMINE:
|
|
|
|
// Examine output - informative. Name(#Num) or Name.
|
|
//
|
|
UTF8 *buff;
|
|
|
|
buff = unparse_object(player, b->thing, false);
|
|
safe_str(buff, boolexp_buf, &buftop);
|
|
free_lbuf(buff);
|
|
break;
|
|
|
|
case F_DECOMPILE:
|
|
|
|
// Decompile output - should be usable on other MUXes. Name if
|
|
// player, Name if thing, else #Num.
|
|
//
|
|
switch (Typeof(b->thing))
|
|
{
|
|
case TYPE_PLAYER:
|
|
|
|
safe_chr('*', boolexp_buf, &buftop);
|
|
|
|
case TYPE_THING:
|
|
|
|
safe_str(Name(b->thing), boolexp_buf, &buftop);
|
|
break;
|
|
|
|
default:
|
|
|
|
safe_tprintf_str(boolexp_buf, &buftop, T("#%d"), b->thing);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case F_FUNCTION:
|
|
|
|
// Function output - must be usable by @lock cmd. Name if player,
|
|
// else #Num.
|
|
//
|
|
switch (Typeof(b->thing))
|
|
{
|
|
case TYPE_PLAYER:
|
|
|
|
safe_chr('*', boolexp_buf, &buftop);
|
|
safe_str(Name(b->thing), boolexp_buf, &buftop);
|
|
break;
|
|
|
|
default:
|
|
|
|
safe_tprintf_str(boolexp_buf, &buftop, T("#%d"), b->thing);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BOOLEXP_ATR:
|
|
case BOOLEXP_EVAL:
|
|
ATTR *ap;
|
|
|
|
ap = atr_num(b->thing);
|
|
if (ap && ap->number)
|
|
{
|
|
// Use the attribute name if the attribute exists.
|
|
//
|
|
safe_str(ap->name, boolexp_buf, &buftop);
|
|
}
|
|
else
|
|
{
|
|
// Otherwise use the attribute number.
|
|
//
|
|
// Only god or the db loader can create a new boolexp
|
|
// with an invalid attribute, but anyone may keep a lock
|
|
// whose attribute has subsequently disappeared.
|
|
//
|
|
safe_ltoa(b->thing, boolexp_buf, &buftop);
|
|
}
|
|
if (b->type == BOOLEXP_EVAL)
|
|
{
|
|
safe_chr('/', boolexp_buf, &buftop);
|
|
}
|
|
else
|
|
{
|
|
safe_chr(':', boolexp_buf, &buftop);
|
|
}
|
|
safe_str(reinterpret_cast<UTF8 *>(b->sub1), boolexp_buf, &buftop);
|
|
break;
|
|
|
|
default:
|
|
|
|
// Bad type.
|
|
//
|
|
Log.WriteString(T("ABORT! unparse.cpp, fell off the end of switch in unparse_boolexp1()" ENDLINE));
|
|
Log.Flush();
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
|
|
UTF8 *unparse_boolexp_quiet(dbref player, BOOLEXP *b)
|
|
{
|
|
buftop = boolexp_buf;
|
|
unparse_boolexp1(player, b, BOOLEXP_CONST, F_QUIET);
|
|
*buftop = '\0';
|
|
return boolexp_buf;
|
|
}
|
|
|
|
UTF8 *unparse_boolexp(dbref player, BOOLEXP *b)
|
|
{
|
|
buftop = boolexp_buf;
|
|
unparse_boolexp1(player, b, BOOLEXP_CONST, F_EXAMINE);
|
|
*buftop = '\0';
|
|
return boolexp_buf;
|
|
}
|
|
|
|
UTF8 *unparse_boolexp_decompile(dbref player, BOOLEXP *b)
|
|
{
|
|
buftop = boolexp_buf;
|
|
unparse_boolexp1(player, b, BOOLEXP_CONST, F_DECOMPILE);
|
|
*buftop = '\0';
|
|
return boolexp_buf;
|
|
}
|
|
|
|
UTF8 *unparse_boolexp_function(dbref player, BOOLEXP *b)
|
|
{
|
|
buftop = boolexp_buf;
|
|
unparse_boolexp1(player, b, BOOLEXP_CONST, F_FUNCTION);
|
|
*buftop = '\0';
|
|
return boolexp_buf;
|
|
}
|