mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
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.
287 lines
7.1 KiB
C++
287 lines
7.1 KiB
C++
/*! \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("Couldn’t 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);
|
||
}
|