tinymux/mux/modules/engine/unparse.cpp

258 lines
7 KiB
C++
Raw Permalink Normal View History

/*! \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);
Convert all static scratch buffers to thread_local 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>
2026-04-05 17:21:14 -06:00
thread_local UTF8 buf[SBUF_SIZE];
mux_sprintf(buf, SBUF_SIZE, T("(#%d)"), loc);
return buf;
}
Convert all static scratch buffers to thread_local 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>
2026-04-05 17:21:14 -06:00
thread_local UTF8 boolexp_buf[LBUF_SIZE];
static UTF8 *buftop;
static void unparse_boolexp1(dbref player, BOOLEXP *b, UTF8 outer_type, int format)
{
2013-09-10 20:07:52 -06:00
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;
}