tinymux/mux/include/stringutil.h
Stephen Dennis 8808b4c375 feat(#2136): flip fargs to const UTF8 * const — and convert every site the compiler surfaced
The flip: FUNCTION/XFUNCTION/FUN::fun/delim_check and the module
interfaces take `const UTF8 * const fargs[]`.  Double-const is
load-bearing: C++ qualification conversion needs const at both pointer
levels, so builder-side `UTF8 *[]` arrays convert implicitly — the
evaluator, the JIT marshaller, and every owner site need zero casts,
and slot reassignment inside bodies becomes a compile error for free.

The conversions: the flip landed first so the compiler enumerated every
violation; this commit is that inventory worked to zero — ~250 sites
across funceval, funceval2, functions, funmath, help, mail, session,
powers, levels, predicates, conf, walkdb, stringutil, timeutil/
date_scan (regenerated, one-line diff), exp3, and mux_main, each
classified per docs/campaign-2136-const-fargs.md's four recipes.

New idioms (functions.h): trim_space_sep_n() — non-destructive trim for
(pointer, length) consumers, so trim-then-scan sites need no copy at
all; FargVec — the argv counterpart of FargCopy for CS_ARGV handlers.
countwords() and DecodeListOfIntegers() rewritten non-destructive.

The flip deleted more than it added: #2157's fun_munge list1 copy, the
engine_com help-topic copy, fun_index's in-place NUL write, and five
const_casts (process_sex x4, sha1_helper).  const_cast budget: zero
added.

Trap recorded in the brief: an old-signature definition doesn't fail
the build — it becomes a C++ overload, and the new-signature symbol
stays undefined until dlopen(RTLD_NOW).  delim_check, the conn_bridge
bridges, the dbt_spike stub, and exp3::Call were all silently shadowed;
muxscript was the only host that noticed, because netmux's own net.cpp
resolved the flat-namespace lookup.  After any signature flip, grep the
old spelling.

Verified: make test EXPECT_CONFIG="jit=yes" (35 passed / 0 failed) and
make test-scenario, including the new tests/scenario/sidefx_fargs.py
that live-probes the class-3 wrappers smoke never touches (pemit/
trigger/link/tel/wipe/destroy).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 14:34:23 -06:00

1977 lines
70 KiB
C++

/*! \file stringutil.h
* \brief string utilities.
*
*/
#ifndef STRINGUTIL_H
#define STRINGUTIL_H
#define mux_strlen(x) strlen(reinterpret_cast<const char *>(x))
inline bool isEmpty(const UTF8 *p)
{
return ((nullptr == p) || ('\0' == p[0]));
}
extern LIBMUX_API const bool mux_isprint_ascii[256];
extern LIBMUX_API const bool mux_isprint_cp437[256];
extern LIBMUX_API const bool mux_isprint_latin1[256];
extern LIBMUX_API const bool mux_isprint_latin2[256];
extern LIBMUX_API const bool mux_isdigit[256];
extern LIBMUX_API const bool mux_isxdigit[256];
extern LIBMUX_API const bool mux_isazAZ[256];
extern LIBMUX_API const bool mux_isalnum[256];
extern LIBMUX_API const bool mux_islower_ascii[256];
extern LIBMUX_API const bool mux_isupper_ascii[256];
extern LIBMUX_API const bool mux_isspace[256];
extern LIBMUX_API const bool mux_issecure[256];
extern LIBMUX_API const bool mux_isescape[256];
extern LIBMUX_API const unsigned char mux_hex2dec[256];
// mux_toupper_ascii[] and mux_tolower_ascii[] handle ASCII A-Z/a-z only.
// Use mux_toupper()/mux_tolower() (state-machine transforms) for Unicode.
// These ASCII tables are appropriate only when the input is known to be ASCII
// (e.g., format modifiers, month abbreviations, %VA-%VZ attribute indices).
//
extern LIBMUX_API const unsigned char mux_toupper_ascii[256];
extern LIBMUX_API const unsigned char mux_tolower_ascii[256];
extern LIBMUX_API const UTF8 TableATOI[16][10];
#define UTF8_SIZE1 1
#define UTF8_SIZE2 2
#define UTF8_SIZE3 3
#define UTF8_SIZE4 4
#define UTF8_CONTINUE 5
#define UTF8_ILLEGAL 6
extern "C" LIBMUX_API const unsigned char utf8_FirstByte[256];
extern LIBMUX_API const UTF8 *cp437_utf8[256];
#define cp437_utf8(x) (reinterpret_cast<const UTF8 *>(cp437_utf8[static_cast<unsigned char>(x)]))
extern LIBMUX_API const UTF8 *latin1_utf8[256];
#define latin1_utf8(x) (reinterpret_cast<const UTF8 *>(latin1_utf8[static_cast<unsigned char>(x)]))
extern LIBMUX_API const UTF8 *latin2_utf8[256];
#define latin2_utf8(x) (reinterpret_cast<const UTF8 *>(latin2_utf8[static_cast<unsigned char>(x)]))
#define UNI_EOF ((UTF32)-1)
#define UNI_REPLACEMENT_CHAR ((UTF32)0x0000FFFDUL)
#define UNI_MAX_BMP ((UTF32)0x0000FFFFUL)
#define UNI_MAX_UTF16 ((UTF32)0x0010FFFFUL)
#define UNI_MAX_UTF32 ((UTF32)0x7FFFFFFFUL)
#define UNI_MAX_LEGAL_UTF32 ((UTF32)0x0010FFFFUL)
#define UNI_SUR_HIGH_START ((UTF32)0x0000D800UL)
#define UNI_SUR_HIGH_END ((UTF32)0x0000DBFFUL)
#define UNI_SUR_LOW_START ((UTF32)0x0000DC00UL)
#define UNI_SUR_LOW_END ((UTF32)0x0000DFFFUL)
#define UNI_PU1_START ((UTF32)0x0000E000UL)
#define UNI_PU1_END ((UTF32)0x0000F8FFUL)
#define UNI_PU2_START ((UTF32)0x000F0000UL)
#define UNI_PU2_END ((UTF32)0x000FFFFDUL)
#define UNI_PU3_START ((UTF32)0x00100000UL)
#define UNI_PU3_END ((UTF32)0x0010FFFDUL)
// Decode a validated UTF-8 sequence of n bytes into a Unicode scalar value.
// The caller must have already verified that p[0] is a valid lead byte and
// p[1..n-1] are valid continuation bytes.
//
inline UTF32 utf8_decode_raw(const UTF8 *p, size_t n)
{
if (1 == n) return p[0];
if (2 == n)
{
return ((UTF32)(p[0] & 0x1F) << 6)
| (UTF32)(p[1] & 0x3F);
}
if (3 == n)
{
return ((UTF32)(p[0] & 0x0F) << 12)
| ((UTF32)(p[1] & 0x3F) << 6)
| (UTF32)(p[2] & 0x3F);
}
return ((UTF32)(p[0] & 0x07) << 18)
| ((UTF32)(p[1] & 0x3F) << 12)
| ((UTF32)(p[2] & 0x3F) << 6)
| (UTF32)(p[3] & 0x3F);
}
// Check whether a decoded scalar value is valid for its encoding length.
// Rejects overlong encodings, surrogates (U+D800..U+DFFF), and values
// beyond U+10FFFF.
//
inline bool utf8_is_valid_scalar(UTF32 cp, size_t n)
{
if ( (2 == n && cp < 0x80)
|| (3 == n && cp < 0x800)
|| (4 == n && cp < 0x10000)
|| cp > UNI_MAX_LEGAL_UTF32
|| (cp >= UNI_SUR_HIGH_START && cp <= UNI_SUR_LOW_END))
{
return false;
}
return true;
}
// This function trims the string back to the first valid UTF-8 sequence it
// finds, but it does not validate the entire string.
//
inline size_t TrimPartialSequence(size_t n, const UTF8 *p)
{
while (0 < n)
{
size_t iStart = n - 1;
while (0 < iStart && UTF8_CONTINUE == utf8_FirstByte[p[iStart]])
{
iStart--;
}
int nBytes = utf8_FirstByte[p[iStart]];
if (nBytes < 1 || nBytes >= UTF8_CONTINUE)
{
n = iStart;
continue;
}
if (iStart + static_cast<size_t>(nBytes) != n)
{
n = iStart;
continue;
}
bool bValid = true;
for (int i = 1; i < nBytes; i++)
{
if (UTF8_CONTINUE != utf8_FirstByte[p[iStart + i]])
{
bValid = false;
break;
}
}
if (!bValid)
{
n = iStart;
continue;
}
UTF32 cp = utf8_decode_raw(p + iStart, static_cast<size_t>(nBytes));
if (!utf8_is_valid_scalar(cp, static_cast<size_t>(nBytes)))
{
n = iStart;
continue;
}
return n;
}
return 0;
}
#define mux_isprint_ascii(x) (mux_isprint_ascii[static_cast<unsigned char>(x)])
#define mux_isprint_cp437(x) (mux_isprint_cp437[static_cast<unsigned char>(x)])
#define mux_isprint_latin1(x) (mux_isprint_latin1[static_cast<unsigned char>(x)])
#define mux_isprint_latin2(x) (mux_isprint_latin2[static_cast<unsigned char>(x)])
#define mux_isdigit(x) (mux_isdigit[static_cast<unsigned char>(x)])
#define mux_isxdigit(x)(mux_isxdigit[static_cast<unsigned char>(x)])
#define mux_isazAZ(x) (mux_isazAZ[static_cast<unsigned char>(x)])
#define mux_isalpha(x) (mux_isazAZ[static_cast<unsigned char>(x)])
#define mux_isalnum(x) (mux_isalnum[static_cast<unsigned char>(x)])
#define mux_islower_ascii(x) (mux_islower_ascii[static_cast<unsigned char>(x)])
#define mux_isupper_ascii(x) (mux_isupper_ascii[static_cast<unsigned char>(x)])
#define mux_isspace(x) (mux_isspace[static_cast<unsigned char>(x)])
#define mux_hex2dec(x) (mux_hex2dec[static_cast<unsigned char>(x)])
#define mux_toupper_ascii(x) (mux_toupper_ascii[static_cast<unsigned char>(x)])
#define mux_tolower_ascii(x) (mux_tolower_ascii[static_cast<unsigned char>(x)])
#define TableATOI(x,y) (TableATOI[static_cast<unsigned char>(x)][static_cast<unsigned char>(y)])
#define mux_issecure(x) (mux_issecure[static_cast<unsigned char>(x)])
#define mux_isescape(x) (mux_isescape[static_cast<unsigned char>(x)])
#define utf8_NextCodePoint(x) (x + utf8_FirstByte[static_cast<unsigned char>(*x)])
// utf/cl_Printable.txt
//
inline bool mux_isprint(const unsigned char *p)
{
unsigned short iState = CL_PRINT_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_print_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = cl_print_sot[iState];
for (;;)
{
int y = cl_print_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_print_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_print_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < CL_PRINT_ACCEPTING_STATES_START);
return ((iState - CL_PRINT_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_Alpha.txt
//
inline bool mux_isalpha_utf8(const unsigned char *p)
{
unsigned short iState = CL_ALPHA_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_alpha_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = cl_alpha_sot[iState];
for (;;)
{
int y = cl_alpha_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_alpha_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_alpha_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < CL_ALPHA_ACCEPTING_STATES_START);
return ((iState - CL_ALPHA_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_Digit.txt
//
inline bool mux_isdigit_utf8(const unsigned char *p)
{
unsigned char iState = CL_DIGIT_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_digit_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_digit_sot[iState];
for (;;)
{
int y = cl_digit_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_digit_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_digit_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_DIGIT_ACCEPTING_STATES_START);
return ((iState - CL_DIGIT_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_Alnum.txt
//
inline bool mux_isalnum_utf8(const unsigned char *p)
{
unsigned short iState = CL_ALNUM_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_alnum_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = cl_alnum_sot[iState];
for (;;)
{
int y = cl_alnum_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_alnum_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_alnum_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < CL_ALNUM_ACCEPTING_STATES_START);
return ((iState - CL_ALNUM_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_AttrNameInitial.txt
//
inline bool mux_isattrnameinitial(const unsigned char *p)
{
unsigned char iState = CL_ATTRNAMEINITIAL_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_attrnameinitial_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_attrnameinitial_sot[iState];
for (;;)
{
int y = cl_attrnameinitial_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_attrnameinitial_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_attrnameinitial_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_ATTRNAMEINITIAL_ACCEPTING_STATES_START);
return ((iState - CL_ATTRNAMEINITIAL_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_AttrName.txt
//
inline bool mux_isattrname(const unsigned char *p)
{
unsigned char iState = CL_ATTRNAME_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_attrname_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_attrname_sot[iState];
for (;;)
{
int y = cl_attrname_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_attrname_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_attrname_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_ATTRNAME_ACCEPTING_STATES_START);
return ((iState - CL_ATTRNAME_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_Objectname.txt
//
inline bool mux_isobjectname(const unsigned char *p)
{
unsigned char iState = CL_OBJECTNAME_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_objectname_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = cl_objectname_sot[iState];
for (;;)
{
int y = cl_objectname_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_objectname_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_objectname_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_OBJECTNAME_ACCEPTING_STATES_START);
return ((iState - CL_OBJECTNAME_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_PlayerName.txt
//
inline bool mux_isplayername(const unsigned char *p)
{
unsigned char iState = CL_PLAYERNAME_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_playername_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = cl_playername_sot[iState];
for (;;)
{
int y = cl_playername_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_playername_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_playername_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_PLAYERNAME_ACCEPTING_STATES_START);
return ((iState - CL_PLAYERNAME_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_8859_1.txt
//
inline bool mux_is8859_1(const unsigned char *p)
{
unsigned char iState = CL_8859_1_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_8859_1_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_8859_1_sot[iState];
for (;;)
{
int y = cl_8859_1_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_8859_1_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_8859_1_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_8859_1_ACCEPTING_STATES_START);
return ((iState - CL_8859_1_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_8859_2.txt
//
inline bool mux_is8859_2(const unsigned char *p)
{
unsigned char iState = CL_8859_2_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_8859_2_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_8859_2_sot[iState];
for (;;)
{
int y = cl_8859_2_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_8859_2_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_8859_2_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_8859_2_ACCEPTING_STATES_START);
return ((iState - CL_8859_2_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_hangul.txt
//
inline bool mux_ishangul(const unsigned char *p)
{
unsigned char iState = CL_HANGUL_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_hangul_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_hangul_sot[iState];
for (;;)
{
int y = cl_hangul_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_hangul_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_hangul_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_HANGUL_ACCEPTING_STATES_START);
return ((iState - CL_HANGUL_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_hiragana.txt
//
inline bool mux_ishiragana(const unsigned char *p)
{
unsigned char iState = CL_HIRAGANA_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_hiragana_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_hiragana_sot[iState];
for (;;)
{
int y = cl_hiragana_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_hiragana_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_hiragana_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_HIRAGANA_ACCEPTING_STATES_START);
return ((iState - CL_HIRAGANA_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_kanji.txt
//
inline bool mux_iskanji(const unsigned char *p)
{
unsigned char iState = CL_KANJI_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_kanji_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_kanji_sot[iState];
for (;;)
{
int y = cl_kanji_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_kanji_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_kanji_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_KANJI_ACCEPTING_STATES_START);
return ((iState - CL_KANJI_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/cl_katakana.txt
//
inline bool mux_iskatakana(const unsigned char *p)
{
unsigned char iState = CL_KATAKANA_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = cl_katakana_itt[static_cast<unsigned char>(ch)];
unsigned char iOffset = cl_katakana_sot[iState];
for (;;)
{
int y = cl_katakana_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = cl_katakana_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = cl_katakana_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned char>(iOffset + y + 1);
}
}
}
} while (iState < CL_KATAKANA_ACCEPTING_STATES_START);
return ((iState - CL_KATAKANA_ACCEPTING_STATES_START) == 1) ? true : false;
}
// utf/tr_utf8_ascii.txt
//
LIBMUX_API const UTF8 *ConvertToAscii(const UTF8 *pString);
// utf/tr_utf8_cp437.txt
//
LIBMUX_API const UTF8 *ConvertToCp437(const UTF8 *pString);
// utf/tr_utf8_latin1.txt
//
LIBMUX_API const UTF8 *ConvertToLatin1(const UTF8 *pString);
// utf/tr_utf8_latin2.txt
//
LIBMUX_API const UTF8 *ConvertToLatin2(const UTF8 *pString);
// utf/tr_widths.txt
//
LIBMUX_API int ConsoleWidth(const UTF8 *pCodePoint);
// utf/utf8_normalize.cpp — NFC normalization.
//
LIBMUX_API bool utf8_is_nfc(const UTF8 *src, size_t nSrc);
LIBMUX_API void utf8_normalize_nfc(const UTF8 *src, size_t nSrc, UTF8 *dst, size_t nDstMax, size_t *pnDst);
// utf8_collate.cpp — Unicode Collation Algorithm (UCA).
//
LIBMUX_API int mux_collate_cmp(const UTF8 *a, size_t nA, const UTF8 *b, size_t nB);
LIBMUX_API size_t mux_collate_sortkey(const UTF8 *src, size_t nSrc, UTF8 *key, size_t nKeyMax);
LIBMUX_API int mux_collate_cmp_ci(const UTF8 *a, size_t nA, const UTF8 *b, size_t nB);
LIBMUX_API size_t mux_collate_sortkey_ci(const UTF8 *src, size_t nSrc, UTF8 *key, size_t nKeyMax);
// Case mapping and fold-match: thin wrappers around the co_dfa_* functions
// from unicode_tables_c.h. string_desc and co_string_desc are ABI-identical
// (UTF8 is unsigned char), so the reinterpret_cast is safe.
//
#include "unicode_tables_c.h"
inline const string_desc *mux_tolower(const unsigned char *p, bool &bXor)
{
int iXor;
const co_string_desc *r = co_dfa_tolower(p, &iXor);
bXor = (iXor != 0);
return reinterpret_cast<const string_desc *>(r);
}
inline const string_desc *mux_toupper(const unsigned char *p, bool &bXor)
{
int iXor;
const co_string_desc *r = co_dfa_toupper(p, &iXor);
bXor = (iXor != 0);
return reinterpret_cast<const string_desc *>(r);
}
inline const string_desc *mux_totitle(const unsigned char *p, bool &bXor)
{
int iXor;
const co_string_desc *r = co_dfa_totitle(p, &iXor);
bXor = (iXor != 0);
return reinterpret_cast<const string_desc *>(r);
}
inline const string_desc *mux_foldmatch(const unsigned char *p, bool &bXor)
{
int iXor;
const co_string_desc *r = co_dfa_foldmatch(p, &iXor);
bXor = (iXor != 0);
return reinterpret_cast<const string_desc *>(r);
}
// utf/tr_Color.txt
//
// SMP PUA 24-bit color: U+F0000-F3FFF (4 blocks of 4096)
// UTF-8: F3 (B0-B3) (80-BF) (80-BF)
// Block 0 (B0): FG CP1 — R high nibble + G
// Block 1 (B1): FG CP2 — R low nibble + B
// Block 2 (B2): BG CP1 — R high nibble + G
// Block 3 (B3): BG CP2 — R low nibble + B
//
// These are handled by a prefix check before the DFA, returning
// 518..521 (COLOR_INDEX_FG_24_CP1..COLOR_INDEX_BG_24_CP2).
//
// The constant 518 = NUM_OTHER + NUM_ATTR + NUM_FG + NUM_BG = 2+4+256+256.
// It must match COLOR_INDEX_FG_24_CP1 defined below.
//
inline int mux_color(const unsigned char *p)
{
// SMP PUA 24-bit color prefix check (avoids 16K-entry DFA).
// Validate full 4-byte UTF-8 form to avoid misclassifying malformed data.
//
if ( 0xF3 == p[0]
&& 0xB0 <= p[1]
&& p[1] <= 0xB3
&& 0x80 <= p[2] && p[2] <= 0xBF
&& 0x80 <= p[3] && p[3] <= 0xBF)
{
return 518 + (p[1] - 0xB0);
}
unsigned short iState = TR_COLOR_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = tr_color_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = tr_color_sot[iState];
for (;;)
{
int y = tr_color_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = tr_color_sbt[iOffset+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset += 2;
}
}
else
{
// COPY phrase.
//
y = 256-y;
if (iColumn < y)
{
iState = tr_color_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < TR_COLOR_ACCEPTING_STATES_START);
return iState - TR_COLOR_ACCEPTING_STATES_START;
}
// Extract 12-bit payload from a 4-byte SMP PUA code point.
// p must point to F3 Bx xx xx where x is B0-B3.
//
inline unsigned int mux_color_smp_payload(const unsigned char *p)
{
return (static_cast<unsigned int>(p[2] - 0x80) << 6)
| static_cast<unsigned int>(p[3] - 0x80);
}
#define mux_haswidth(x) mux_isprint(x)
LIBMUX_API bool utf8_strlen(const UTF8 *pString, size_t &nString);
// This class replaces the functionality of the strtok() C runtime library
// function. Set the source and control, and then call parse to obtain tokens.
//
// You may reset the control between calls to parse, however note that
// parsing does not consume -all- of the controlling delimiters that separate
// two tokens. It consumes only the first one.
//
class LIBMUX_API string_token
{
public:
string_token() : source(nullptr)
{
memset(control, 0, sizeof(control));
}
string_token(UTF8* source, const UTF8* control) : source(source)
{
set_control(control);
}
void set_source(UTF8* source);
void set_control(const UTF8* control);
UTF8* parse();
private:
UTF8* parse_length(size_t* length);
UTF8* source;
UTF8 control[256]{};
};
// Color State
//
typedef uint64_t ColorState;
// Indexes into the aColors table:
//
// The first entry is not used. The second is reset to normal. The next four
// are the four character attributes. Finally, we see the 256 foreground and
// background colors.
//
#define NUM_OTHER 2
#define NUM_ATTR 4
#define NUM_FG 256
#define NUM_BG 256
#define COLOR_INDEX_ATTR (NUM_OTHER)
#define COLOR_INDEX_FG (COLOR_INDEX_ATTR + NUM_ATTR)
#define COLOR_INDEX_BG (COLOR_INDEX_FG + NUM_FG)
#define COLOR_INDEX_FG_24_CP1 (COLOR_INDEX_BG + NUM_BG)
#define COLOR_INDEX_FG_24_CP2 (COLOR_INDEX_FG_24_CP1 + 1)
#define COLOR_INDEX_BG_24_CP1 (COLOR_INDEX_FG_24_CP2 + 1)
#define COLOR_INDEX_BG_24_CP2 (COLOR_INDEX_BG_24_CP1 + 1)
#define COLOR_INDEX_LAST COLOR_INDEX_BG_24_CP2
#define COLOR_INDEX_RESET 1
#define COLOR_INDEX_INTENSE (COLOR_INDEX_ATTR + 0)
#define COLOR_INDEX_UNDERLINE (COLOR_INDEX_ATTR + 1)
#define COLOR_INDEX_BLINK (COLOR_INDEX_ATTR + 2)
#define COLOR_INDEX_INVERSE (COLOR_INDEX_ATTR + 3)
#define COLOR_INDEX_BLACK 0
#define COLOR_INDEX_RED 1
#define COLOR_INDEX_GREEN 2
#define COLOR_INDEX_YELLOW 3
#define COLOR_INDEX_BLUE 4
#define COLOR_INDEX_MAGENTA 5
#define COLOR_INDEX_CYAN 6
#define COLOR_INDEX_WHITE 7
#define COLOR_INDEX_DEFAULT (NUM_FG)
#define COLOR_NOTCOLOR 0
#define COLOR_RESET "\xEF\x94\x80" // 1
#define COLOR_INTENSE "\xEF\x94\x81" // 2
#define COLOR_UNDERLINE "\xEF\x94\x84" // 3
#define COLOR_BLINK "\xEF\x94\x85" // 4
#define COLOR_INVERSE "\xEF\x94\x87" // 5
#define COLOR_FG_BLACK "\xEF\x98\x80" // 6
#define COLOR_FG_RED "\xEF\x98\x81" // 7
#define COLOR_FG_GREEN "\xEF\x98\x82" // 8
#define COLOR_FG_YELLOW "\xEF\x98\x83" // 9
#define COLOR_FG_BLUE "\xEF\x98\x84" // 10
#define COLOR_FG_MAGENTA "\xEF\x98\x85" // 11
#define COLOR_FG_CYAN "\xEF\x98\x86" // 12
#define COLOR_FG_WHITE "\xEF\x98\x87" // 13
#define COLOR_FG_555555 "\xEF\x98\x88" // 14
#define COLOR_FG_FF5555 "\xEF\x98\x89" // 15
#define COLOR_FG_55FF55 "\xEF\x98\x8A" // 16
#define COLOR_FG_FFFF55 "\xEF\x98\x8B" // 17
#define COLOR_FG_5555FF "\xEF\x98\x8C" // 18
#define COLOR_FG_FF55FF "\xEF\x98\x8D" // 19
#define COLOR_FG_55FFFF "\xEF\x98\x8E" // 20
#define COLOR_FG_FFFFFF_1 "\xEF\x98\x8F" // 21
#define COLOR_FG_000000 "\xEF\x98\x90" // 22
#define COLOR_FG_00005F "\xEF\x98\x91" // 23
#define COLOR_FG_000087 "\xEF\x98\x92" // 24
#define COLOR_FG_0000AF "\xEF\x98\x93" // 25
#define COLOR_FG_0000D7 "\xEF\x98\x94" // 26
#define COLOR_FG_0000FF "\xEF\x98\x95" // 27
#define COLOR_FG_005F00 "\xEF\x98\x96" // 28
#define COLOR_FG_005F5F "\xEF\x98\x97" // 29
#define COLOR_FG_005F87 "\xEF\x98\x98" // 30
#define COLOR_FG_005FAF "\xEF\x98\x99" // 31
#define COLOR_FG_005FD7 "\xEF\x98\x9A" // 32
#define COLOR_FG_005FFF "\xEF\x98\x9B" // 33
#define COLOR_FG_008700 "\xEF\x98\x9C" // 34
#define COLOR_FG_00875F "\xEF\x98\x9D" // 35
#define COLOR_FG_008785 "\xEF\x98\x9E" // 36
#define COLOR_FG_0087AF "\xEF\x98\x9F" // 37
#define COLOR_FG_0087D7 "\xEF\x98\xA0" // 38
#define COLOR_FG_0087FF "\xEF\x98\xA1" // 39
#define COLOR_FG_00AF00 "\xEF\x98\xA2" // 40
#define COLOR_FG_00AF5F "\xEF\x98\xA3" // 41
#define COLOR_FG_00AF87 "\xEF\x98\xA4" // 42
#define COLOR_FG_00AFAF "\xEF\x98\xA5" // 43
#define COLOR_FG_00AFD7 "\xEF\x98\xA6" // 44
#define COLOR_FG_00AFFF "\xEF\x98\xA7" // 45
#define COLOR_FG_00D700 "\xEF\x98\xA8" // 46
#define COLOR_FG_00D75F "\xEF\x98\xA9" // 47
#define COLOR_FG_00D787 "\xEF\x98\xAA" // 48
#define COLOR_FG_00D7AF "\xEF\x98\xAB" // 49
#define COLOR_FG_00D7D7 "\xEF\x98\xAC" // 50
#define COLOR_FG_00D7FF "\xEF\x98\xAD" // 51
#define COLOR_FG_00FF00 "\xEF\x98\xAE" // 52
#define COLOR_FG_00FF5A "\xEF\x98\xAF" // 53
#define COLOR_FG_00FF87 "\xEF\x98\xB0" // 54
#define COLOR_FG_00FFAF "\xEF\x98\xB1" // 55
#define COLOR_FG_00FFD7 "\xEF\x98\xB2" // 56
#define COLOR_FG_00FFFF "\xEF\x98\xB3" // 57
#define COLOR_FG_5F0000 "\xEF\x98\xB4" // 58
#define COLOR_FG_5F005F "\xEF\x98\xB5" // 59
#define COLOR_FG_5F0087 "\xEF\x98\xB6" // 60
#define COLOR_FG_5F00AF "\xEF\x98\xB7" // 61
#define COLOR_FG_5F00D7 "\xEF\x98\xB8" // 62
#define COLOR_FG_5F00FF "\xEF\x98\xB9" // 63
#define COLOR_FG_5F5F00 "\xEF\x98\xBA" // 64
#define COLOR_FG_5F5F5F "\xEF\x98\xBB" // 65
#define COLOR_FG_5F5F87 "\xEF\x98\xBC" // 66
#define COLOR_FG_5F5FAF "\xEF\x98\xBD" // 67
#define COLOR_FG_5F5FD7 "\xEF\x98\xBE" // 68
#define COLOR_FG_5F5FFF "\xEF\x98\xBF" // 69
#define COLOR_FG_5F8700 "\xEF\x99\x80" // 70
#define COLOR_FG_5F875F "\xEF\x99\x81" // 71
#define COLOR_FG_5F8787 "\xEF\x99\x82" // 72
#define COLOR_FG_5F87AF "\xEF\x99\x83" // 73
#define COLOR_FG_5F87D7 "\xEF\x99\x84" // 74
#define COLOR_FG_5F87FF "\xEF\x99\x85" // 75
#define COLOR_FG_5FAF00 "\xEF\x99\x86" // 76
#define COLOR_FG_5FAF5F "\xEF\x99\x87" // 77
#define COLOR_FG_5FAF87 "\xEF\x99\x88" // 78
#define COLOR_FG_5FAFAF "\xEF\x99\x89" // 79
#define COLOR_FG_5FAFD7 "\xEF\x99\x8A" // 80
#define COLOR_FG_5FAFFF "\xEF\x99\x8B" // 81
#define COLOR_FG_5FD700 "\xEF\x99\x8C" // 82
#define COLOR_FG_5FD75F "\xEF\x99\x8D" // 83
#define COLOR_FG_5FD787 "\xEF\x99\x8E" // 84
#define COLOR_FG_5FD7AF "\xEF\x99\x8F" // 85
#define COLOR_FG_5FD7D7 "\xEF\x99\x90" // 86
#define COLOR_FG_5FD7FF "\xEF\x99\x91" // 87
#define COLOR_FG_5FFF00 "\xEF\x99\x92" // 88
#define COLOR_FG_5FFF5F "\xEF\x99\x93" // 89
#define COLOR_FG_5FFF87 "\xEF\x99\x94" // 90
#define COLOR_FG_5FFFAF "\xEF\x99\x95" // 91
#define COLOR_FG_5FFFD7 "\xEF\x99\x96" // 92
#define COLOR_FG_5FFFFF "\xEF\x99\x97" // 93
#define COLOR_FG_870000 "\xEF\x99\x98" // 94
#define COLOR_FG_87005F "\xEF\x99\x99" // 95
#define COLOR_FG_870087 "\xEF\x99\x9A" // 96
#define COLOR_FG_8700AF "\xEF\x99\x9B" // 97
#define COLOR_FG_8700D7 "\xEF\x99\x9C" // 98
#define COLOR_FG_8700FF "\xEF\x99\x9D" // 99
#define COLOR_FG_875F00 "\xEF\x99\x9E" // 100
#define COLOR_FG_875F5F "\xEF\x99\x9F" // 101
#define COLOR_FG_875F87 "\xEF\x99\xA0" // 102
#define COLOR_FG_875FAF "\xEF\x99\xA1" // 103
#define COLOR_FG_875FD7 "\xEF\x99\xA2" // 104
#define COLOR_FG_875FFF "\xEF\x99\xA3" // 105
#define COLOR_FG_878700 "\xEF\x99\xA4" // 106
#define COLOR_FG_87875F "\xEF\x99\xA5" // 107
#define COLOR_FG_878787 "\xEF\x99\xA6" // 108
#define COLOR_FG_8787AF "\xEF\x99\xA7" // 109
#define COLOR_FG_8787D7 "\xEF\x99\xA8" // 110
#define COLOR_FG_8787FF "\xEF\x99\xA9" // 111
#define COLOR_FG_87AF00 "\xEF\x99\xAA" // 112
#define COLOR_FG_87AF5F "\xEF\x99\xAB" // 113
#define COLOR_FG_87AF87 "\xEF\x99\xAC" // 114
#define COLOR_FG_87AFAF "\xEF\x99\xAD" // 115
#define COLOR_FG_87AFD7 "\xEF\x99\xAE" // 116
#define COLOR_FG_87AFFF "\xEF\x99\xAF" // 117
#define COLOR_FG_87D700 "\xEF\x99\xB0" // 118
#define COLOR_FG_87D75A "\xEF\x99\xB1" // 119
#define COLOR_FG_87D787 "\xEF\x99\xB2" // 120
#define COLOR_FG_87D7AF "\xEF\x99\xB3" // 121
#define COLOR_FG_87D7D7 "\xEF\x99\xB4" // 122
#define COLOR_FG_87D7FF "\xEF\x99\xB5" // 123
#define COLOR_FG_87FF00 "\xEF\x99\xB6" // 124
#define COLOR_FG_87FF5F "\xEF\x99\xB7" // 125
#define COLOR_FG_87FF87 "\xEF\x99\xB8" // 126
#define COLOR_FG_87FFAF "\xEF\x99\xB9" // 127
#define COLOR_FG_87FFD7 "\xEF\x99\xBA" // 128
#define COLOR_FG_87FFFF "\xEF\x99\xBB" // 129
#define COLOR_FG_AF0000 "\xEF\x99\xBC" // 130
#define COLOR_FG_AF005F "\xEF\x99\xBD" // 131
#define COLOR_FG_AF0087 "\xEF\x99\xBE" // 132
#define COLOR_FG_AF00AF "\xEF\x99\xBF" // 133
#define COLOR_FG_AF00D7 "\xEF\x9A\x80" // 134
#define COLOR_FG_AF00FF "\xEF\x9A\x81" // 135
#define COLOR_FG_AF5F00 "\xEF\x9A\x82" // 136
#define COLOR_FG_AF5F5F "\xEF\x9A\x83" // 137
#define COLOR_FG_AF5F87 "\xEF\x9A\x84" // 138
#define COLOR_FG_AF5FAF "\xEF\x9A\x85" // 139
#define COLOR_FG_AF5FD7 "\xEF\x9A\x86" // 140
#define COLOR_FG_AF5FFF "\xEF\x9A\x87" // 141
#define COLOR_FG_AF8700 "\xEF\x9A\x88" // 142
#define COLOR_FG_AF875F "\xEF\x9A\x89" // 143
#define COLOR_FG_AF8787 "\xEF\x9A\x8A" // 144
#define COLOR_FG_AF87AF "\xEF\x9A\x8B" // 145
#define COLOR_FG_AF87D7 "\xEF\x9A\x8C" // 146
#define COLOR_FG_AF87FF "\xEF\x9A\x8D" // 147
#define COLOR_FG_AFAF00 "\xEF\x9A\x8E" // 148
#define COLOR_FG_AFAF5F "\xEF\x9A\x8F" // 149
#define COLOR_FG_AFAF87 "\xEF\x9A\x90" // 150
#define COLOR_FG_AFAFAF "\xEF\x9A\x91" // 151
#define COLOR_FG_AFAFD7 "\xEF\x9A\x92" // 152
#define COLOR_FG_AFAFFF "\xEF\x9A\x93" // 153
#define COLOR_FG_AFD700 "\xEF\x9A\x94" // 154
#define COLOR_FG_AFD75F "\xEF\x9A\x95" // 155
#define COLOR_FG_AFD787 "\xEF\x9A\x96" // 156
#define COLOR_FG_AFD7AF "\xEF\x9A\x97" // 157
#define COLOR_FG_AFD7D7 "\xEF\x9A\x98" // 158
#define COLOR_FG_AFD7FF "\xEF\x9A\x99" // 159
#define COLOR_FG_AFFF00 "\xEF\x9A\x9A" // 160
#define COLOR_FG_AFFF5F "\xEF\x9A\x9B" // 161
#define COLOR_FG_AFFF87 "\xEF\x9A\x9C" // 162
#define COLOR_FG_AFFFAF "\xEF\x9A\x9D" // 163
#define COLOR_FG_AFFFD7 "\xEF\x9A\x9E" // 164
#define COLOR_FG_AFFFFF "\xEF\x9A\x9F" // 165
#define COLOR_FG_D70000 "\xEF\x9A\xA0" // 166
#define COLOR_FG_D7005F "\xEF\x9A\xA1" // 167
#define COLOR_FG_D70087 "\xEF\x9A\xA2" // 168
#define COLOR_FG_D700AF "\xEF\x9A\xA3" // 169
#define COLOR_FG_D700D7 "\xEF\x9A\xA4" // 170
#define COLOR_FG_D700FF "\xEF\x9A\xA5" // 171
#define COLOR_FG_D75F00 "\xEF\x9A\xA6" // 172
#define COLOR_FG_D75F5F "\xEF\x9A\xA7" // 173
#define COLOR_FG_D75F87 "\xEF\x9A\xA8" // 174
#define COLOR_FG_D75FAF "\xEF\x9A\xA9" // 175
#define COLOR_FG_D75FD7 "\xEF\x9A\xAA" // 176
#define COLOR_FG_D75FFF "\xEF\x9A\xAB" // 177
#define COLOR_FG_D78700 "\xEF\x9A\xAC" // 178
#define COLOR_FG_D7875A "\xEF\x9A\xAD" // 179
#define COLOR_FG_D78787 "\xEF\x9A\xAE" // 180
#define COLOR_FG_D787AF "\xEF\x9A\xAF" // 181
#define COLOR_FG_D787D7 "\xEF\x9A\xB0" // 182
#define COLOR_FG_D787FF "\xEF\x9A\xB1" // 183
#define COLOR_FG_D7AF00 "\xEF\x9A\xB2" // 184
#define COLOR_FG_D7AF5A "\xEF\x9A\xB3" // 185
#define COLOR_FG_D7AF87 "\xEF\x9A\xB4" // 186
#define COLOR_FG_D7AFAF "\xEF\x9A\xB5" // 187
#define COLOR_FG_D7AFD7 "\xEF\x9A\xB6" // 188
#define COLOR_FG_D7AFFF "\xEF\x9A\xB7" // 189
#define COLOR_FG_D7D700 "\xEF\x9A\xB8" // 190
#define COLOR_FG_D7D75F "\xEF\x9A\xB9" // 191
#define COLOR_FG_D7D787 "\xEF\x9A\xBA" // 192
#define COLOR_FG_D7D7AF "\xEF\x9A\xBB" // 193
#define COLOR_FG_D7D7D7 "\xEF\x9A\xBC" // 194
#define COLOR_FG_D7D7FF "\xEF\x9A\xBD" // 195
#define COLOR_FG_D7FF00 "\xEF\x9A\xBE" // 196
#define COLOR_FG_D7FF5F "\xEF\x9A\xBF" // 197
#define COLOR_FG_D7FF87 "\xEF\x9B\x80" // 198
#define COLOR_FG_D7FFAF "\xEF\x9B\x81" // 199
#define COLOR_FG_D7FFD7 "\xEF\x9B\x82" // 200
#define COLOR_FG_D7FFFF "\xEF\x9B\x83" // 201
#define COLOR_FG_FF0000 "\xEF\x9B\x84" // 202
#define COLOR_FG_FF005F "\xEF\x9B\x85" // 203
#define COLOR_FG_FF0087 "\xEF\x9B\x86" // 204
#define COLOR_FG_FF00AF "\xEF\x9B\x87" // 205
#define COLOR_FG_FF00D7 "\xEF\x9B\x88" // 206
#define COLOR_FG_FF00FF "\xEF\x9B\x89" // 207
#define COLOR_FG_FF5F00 "\xEF\x9B\x8A" // 208
#define COLOR_FG_FF5F5F "\xEF\x9B\x8B" // 209
#define COLOR_FG_FF5F87 "\xEF\x9B\x8C" // 210
#define COLOR_FG_FF5FAF "\xEF\x9B\x8D" // 211
#define COLOR_FG_FF5FD7 "\xEF\x9B\x8E" // 212
#define COLOR_FG_FF5FFF "\xEF\x9B\x8F" // 213
#define COLOR_FG_FF8700 "\xEF\x9B\x90" // 214
#define COLOR_FG_FF875F "\xEF\x9B\x91" // 215
#define COLOR_FG_FF8787 "\xEF\x9B\x92" // 216
#define COLOR_FG_FF87AF "\xEF\x9B\x93" // 217
#define COLOR_FG_FF87D7 "\xEF\x9B\x94" // 218
#define COLOR_FG_FF87FF "\xEF\x9B\x95" // 219
#define COLOR_FG_FFAF00 "\xEF\x9B\x96" // 220
#define COLOR_FG_FFAF5F "\xEF\x9B\x97" // 221
#define COLOR_FG_FFAF87 "\xEF\x9B\x98" // 222
#define COLOR_FG_FFAFAF "\xEF\x9B\x99" // 223
#define COLOR_FG_FFAFD7 "\xEF\x9B\x9A" // 224
#define COLOR_FG_FFAFFF "\xEF\x9B\x9B" // 225
#define COLOR_FG_FFD700 "\xEF\x9B\x9C" // 226
#define COLOR_FG_FFD75F "\xEF\x9B\x9D" // 227
#define COLOR_FG_FFD787 "\xEF\x9B\x9E" // 228
#define COLOR_FG_FFD7AF "\xEF\x9B\x9F" // 229
#define COLOR_FG_FFD7D7 "\xEF\x9B\xA0" // 230
#define COLOR_FG_FFD7FF "\xEF\x9B\xA1" // 231
#define COLOR_FG_FFFF00 "\xEF\x9B\xA2" // 232
#define COLOR_FG_FFFF5F "\xEF\x9B\xA3" // 233
#define COLOR_FG_FFFF87 "\xEF\x9B\xA4" // 234
#define COLOR_FG_FFFFAF "\xEF\x9B\xA5" // 235
#define COLOR_FG_FFFFD7 "\xEF\x9B\xA6" // 236
#define COLOR_FG_FFFFFF_2 "\xEF\x9B\xA7" // 237
#define COLOR_FG_080808 "\xEF\x9B\xA8" // 238
#define COLOR_FG_121212 "\xEF\x9B\xA9" // 239
#define COLOR_FG_1C1C1C "\xEF\x9B\xAA" // 240
#define COLOR_FG_262626 "\xEF\x9B\xAB" // 241
#define COLOR_FG_303030 "\xEF\x9B\xAC" // 242
#define COLOR_FG_3A3A3A "\xEF\x9B\xAD" // 243
#define COLOR_FG_444444 "\xEF\x9B\xAE" // 244
#define COLOR_FG_4E4E4E "\xEF\x9B\xAF" // 245
#define COLOR_FG_585858 "\xEF\x9B\xB0" // 246
#define COLOR_FG_626262 "\xEF\x9B\xB1" // 247
#define COLOR_FG_6C6C6C "\xEF\x9B\xB2" // 248
#define COLOR_FG_767676 "\xEF\x9B\xB3" // 249
#define COLOR_FG_808080 "\xEF\x9B\xB4" // 250
#define COLOR_FG_8A8A8A "\xEF\x9B\xB5" // 251
#define COLOR_FG_949494 "\xEF\x9B\xB6" // 252
#define COLOR_FG_9E9E9E "\xEF\x9B\xB7" // 253
#define COLOR_FG_A8A8A8 "\xEF\x9B\xB8" // 254
#define COLOR_FG_B2B2B2 "\xEF\x9B\xB9" // 255
#define COLOR_FG_BCBCBC "\xEF\x9B\xBA" // 256
#define COLOR_FG_C6C6C6 "\xEF\x9B\xBB" // 257
#define COLOR_FG_D0D0D0 "\xEF\x9B\xBC" // 258
#define COLOR_FG_DADADA "\xEF\x9B\xBD" // 259
#define COLOR_FG_E4E4E4 "\xEF\x9B\xBE" // 260
#define COLOR_FG_EEEEEE "\xEF\x9B\xBF" // 261
#define COLOR_BG_BLACK "\xEF\x9C\x80" // 262
#define COLOR_BG_RED "\xEF\x9C\x81" // 263
#define COLOR_BG_GREEN "\xEF\x9C\x82" // 264
#define COLOR_BG_YELLOW "\xEF\x9C\x83" // 265
#define COLOR_BG_BLUE "\xEF\x9C\x84" // 266
#define COLOR_BG_MAGENTA "\xEF\x9C\x85" // 267
#define COLOR_BG_CYAN "\xEF\x9C\x86" // 268
#define COLOR_BG_WHITE "\xEF\x9C\x87" // 269
#define COLOR_BG_555555 "\xEF\x9C\x88" // 270
#define COLOR_BG_FF5555 "\xEF\x9C\x89" // 271
#define COLOR_BG_55FF55 "\xEF\x9C\x8A" // 272
#define COLOR_BG_FFFF55 "\xEF\x9C\x8B" // 273
#define COLOR_BG_5555FF "\xEF\x9C\x8C" // 274
#define COLOR_BG_FF55FF "\xEF\x9C\x8D" // 275
#define COLOR_BG_55FFFF "\xEF\x9C\x8E" // 276
#define COLOR_BG_FFFFFF_1 "\xEF\x9C\x8F" // 277
#define COLOR_BG_000000 "\xEF\x9C\x90" // 278
#define COLOR_BG_00005F "\xEF\x9C\x91" // 279
#define COLOR_BG_000087 "\xEF\x9C\x92" // 280
#define COLOR_BG_0000AF "\xEF\x9C\x93" // 281
#define COLOR_BG_0000D7 "\xEF\x9C\x94" // 282
#define COLOR_BG_0000FF "\xEF\x9C\x95" // 283
#define COLOR_BG_005F00 "\xEF\x9C\x96" // 284
#define COLOR_BG_005F5F "\xEF\x9C\x97" // 285
#define COLOR_BG_005F87 "\xEF\x9C\x98" // 286
#define COLOR_BG_005FAF "\xEF\x9C\x99" // 287
#define COLOR_BG_005FD7 "\xEF\x9C\x9A" // 288
#define COLOR_BG_005FFF "\xEF\x9C\x9B" // 289
#define COLOR_BG_008700 "\xEF\x9C\x9C" // 290
#define COLOR_BG_00875F "\xEF\x9C\x9D" // 291
#define COLOR_BG_008785 "\xEF\x9C\x9E" // 292
#define COLOR_BG_0087AF "\xEF\x9C\x9F" // 293
#define COLOR_BG_0087D7 "\xEF\x9C\xA0" // 294
#define COLOR_BG_0087FF "\xEF\x9C\xA1" // 295
#define COLOR_BG_00AF00 "\xEF\x9C\xA2" // 296
#define COLOR_BG_00AF5F "\xEF\x9C\xA3" // 297
#define COLOR_BG_00AF87 "\xEF\x9C\xA4" // 298
#define COLOR_BG_00AFAF "\xEF\x9C\xA5" // 299
#define COLOR_BG_00AFD7 "\xEF\x9C\xA6" // 300
#define COLOR_BG_00AFFF "\xEF\x9C\xA7" // 301
#define COLOR_BG_00D700 "\xEF\x9C\xA8" // 302
#define COLOR_BG_00D75F "\xEF\x9C\xA9" // 303
#define COLOR_BG_00D787 "\xEF\x9C\xAA" // 304
#define COLOR_BG_00D7AF "\xEF\x9C\xAB" // 305
#define COLOR_BG_00D7D7 "\xEF\x9C\xAC" // 306
#define COLOR_BG_00D7FF "\xEF\x9C\xAD" // 307
#define COLOR_BG_00FF00 "\xEF\x9C\xAE" // 308
#define COLOR_BG_00FF5A "\xEF\x9C\xAF" // 309
#define COLOR_BG_00FF87 "\xEF\x9C\xB0" // 310
#define COLOR_BG_00FFAF "\xEF\x9C\xB1" // 311
#define COLOR_BG_00FFD7 "\xEF\x9C\xB2" // 312
#define COLOR_BG_00FFFF "\xEF\x9C\xB3" // 313
#define COLOR_BG_5F0000 "\xEF\x9C\xB4" // 314
#define COLOR_BG_5F005F "\xEF\x9C\xB5" // 315
#define COLOR_BG_5F0087 "\xEF\x9C\xB6" // 316
#define COLOR_BG_5F00AF "\xEF\x9C\xB7" // 317
#define COLOR_BG_5F00D7 "\xEF\x9C\xB8" // 318
#define COLOR_BG_5F00FF "\xEF\x9C\xB9" // 319
#define COLOR_BG_5F5F00 "\xEF\x9C\xBA" // 320
#define COLOR_BG_5F5F5F "\xEF\x9C\xBB" // 321
#define COLOR_BG_5F5F87 "\xEF\x9C\xBC" // 322
#define COLOR_BG_5F5FAF "\xEF\x9C\xBD" // 323
#define COLOR_BG_5F5FD7 "\xEF\x9C\xBE" // 324
#define COLOR_BG_5F5FFF "\xEF\x9C\xBF" // 325
#define COLOR_BG_5F8700 "\xEF\x9D\x80" // 326
#define COLOR_BG_5F875F "\xEF\x9D\x81" // 327
#define COLOR_BG_5F8787 "\xEF\x9D\x82" // 328
#define COLOR_BG_5F87AF "\xEF\x9D\x83" // 329
#define COLOR_BG_5F87D7 "\xEF\x9D\x84" // 330
#define COLOR_BG_5F87FF "\xEF\x9D\x85" // 331
#define COLOR_BG_5FAF00 "\xEF\x9D\x86" // 332
#define COLOR_BG_5FAF5F "\xEF\x9D\x87" // 333
#define COLOR_BG_5FAF87 "\xEF\x9D\x88" // 334
#define COLOR_BG_5FAFAF "\xEF\x9D\x89" // 335
#define COLOR_BG_5FAFD7 "\xEF\x9D\x8A" // 336
#define COLOR_BG_5FAFFF "\xEF\x9D\x8B" // 337
#define COLOR_BG_5FD700 "\xEF\x9D\x8C" // 338
#define COLOR_BG_5FD75F "\xEF\x9D\x8D" // 339
#define COLOR_BG_5FD787 "\xEF\x9D\x8E" // 340
#define COLOR_BG_5FD7AF "\xEF\x9D\x8F" // 341
#define COLOR_BG_5FD7D7 "\xEF\x9D\x90" // 342
#define COLOR_BG_5FD7FF "\xEF\x9D\x91" // 343
#define COLOR_BG_5FFF00 "\xEF\x9D\x92" // 344
#define COLOR_BG_5FFF5F "\xEF\x9D\x93" // 345
#define COLOR_BG_5FFF87 "\xEF\x9D\x94" // 346
#define COLOR_BG_5FFFAF "\xEF\x9D\x95" // 347
#define COLOR_BG_5FFFD7 "\xEF\x9D\x96" // 348
#define COLOR_BG_5FFFFF "\xEF\x9D\x97" // 349
#define COLOR_BG_870000 "\xEF\x9D\x98" // 350
#define COLOR_BG_87005F "\xEF\x9D\x99" // 351
#define COLOR_BG_870087 "\xEF\x9D\x9A" // 352
#define COLOR_BG_8700AF "\xEF\x9D\x9B" // 353
#define COLOR_BG_8700D7 "\xEF\x9D\x9C" // 354
#define COLOR_BG_8700FF "\xEF\x9D\x9D" // 355
#define COLOR_BG_875F00 "\xEF\x9D\x9E" // 356
#define COLOR_BG_875F5F "\xEF\x9D\x9F" // 357
#define COLOR_BG_875F87 "\xEF\x9D\xA0" // 358
#define COLOR_BG_875FAF "\xEF\x9D\xA1" // 359
#define COLOR_BG_875FD7 "\xEF\x9D\xA2" // 360
#define COLOR_BG_875FFF "\xEF\x9D\xA3" // 361
#define COLOR_BG_878700 "\xEF\x9D\xA4" // 362
#define COLOR_BG_87875F "\xEF\x9D\xA5" // 363
#define COLOR_BG_878787 "\xEF\x9D\xA6" // 364
#define COLOR_BG_8787AF "\xEF\x9D\xA7" // 365
#define COLOR_BG_8787D7 "\xEF\x9D\xA8" // 366
#define COLOR_BG_8787FF "\xEF\x9D\xA9" // 367
#define COLOR_BG_87AF00 "\xEF\x9D\xAA" // 368
#define COLOR_BG_87AF5F "\xEF\x9D\xAB" // 369
#define COLOR_BG_87AF87 "\xEF\x9D\xAC" // 370
#define COLOR_BG_87AFAF "\xEF\x9D\xAD" // 371
#define COLOR_BG_87AFD7 "\xEF\x9D\xAE" // 372
#define COLOR_BG_87AFFF "\xEF\x9D\xAF" // 373
#define COLOR_BG_87D700 "\xEF\x9D\xB0" // 374
#define COLOR_BG_87D75A "\xEF\x9D\xB1" // 375
#define COLOR_BG_87D787 "\xEF\x9D\xB2" // 376
#define COLOR_BG_87D7AF "\xEF\x9D\xB3" // 377
#define COLOR_BG_87D7D7 "\xEF\x9D\xB4" // 378
#define COLOR_BG_87D7FF "\xEF\x9D\xB5" // 379
#define COLOR_BG_87FF00 "\xEF\x9D\xB6" // 380
#define COLOR_BG_87FF5F "\xEF\x9D\xB7" // 381
#define COLOR_BG_87FF87 "\xEF\x9D\xB8" // 382
#define COLOR_BG_87FFAF "\xEF\x9D\xB9" // 383
#define COLOR_BG_87FFD7 "\xEF\x9D\xBA" // 384
#define COLOR_BG_87FFFF "\xEF\x9D\xBB" // 385
#define COLOR_BG_AF0000 "\xEF\x9D\xBC" // 386
#define COLOR_BG_AF005F "\xEF\x9D\xBD" // 387
#define COLOR_BG_AF0087 "\xEF\x9D\xBE" // 388
#define COLOR_BG_AF00AF "\xEF\x9D\xBF" // 389
#define COLOR_BG_AF00D7 "\xEF\x9E\x80" // 390
#define COLOR_BG_AF00FF "\xEF\x9E\x81" // 391
#define COLOR_BG_AF5F00 "\xEF\x9E\x82" // 392
#define COLOR_BG_AF5F5F "\xEF\x9E\x83" // 393
#define COLOR_BG_AF5F87 "\xEF\x9E\x84" // 394
#define COLOR_BG_AF5FAF "\xEF\x9E\x85" // 395
#define COLOR_BG_AF5FD7 "\xEF\x9E\x86" // 396
#define COLOR_BG_AF5FFF "\xEF\x9E\x87" // 397
#define COLOR_BG_AF8700 "\xEF\x9E\x88" // 398
#define COLOR_BG_AF875F "\xEF\x9E\x89" // 399
#define COLOR_BG_AF8787 "\xEF\x9E\x8A" // 400
#define COLOR_BG_AF87AF "\xEF\x9E\x8B" // 401
#define COLOR_BG_AF87D7 "\xEF\x9E\x8C" // 402
#define COLOR_BG_AF87FF "\xEF\x9E\x8D" // 403
#define COLOR_BG_AFAF00 "\xEF\x9E\x8E" // 404
#define COLOR_BG_AFAF5F "\xEF\x9E\x8F" // 405
#define COLOR_BG_AFAF87 "\xEF\x9E\x90" // 406
#define COLOR_BG_AFAFAF "\xEF\x9E\x91" // 407
#define COLOR_BG_AFAFD7 "\xEF\x9E\x92" // 408
#define COLOR_BG_AFAFFF "\xEF\x9E\x93" // 409
#define COLOR_BG_AFD700 "\xEF\x9E\x94" // 410
#define COLOR_BG_AFD75F "\xEF\x9E\x95" // 411
#define COLOR_BG_AFD787 "\xEF\x9E\x96" // 412
#define COLOR_BG_AFD7AF "\xEF\x9E\x97" // 413
#define COLOR_BG_AFD7D7 "\xEF\x9E\x98" // 414
#define COLOR_BG_AFD7FF "\xEF\x9E\x99" // 415
#define COLOR_BG_AFFF00 "\xEF\x9E\x9A" // 416
#define COLOR_BG_AFFF5F "\xEF\x9E\x9B" // 417
#define COLOR_BG_AFFF87 "\xEF\x9E\x9C" // 418
#define COLOR_BG_AFFFAF "\xEF\x9E\x9D" // 419
#define COLOR_BG_AFFFD7 "\xEF\x9E\x9E" // 420
#define COLOR_BG_AFFFFF "\xEF\x9E\x9F" // 421
#define COLOR_BG_D70000 "\xEF\x9E\xA0" // 422
#define COLOR_BG_D7005F "\xEF\x9E\xA1" // 423
#define COLOR_BG_D70087 "\xEF\x9E\xA2" // 424
#define COLOR_BG_D700AF "\xEF\x9E\xA3" // 425
#define COLOR_BG_D700D7 "\xEF\x9E\xA4" // 426
#define COLOR_BG_D700FF "\xEF\x9E\xA5" // 427
#define COLOR_BG_D75F00 "\xEF\x9E\xA6" // 428
#define COLOR_BG_D75F5F "\xEF\x9E\xA7" // 429
#define COLOR_BG_D75F87 "\xEF\x9E\xA8" // 430
#define COLOR_BG_D75FAF "\xEF\x9E\xA9" // 431
#define COLOR_BG_D75FD7 "\xEF\x9E\xAA" // 432
#define COLOR_BG_D75FFF "\xEF\x9E\xAB" // 433
#define COLOR_BG_D78700 "\xEF\x9E\xAC" // 434
#define COLOR_BG_D7875A "\xEF\x9E\xAD" // 435
#define COLOR_BG_D78787 "\xEF\x9E\xAE" // 436
#define COLOR_BG_D787AF "\xEF\x9E\xAF" // 437
#define COLOR_BG_D787D7 "\xEF\x9E\xB0" // 438
#define COLOR_BG_D787FF "\xEF\x9E\xB1" // 439
#define COLOR_BG_D7AF00 "\xEF\x9E\xB2" // 440
#define COLOR_BG_D7AF5A "\xEF\x9E\xB3" // 441
#define COLOR_BG_D7AF87 "\xEF\x9E\xB4" // 442
#define COLOR_BG_D7AFAF "\xEF\x9E\xB5" // 443
#define COLOR_BG_D7AFD7 "\xEF\x9E\xB6" // 444
#define COLOR_BG_D7AFFF "\xEF\x9E\xB7" // 445
#define COLOR_BG_D7D700 "\xEF\x9E\xB8" // 446
#define COLOR_BG_D7D75F "\xEF\x9E\xB9" // 447
#define COLOR_BG_D7D787 "\xEF\x9E\xBA" // 448
#define COLOR_BG_D7D7AF "\xEF\x9E\xBB" // 449
#define COLOR_BG_D7D7D7 "\xEF\x9E\xBC" // 450
#define COLOR_BG_D7D7FF "\xEF\x9E\xBD" // 451
#define COLOR_BG_D7FF00 "\xEF\x9E\xBE" // 452
#define COLOR_BG_D7FF5F "\xEF\x9E\xBF" // 453
#define COLOR_BG_D7FF87 "\xEF\x9F\x80" // 454
#define COLOR_BG_D7FFAF "\xEF\x9F\x81" // 455
#define COLOR_BG_D7FFD7 "\xEF\x9F\x82" // 456
#define COLOR_BG_D7FFFF "\xEF\x9F\x83" // 457
#define COLOR_BG_FF0000 "\xEF\x9F\x84" // 458
#define COLOR_BG_FF005F "\xEF\x9F\x85" // 459
#define COLOR_BG_FF0087 "\xEF\x9F\x86" // 460
#define COLOR_BG_FF00AF "\xEF\x9F\x87" // 461
#define COLOR_BG_FF00D7 "\xEF\x9F\x88" // 462
#define COLOR_BG_FF00FF "\xEF\x9F\x89" // 463
#define COLOR_BG_FF5F00 "\xEF\x9F\x8A" // 464
#define COLOR_BG_FF5F5F "\xEF\x9F\x8B" // 465
#define COLOR_BG_FF5F87 "\xEF\x9F\x8C" // 466
#define COLOR_BG_FF5FAF "\xEF\x9F\x8D" // 467
#define COLOR_BG_FF5FD7 "\xEF\x9F\x8E" // 468
#define COLOR_BG_FF5FFF "\xEF\x9F\x8F" // 469
#define COLOR_BG_FF8700 "\xEF\x9F\x90" // 470
#define COLOR_BG_FF875F "\xEF\x9F\x91" // 471
#define COLOR_BG_FF8787 "\xEF\x9F\x92" // 472
#define COLOR_BG_FF87AF "\xEF\x9F\x93" // 473
#define COLOR_BG_FF87D7 "\xEF\x9F\x94" // 474
#define COLOR_BG_FF87FF "\xEF\x9F\x95" // 475
#define COLOR_BG_FFAF00 "\xEF\x9F\x96" // 476
#define COLOR_BG_FFAF5F "\xEF\x9F\x97" // 477
#define COLOR_BG_FFAF87 "\xEF\x9F\x98" // 478
#define COLOR_BG_FFAFAF "\xEF\x9F\x99" // 479
#define COLOR_BG_FFAFD7 "\xEF\x9F\x9A" // 480
#define COLOR_BG_FFAFFF "\xEF\x9F\x9B" // 481
#define COLOR_BG_FFD700 "\xEF\x9F\x9C" // 482
#define COLOR_BG_FFD75F "\xEF\x9F\x9D" // 483
#define COLOR_BG_FFD787 "\xEF\x9F\x9E" // 484
#define COLOR_BG_FFD7AF "\xEF\x9F\x9F" // 485
#define COLOR_BG_FFD7D7 "\xEF\x9F\xA0" // 486
#define COLOR_BG_FFD7FF "\xEF\x9F\xA1" // 487
#define COLOR_BG_FFFF00 "\xEF\x9F\xA2" // 488
#define COLOR_BG_FFFF5F "\xEF\x9F\xA3" // 489
#define COLOR_BG_FFFF87 "\xEF\x9F\xA4" // 490
#define COLOR_BG_FFFFAF "\xEF\x9F\xA5" // 491
#define COLOR_BG_FFFFD7 "\xEF\x9F\xA6" // 492
#define COLOR_BG_FFFFFF_2 "\xEF\x9F\xA7" // 493
#define COLOR_BG_080808 "\xEF\x9F\xA8" // 494
#define COLOR_BG_121212 "\xEF\x9F\xA9" // 495
#define COLOR_BG_1C1C1C "\xEF\x9F\xAA" // 496
#define COLOR_BG_262626 "\xEF\x9F\xAB" // 497
#define COLOR_BG_303030 "\xEF\x9F\xAC" // 498
#define COLOR_BG_3A3A3A "\xEF\x9F\xAD" // 499
#define COLOR_BG_444444 "\xEF\x9F\xAE" // 500
#define COLOR_BG_4E4E4E "\xEF\x9F\xAF" // 501
#define COLOR_BG_585858 "\xEF\x9F\xB0" // 502
#define COLOR_BG_626262 "\xEF\x9F\xB1" // 503
#define COLOR_BG_6C6C6C "\xEF\x9F\xB2" // 504
#define COLOR_BG_767676 "\xEF\x9F\xB3" // 505
#define COLOR_BG_808080 "\xEF\x9F\xB4" // 506
#define COLOR_BG_8A8A8A "\xEF\x9F\xB5" // 507
#define COLOR_BG_949494 "\xEF\x9F\xB6" // 508
#define COLOR_BG_9E9E9E "\xEF\x9F\xB7" // 509
#define COLOR_BG_A8A8A8 "\xEF\x9F\xB8" // 510
#define COLOR_BG_B2B2B2 "\xEF\x9F\xB9" // 511
#define COLOR_BG_BCBCBC "\xEF\x9F\xBA" // 512
#define COLOR_BG_C6C6C6 "\xEF\x9F\xBB" // 513
#define COLOR_BG_D0D0D0 "\xEF\x9F\xBC" // 514
#define COLOR_BG_DADADA "\xEF\x9F\xBD" // 515
#define COLOR_BG_E4E4E4 "\xEF\x9F\xBE" // 516
#define COLOR_BG_EEEEEE "\xEF\x9F\xBF" // 517
#define COLOR_INDEX_FG_WHITE (COLOR_INDEX_FG + COLOR_INDEX_WHITE)
typedef struct
{
ColorState cs;
ColorState csMask;
const char pAnsi[12];
size_t nAnsi;
const UTF8 *pUTF;
size_t nUTF;
const UTF8 *pEscape;
size_t nEscape;
} MUX_COLOR_SET;
extern LIBMUX_API const MUX_COLOR_SET aColors[];
typedef struct
{
int r;
int g;
int b;
} RGB;
typedef struct
{
int L; // L* scaled by 100
int a; // a* scaled by 100
int b; // b* scaled by 100
} LABi;
typedef struct
{
RGB rgb;
LABi labi;
int child[2];
int color8;
int color16;
} PALETTE_ENTRY;
extern LIBMUX_API PALETTE_ENTRY palette[];
extern LIBMUX_API const unsigned int ColorTable[256];
LIBMUX_API bool parse_rgb(size_t n, const UTF8 *p, RGB &rgb);
LIBMUX_API int FindNearestPaletteEntry(RGB &rgb, bool fColor256);
LIBMUX_API UTF8 *LettersToBinary(const UTF8 *pLetters);
LIBMUX_API UTF8 *convert_to_html(const UTF8 *pString);
LIBMUX_API UTF8 *convert_color(const UTF8 *pString, bool fNoBleed, bool fColor256);
LIBMUX_API UTF8 *strip_color(const UTF8 *pString, size_t *pnLength = 0, size_t *pnPoints = 0);
LIBMUX_API UTF8 *munge_space(const UTF8 *);
LIBMUX_API UTF8 *trim_spaces(const UTF8 *);
LIBMUX_API UTF8 *grabto(UTF8 **, UTF8);
LIBMUX_API int string_compare(const UTF8 *, const UTF8 *);
LIBMUX_API int string_prefix(const UTF8 *, const UTF8 *);
LIBMUX_API const UTF8 *string_match(const UTF8 *, const UTF8 *);
LIBMUX_API UTF8 *replace_string(const UTF8 *, const UTF8 *, const UTF8 *);
LIBMUX_API bool minmatch(const UTF8 *str, const UTF8 *target, int min);
LIBMUX_API UTF8 *StringCloneLen(const UTF8 *str, size_t nStr);
LIBMUX_API UTF8 *StringClone(const UTF8 *str);
LIBMUX_API void safe_copy_str(const UTF8 *src, UTF8 *buff, UTF8 **bufp, size_t nSizeOfBuffer);
LIBMUX_API void safe_copy_str_lbuf(const UTF8 *src, UTF8 *buff, UTF8 **bufp);
LIBMUX_API size_t safe_copy_buf(const UTF8 *src, size_t nLen, UTF8 *buff, UTF8 **bufp);
LIBMUX_API size_t safe_fill(UTF8 *buff, UTF8 **bufc, UTF8 chFile, size_t nSpaces);
LIBMUX_API void safe_chr_utf8(const UTF8 *src, UTF8 *buff, UTF8 **bufp);
#define utf8_safe_chr safe_chr_utf8
LIBMUX_API UTF8 *ConvertToUTF8(UTF32 ch);
LIBMUX_API UTF8 *ConvertToUTF8(const char *p, size_t *pn);
LIBMUX_API UTF16 *ConvertToUTF16(UTF32 ch);
LIBMUX_API UTF32 ConvertFromUTF8(const UTF8 *p);
LIBMUX_API size_t ConvertFromUTF16(UTF16 *pString, UTF32 &ch);
LIBMUX_API UTF16 *ConvertFromUTF8ToUTF16(const UTF8 *pString, size_t& length);
LIBMUX_API UTF8 *ConvertFromUTF16ToUTF8(const UTF16 *pSTring);
LIBMUX_API void mux_strncpy(UTF8 *dest, const UTF8 *src, size_t length_to_copy);
LIBMUX_API bool matches_exit_from_list(const UTF8 *, const UTF8 *);
LIBMUX_API UTF8 *translate_string(const UTF8 *, bool);
LIBMUX_API bool IsDecompFriendly(const UTF8 *pString);
LIBMUX_API int mux_stricmp(const UTF8 *a, const UTF8 *b);
LIBMUX_API int mux_memicmp(const void *p1_arg, const void *p2_arg, size_t n);
LIBMUX_API UTF8 *mux_strlwr(const UTF8 *a, size_t &n);
LIBMUX_API UTF8 *mux_strupr(const UTF8 *a, size_t &n);
LIBMUX_API void mux_toupper_first(UTF8 *buff, UTF8 **bufc, size_t nBufferTotal);
LIBMUX_API UTF8 *mux_foldmatch(const UTF8 *a, size_t &n, bool &fChanged);
typedef struct tag_itl
{
bool bFirst;
char chPrefix;
char chSep;
UTF8 *buff;
UTF8 **bufc;
size_t nBufferAvailable;
} ITL;
LIBMUX_API void ItemToList_Init(ITL *pContext, UTF8 *arg_buff, UTF8 **arg_bufc,
UTF8 arg_chPrefix = 0, UTF8 arg_chSep = ' ');
LIBMUX_API bool ItemToList_AddInteger(ITL *pContext, int i);
LIBMUX_API bool ItemToList_AddInteger64(ITL *pContext, int64_t i);
LIBMUX_API bool ItemToList_AddString(ITL *pContext, const UTF8 *pStr);
LIBMUX_API bool ItemToList_AddStringLEN(ITL *pContext, size_t nStr, const UTF8 *pStr);
LIBMUX_API void ItemToList_Final(ITL *pContext);
LIBMUX_API size_t DCL_CDECL mux_vsnprintf(UTF8 *pBuffer, size_t nBuffer, const UTF8 *pFmt, va_list va);
LIBMUX_API void DCL_CDECL mux_sprintf(UTF8 *buff, size_t count, const UTF8 *fmt, ...);
LIBMUX_API size_t DCL_CDECL mux_snprintf(UTF8 *buff, size_t count, const UTF8 *fmt, ...);
LIBMUX_API void DCL_CDECL mux_fprintf(FILE *fp, const UTF8 *fmt, ...);
LIBMUX_API size_t GetLineTrunc(UTF8 *Buffer, size_t nBuffer, FILE *fp);
typedef struct
{
size_t m_d[256];
size_t m_skip2;
} BMH_State;
extern LIBMUX_API void BMH_Prepare(BMH_State *bmhs, size_t nPat, const UTF8 *pPat);
extern LIBMUX_API bool BMH_Execute(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc);
extern LIBMUX_API bool BMH_StringSearch(size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc);
extern LIBMUX_API void BMH_PrepareI(BMH_State *bmhs, size_t nPat, const UTF8 *pPat);
extern LIBMUX_API bool BMH_ExecuteI(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc);
extern LIBMUX_API bool BMH_StringSearchI(size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc);
class mux_field
{
public:
LBUF_OFFSET m_byte;
LBUF_OFFSET m_column;
inline mux_field(size_t byte = 0, size_t column = 0)
{
m_byte = static_cast<LBUF_OFFSET>(byte);
m_column = static_cast<LBUF_OFFSET>(column);
};
inline void operator =(const mux_field &c)
{
m_byte = c.m_byte;
m_column = c.m_column;
};
inline void operator ()(size_t byte, size_t column)
{
m_byte = static_cast<LBUF_OFFSET>(byte);
m_column = static_cast<LBUF_OFFSET>(column);
};
inline bool operator <(const mux_field &a) const
{
return ( m_byte < a.m_byte
&& m_column < a.m_column);
};
inline bool operator <=(const mux_field &a) const
{
return ( m_byte <= a.m_byte
&& m_column <= a.m_column);
};
inline bool operator ==(const mux_field &a) const
{
return (m_byte == a.m_byte) && (m_column == a.m_column);
};
inline bool operator !=(const mux_field &a) const
{
return (m_byte != a.m_byte) || (m_column != a.m_column);
};
inline mux_field operator -(const mux_field &a) const
{
mux_field b;
if ( a.m_byte < m_byte
&& a.m_column < m_column)
{
b.m_byte = m_byte - a.m_byte;
b.m_column = m_column - a.m_column;
}
else
{
b.m_byte = 0;
b.m_column = 0;
}
return b;
};
inline mux_field operator +(const mux_field &a) const
{
mux_field b;
b.m_byte = m_byte + a.m_byte;
b.m_column = m_column + a.m_column;
return b;
};
inline void operator +=(const mux_field &a)
{
m_byte = m_byte + a.m_byte;
m_column = m_column + a.m_column;
};
inline void operator -=(const mux_field &a)
{
if ( a.m_byte < m_byte
&& a.m_column < m_column)
{
m_byte = m_byte - a.m_byte;
m_column = m_column - a.m_column;
}
else
{
m_byte = 0;
m_column = 0;
}
};
};
// Cursor for tracking byte/code-point positions in UTF-8 strings.
// Used by utf8_next_grapheme() and related grapheme cluster functions.
//
class mux_cursor
{
public:
LBUF_OFFSET m_byte;
LBUF_OFFSET m_point;
inline mux_cursor(size_t byte = 0, size_t point = 0)
{
m_byte = static_cast<LBUF_OFFSET>(byte);
m_point = static_cast<LBUF_OFFSET>(point);
};
inline void operator =(const mux_cursor &c)
{
m_byte = c.m_byte;
m_point = c.m_point;
};
inline void operator ()(size_t byte, size_t point)
{
m_byte = static_cast<LBUF_OFFSET>(byte);
m_point = static_cast<LBUF_OFFSET>(point);
};
inline bool operator <(const mux_cursor &a) const
{
return ( m_byte < a.m_byte
&& m_point < a.m_point);
};
inline bool operator <=(const mux_cursor &a) const
{
return ( m_byte <= a.m_byte
&& m_point <= a.m_point);
};
inline bool operator ==(const mux_cursor &a) const
{
return (m_byte == a.m_byte) && (m_point == a.m_point);
};
inline bool operator !=(const mux_cursor &a) const
{
return (m_byte != a.m_byte) || (m_point != a.m_point);
};
inline mux_cursor operator -(const mux_cursor &a) const
{
mux_cursor b;
if ( a.m_byte < m_byte
&& a.m_point < m_point)
{
b.m_byte = m_byte - a.m_byte;
b.m_point = m_point - a.m_point;
}
else
{
b.m_byte = 0;
b.m_point = 0;
}
return b;
};
inline mux_cursor operator +(const mux_cursor &a) const
{
mux_cursor b;
b.m_byte = m_byte + a.m_byte;
b.m_point = m_point + a.m_point;
return b;
};
inline void operator +=(const mux_cursor &a)
{
m_byte = m_byte + a.m_byte;
m_point = m_point + a.m_point;
};
inline void operator -=(const mux_cursor &a)
{
if ( a.m_byte < m_byte
&& a.m_point < m_point)
{
m_byte = m_byte - a.m_byte;
m_point = m_point - a.m_point;
}
else
{
m_byte = 0;
m_point = 0;
}
};
};
static const mux_field fldAscii(1, 1);
static const mux_field fldMin(0, 0);
LIBMUX_API bool utf8_strlen(const UTF8 *pString, mux_cursor &nString);
// utf8_grapheme.cpp — Extended Grapheme Cluster segmentation (UAX #29).
//
LIBMUX_API mux_cursor utf8_next_grapheme(const UTF8 *src, size_t nSrc);
LIBMUX_API size_t utf8_cluster_count(const UTF8 *src, size_t nSrc);
LIBMUX_API size_t utf8_clusters_before(const UTF8 *src, size_t nSrc, size_t nBefore);
LIBMUX_API mux_field StripTabsAndTruncate(const UTF8 *pString, UTF8 *pBuffer,
size_t nLength, size_t nWidth);
LIBMUX_API mux_field PadField(UTF8 *pBuffer, size_t nMaxBytes, LBUF_OFFSET nMinWidth,
mux_field fldOutput = fldMin);
LIBMUX_API size_t TruncateToBuffer(const UTF8 *pString, UTF8 *pBuffer, size_t nBuffer);
// String buffers are LBUF_SIZE, so maximum string length is LBUF_SIZE-1.
// That means the longest possible list can consist of LBUF_SIZE-1 copies
// of the delimiter, making for LBUF_SIZE words in the list.
//
#define MAX_WORDS LBUF_SIZE
inline int mux_min(int x, int y)
{
if (x < y) return x;
else return y;
}
LIBMUX_API void strip_fancy_quotes(UTF8 *str);
LIBMUX_API UTF8 *find_pattern_delimiter(UTF8 *str);
LIBMUX_API void unescape_pattern_colons(UTF8 *str);
// Formatted string utilities.
//
DCL_EXPORT UTF8 * DCL_CDECL tprintf(const UTF8 *, ...);
LIBMUX_API void DCL_CDECL safe_tprintf_str(UTF8 *, UTF8 **, const UTF8 *, ...);
// Server-layer globals mirrored from mudconf/mudstate so that
// stringutil.cpp can be compiled with core.h alone.
//
extern LIBMUX_API bool g_no_flash; // mudconf.no_flash
extern LIBMUX_API bool g_space_compress; // mudstate.bStandAlone || mudconf.space_compress
LIBMUX_API size_t LeftJustifyString(UTF8 *field, size_t nWidth, const UTF8 *value);
LIBMUX_API size_t RightJustifyNumber(UTF8 *field, size_t nWidth, int64_t value, UTF8 chFill);
LIBMUX_API UTF8 *ConvertCRLFtoSpace(const UTF8 *pString);
#endif // STRINGUTIL_H