tinymux/mux/modules/engine/file_c.cpp
Stephen Dennis b5ee3b6f81 refactor: use UTF-8 text in user-facing string literals (#1513)
Replace ~900 typographic \xE2\x80\x.. escapes (curly quotes, en dashes)
and a few \xE2\x80\230 octal workarounds with real UTF-8 in message
strings under mux/modules and mux/src. Leave stringutil and convert
charset mapping tables as explicit byte sequences.
2026-07-26 21:52:48 -06:00

287 lines
7.1 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*! \file file_c.cpp
* \brief File cache management.
*
* These functions load, cache, and display text files for the
* connect screen, motd, and similar uses.
*/
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"
typedef struct filecache_block_hdr FBLKHDR;
typedef struct filecache_block FBLOCK;
struct filecache_block
{
struct filecache_block_hdr
{
struct filecache_block *nxt;
unsigned int nchars;
} hdr;
UTF8 data[MBUF_SIZE - sizeof(struct filecache_block_hdr)];
};
struct filecache_hdr
{
UTF8 **ppFilename;
FBLOCK *fileblock;
const UTF8 *desc;
};
typedef struct filecache_hdr FCACHE;
#define FBLOCK_SIZE (MBUF_SIZE - sizeof(FBLKHDR))
static FCACHE fcache[] =
{
{ &mudconf.conn_file, nullptr, T("Conn") },
{ &mudconf.site_file, nullptr, T("Conn/Badsite") },
{ &mudconf.down_file, nullptr, T("Conn/Down") },
{ &mudconf.full_file, nullptr, T("Conn/Full") },
{ &mudconf.guest_file, nullptr, T("Conn/Guest") },
{ &mudconf.creg_file, nullptr, T("Conn/Reg") },
{ &mudconf.crea_file, nullptr, T("Crea/Newuser") },
{ &mudconf.regf_file, nullptr, T("Crea/RegFaill") },
{ &mudconf.motd_file, nullptr, T("Motd") },
{ &mudconf.wizmotd_file, nullptr, T("Wizmotd") },
{ &mudconf.quit_file, nullptr, T("Quit") },
{ &mudconf.conn_help_file, nullptr, T("Conn/Help") },
{ nullptr, nullptr, nullptr }
};
static NAMETAB list_files[] =
{
{T("badsite_connect"), 1, CA_WIZARD, FC_CONN_SITE},
{T("connect"), 2, CA_WIZARD, FC_CONN},
{T("connect_help"), 2, CA_WIZARD, FC_CONN_HELP},
{T("create_register"), 2, CA_WIZARD, FC_CREA_REG},
{T("down"), 1, CA_WIZARD, FC_CONN_DOWN},
{T("full"), 1, CA_WIZARD, FC_CONN_FULL},
{T("guest_motd"), 1, CA_WIZARD, FC_CONN_GUEST},
{T("motd"), 1, CA_WIZARD, FC_MOTD},
{T("newuser"), 1, CA_WIZARD, FC_CREA_NEW},
{T("quit"), 1, CA_WIZARD, FC_QUIT},
{T("register_connect"), 1, CA_WIZARD, FC_CONN_REG},
{T("wizard_motd"), 1, CA_WIZARD, FC_WIZMOTD},
{ nullptr, 0, 0, 0}
};
void do_list_file(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *arg, const UTF8 *cargs[], int ncargs)
{
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(eval);
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);
int flagvalue;
if (!search_nametab(executor, list_files, arg, &flagvalue))
{
display_nametab(executor, list_files, T("Unknown file. Use one of"), true);
return;
}
fcache_send(executor, flagvalue);
}
static FBLOCK *fcache_fill(FBLOCK *fp, UTF8 ch)
{
if (fp->hdr.nchars >= sizeof(fp->data))
{
// We filled the current buffer. Go get a new one.
//
FBLOCK *tfp = fp;
fp = reinterpret_cast<FBLOCK *>(alloc_mbuf("fcache_fill"));
fp->hdr.nxt = nullptr;
fp->hdr.nchars = 0;
tfp->hdr.nxt = fp;
}
fp->data[fp->hdr.nchars++] = ch;
return fp;
}
static int fcache_read(FBLOCK **cp, UTF8 *filename)
{
// Free a prior buffer chain.
//
FBLOCK *fp = *cp;
while (fp != nullptr)
{
FBLOCK *tfp = fp->hdr.nxt;
free_mbuf(fp);
fp = tfp;
}
*cp = nullptr;
// Read the text file into a new chain.
//
int fd;
UTF8 *buff;
if (!mux_open(&fd, filename, O_RDONLY|O_BINARY))
{
// Failure: log the event
//
STARTLOG(LOG_PROBLEMS, "FIL", "OPEN");
buff = alloc_mbuf("fcache_read.LOG");
mux_sprintf(buff, MBUF_SIZE, T("Couldnt open file %s."), filename);
log_text(buff);
free_mbuf(buff);
ENDLOG
return -1;
}
LBuf lbuf_temp = LBuf_Src("fcache_read.temp");
// Set up the initial cache buffer to make things easier.
//
fp = reinterpret_cast<FBLOCK *>(alloc_mbuf("fcache_read.first"));
fp->hdr.nxt = nullptr;
fp->hdr.nchars = 0;
*cp = fp;
int tchars = 0;
// Process the file, one lbuf at a time.
//
int nmax = mux_read(fd, lbuf_temp, LBUF_SIZE);
while (nmax > 0)
{
for (int n = 0; n < nmax; n++)
{
switch (lbuf_temp[n])
{
case '\n':
fp = fcache_fill(fp, '\r');
fp = fcache_fill(fp, '\n');
tchars += 2;
case '\0':
case '\r':
break;
default:
fp = fcache_fill(fp, lbuf_temp[n]);
tchars++;
}
}
nmax = mux_read(fd, lbuf_temp, LBUF_SIZE);
}
mux_close(fd);
// If we didn't read anything in, toss the initial buffer.
//
if (fp->hdr.nchars == 0)
{
*cp = nullptr;
free_mbuf(fp);
}
return tchars;
}
void fcache_rawdump(SOCKET fd, int num)
{
if ((num < 0) || (num > FC_LAST))
{
return;
}
FBLOCK *fp = fcache[num].fileblock;
int cnt, remaining;
UTF8 *start;
while (fp != nullptr)
{
start = fp->data;
remaining = fp->hdr.nchars;
while (remaining > 0)
{
cnt = SOCKET_WRITE(fd, reinterpret_cast<char *>(start), remaining, 0);
if (cnt < 0)
{
return;
}
remaining -= cnt;
start += cnt;
}
fp = fp->hdr.nxt;
}
return;
}
void fcache_dump(DESC *d, int num)
{
if ((num < 0) || (num > FC_LAST))
{
return;
}
FBLOCK *fp = fcache[num].fileblock;
while (fp != nullptr)
{
queue_write_LEN(d, fp->data, fp->hdr.nchars);
fp = fp->hdr.nxt;
}
}
struct fcache_send_context
{
int num;
};
static void fcache_send_callback(DESC *d, void *ctx)
{
const fcache_send_context *fsc = static_cast<fcache_send_context *>(ctx);
fcache_dump(d, fsc->num);
}
void fcache_send(const dbref player, const int num)
{
fcache_send_context ctx = { num };
for_each_player_desc(player, fcache_send_callback, &ctx);
}
void fcache_load(dbref player)
{
FCACHE *fp;
UTF8 *bufc, *sbuf;
LBuf buff = LBuf_Src("fcache_load.lbuf");
bufc = buff.get();
sbuf = alloc_sbuf("fcache_load.sbuf");
for (fp = fcache; fp->ppFilename; fp++)
{
int i = fcache_read(&fp->fileblock, *fp->ppFilename);
if ( player != NOTHING
&& !Quiet(player))
{
mux_ltoa(i, sbuf);
if (fp == fcache)
{
safe_str(T("File sizes: "), buff, &bufc);
}
else
{
safe_str(T(" "), buff, &bufc);
}
safe_str(fp->desc, buff, &bufc);
safe_str(T("..."), buff, &bufc);
safe_str(sbuf, buff, &bufc);
}
}
*bufc = '\0';
if ( player != NOTHING
&& !Quiet(player))
{
notify(player, buff);
}
free_sbuf(sbuf);
}
void fcache_init(void)
{
FCACHE *fp = fcache;
for (fp = fcache; fp->ppFilename; fp++)
{
fp->fileblock = nullptr;
}
fcache_load(NOTHING);
}