tinymux/mux/lib/stringutil.cpp
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

7712 lines
293 KiB
C++

/*! \file stringutil.cpp
* \brief String utility functions.
*
*/
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "core.h"
extern "C" {
#include "color_ops.h"
}
#include <math.h>
bool g_no_flash = false;
bool g_space_compress = true;
UTF8 *DCL_CDECL tprintf(const UTF8 *fmt,...)
{
static UTF8 buff[LBUF_SIZE];
va_list ap;
va_start(ap, fmt);
mux_vsnprintf(buff, LBUF_SIZE, fmt, ap);
va_end(ap);
return buff;
}
void DCL_CDECL safe_tprintf_str(UTF8 *str, UTF8 **bp, const UTF8 *fmt,...)
{
va_list ap;
va_start(ap, fmt);
size_t nAvailable = LBUF_SIZE - (*bp - str);
size_t len = mux_vsnprintf(*bp, static_cast<int>(nAvailable), fmt, ap);
va_end(ap);
*bp += len;
}
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
using namespace std;
const bool mux_isprint_ascii[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isprint_cp437[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, // 0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
};
const bool mux_isprint_latin1[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, // 8
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, // 9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
};
const bool mux_isprint_latin2[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
};
const bool mux_isdigit[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isxdigit[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isazAZ[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isalnum[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isupper_ascii[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_islower_ascii[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool mux_isspace[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
// Characters which should be escaped for the secure()
// function: '%$\[](){},;'.
//
const bool mux_issecure[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
// Characters which should be escaped for the escape()
// function: '%\[]{};,()^$'.
//
const bool mux_isescape[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const bool ANSI_TokenTerminatorTable[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const unsigned char mux_hex2dec[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 3
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const unsigned char mux_toupper_ascii[UCHAR_MAX+1] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 6
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF // F
};
const unsigned char mux_tolower_ascii[UCHAR_MAX+1] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 4
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF // F
};
// This will help decode UTF-8 sequences.
//
// 0xxxxxxx ==> 00000000-01111111 ==> 00-7F 1 byte sequence.
// 10xxxxxx ==> 10000000-10111111 ==> 80-BF continue
// 110xxxxx ==> 11000000-11011111 ==> C0-DF 2 byte sequence.
// 1110xxxx ==> 11100000-11101111 ==> E0-EF 3 byte sequence.
// 11110xxx ==> 11110000-11110111 ==> F0-F7 4 byte sequence.
// 11111000-11111111 illegal
//
// Also, RFC 3629 specifies that 0xC0, 0xC1, and 0xF5-0xFF never
// appear in a valid sequence.
//
// The first byte gives the length of a sequence (UTF8_SIZE1 - UTF8_SIZE4).
// Bytes in the middle of a sequence map to UTF8_CONTINUE. Bytes which should
// not appear map to UTF8_ILLEGAL.
//
extern "C" const unsigned char utf8_FirstByte[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 8
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 9
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // A
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // B
6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E
4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 // F
};
// Advance within a NUL-terminated UTF-8 string without stepping past '\0'.
// Invalid lead bytes are treated as single-byte units.
static size_t utf8_advance_nul(const UTF8 *p)
{
if (nullptr == p || '\0' == *p)
{
return 0;
}
size_t n = utf8_FirstByte[static_cast<unsigned char>(*p)];
if (n >= UTF8_CONTINUE)
{
n = UTF8_SIZE1;
}
for (size_t i = 1; i < n; i++)
{
if ('\0' == p[i] || UTF8_CONTINUE != utf8_FirstByte[p[i]])
{
return UTF8_SIZE1;
}
}
UTF32 cp = utf8_decode_raw(p, n);
if (!utf8_is_valid_scalar(cp, n))
{
return UTF8_SIZE1;
}
return n;
}
// Advance within a UTF-8 byte span with explicit remaining length.
// Invalid/truncated/illegal scalars are treated as single-byte units.
static size_t utf8_advance_bounded(const UTF8 *p, size_t nAvail)
{
if (nullptr == p || 0 == nAvail)
{
return 0;
}
size_t n = utf8_FirstByte[static_cast<unsigned char>(*p)];
if (n < 1 || n >= UTF8_CONTINUE || n > nAvail)
{
return UTF8_SIZE1;
}
for (size_t i = 1; i < n; i++)
{
if (UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(p[i])])
{
return UTF8_SIZE1;
}
}
UTF32 cp = utf8_decode_raw(p, n);
if (!utf8_is_valid_scalar(cp, n))
{
return UTF8_SIZE1;
}
return n;
}
// The following table maps cp437 characters to their corresponding
// UTF8 sequences.
//
const UTF8 *cp437_utf8[256] =
{
T("\xE2\x80\x87"), T("\xE2\x98\xBA"), T("\xE2\x98\xBB"), T("\xE2\x99\xA5"),
T("\xE2\x99\xA6"), T("\xE2\x99\xA3"), T("\xE2\x99\xA0"), T("\xE2\x80\xA2"),
T("\xE2\x97\x98"), T("\xE2\x97\x8B"), T("\xE2\x97\x99"), T("\xE2\x99\x82"),
T("\xE2\x99\x80"), T("\xE2\x99\xAA"), T("\xE2\x99\xAB"), T("\xE2\x98\xBC"),
T("\xE2\x96\xBA"), T("\xE2\x97\x84"), T("\xE2\x86\x95"), T("\xE2\x80\xBC"),
T("\xC2\xB6"), T("\xC2\xA7"), T("\xE2\x96\xAC"), T("\xE2\x86\xA8"),
T("\xE2\x86\x91"), T("\xE2\x86\x93"), T("\xE2\x86\x92"), T("\xE2\x86\x90"),
T("\xE2\x88\x9F"), T("\xE2\x86\x94"), T("\xE2\x96\xB2"), T("\xE2\x96\xBC"),
T("\x20"), T("\x21"), T("\x22"), T("\x23"),
T("\x24"), T("\x25"), T("\x26"), T("\x27"),
T("\x28"), T("\x29"), T("\x2A"), T("\x2B"),
T("\x2C"), T("\x2D"), T("\x2E"), T("\x2F"),
T("\x30"), T("\x31"), T("\x32"), T("\x33"),
T("\x34"), T("\x35"), T("\x36"), T("\x37"),
T("\x38"), T("\x39"), T("\x3A"), T("\x3B"),
T("\x3C"), T("\x3D"), T("\x3E"), T("\x3F"),
T("\x40"), T("\x41"), T("\x42"), T("\x43"),
T("\x44"), T("\x45"), T("\x46"), T("\x47"),
T("\x48"), T("\x49"), T("\x4A"), T("\x4B"),
T("\x4C"), T("\x4D"), T("\x4E"), T("\x4F"),
T("\x50"), T("\x51"), T("\x52"), T("\x53"),
T("\x54"), T("\x55"), T("\x56"), T("\x57"),
T("\x58"), T("\x59"), T("\x5A"), T("\x5B"),
T("\x5C"), T("\x5D"), T("\x5E"), T("\x5F"),
T("\x60"), T("\x61"), T("\x62"), T("\x63"),
T("\x64"), T("\x65"), T("\x66"), T("\x67"),
T("\x68"), T("\x69"), T("\x6A"), T("\x6B"),
T("\x6C"), T("\x6D"), T("\x6E"), T("\x6F"),
T("\x70"), T("\x71"), T("\x72"), T("\x73"),
T("\x74"), T("\x75"), T("\x76"), T("\x77"),
T("\x78"), T("\x79"), T("\x7A"), T("\x7B"),
T("\x7C"), T("\x7D"), T("\x7E"), T("\x7F"),
T("\xC3\x87"), T("\xC3\xBC"), T("\xC3\xA9"), T("\xC3\xA2"),
T("\xC3\xA4"), T("\xC3\xA0"), T("\xC3\xA5"), T("\xC3\xA7"),
T("\xC3\xAA"), T("\xC3\xAB"), T("\xC3\xA8"), T("\xC3\xAF"),
T("\xC3\xAE"), T("\xC3\xAC"), T("\xC3\x84"), T("\xC3\x85"),
T("\xC3\x89"), T("\xC3\xA6"), T("\xC3\x86"), T("\xC3\xB4"),
T("\xC3\xB6"), T("\xC3\xB2"), T("\xC3\xBB"), T("\xC3\xB9"),
T("\xC3\xBF"), T("\xC3\x96"), T("\xC3\x9C"), T("\xC2\xA2"),
T("\xC2\xA3"), T("\xC2\xA5"), T("\xE2\x82\xA7"), T("\xC6\x92"),
T("\xC3\xA1"), T("\xC3\xAD"), T("\xC3\xB3"), T("\xC3\xBA"),
T("\xC3\xB1"), T("\xC3\x91"), T("\xC2\xAA"), T("\xC2\xBA"),
T("\xC2\xBF"), T("\xE2\x8C\x90"), T("\xC2\xAC"), T("\xC2\xBD"),
T("\xC2\xBC"), T("\xC2\xA1"), T("\xC2\xAB"), T("\xC2\xBB"),
T("\xE2\x96\x91"), T("\xE2\x96\x92"), T("\xE2\x96\x93"), T("\xE2\x94\x82"),
T("\xE2\x94\xA4"), T("\xE2\x95\xA1"), T("\xE2\x95\xA2"), T("\xE2\x95\x96"),
T("\xE2\x95\x95"), T("\xE2\x95\xA3"), T("\xE2\x95\x91"), T("\xE2\x95\x97"),
T("\xE2\x95\x9D"), T("\xE2\x95\x9C"), T("\xE2\x95\x9B"), T("\xE2\x94\x90"),
T("\xE2\x94\x94"), T("\xE2\x94\xB4"), T("\xE2\x94\xAC"), T("\xE2\x94\x9C"),
T("\xE2\x94\x80"), T("\xE2\x94\xBC"), T("\xE2\x95\x9E"), T("\xE2\x95\x9F"),
T("\xE2\x95\x9A"), T("\xE2\x95\x94"), T("\xE2\x95\xA9"), T("\xE2\x95\xA6"),
T("\xE2\x95\xA0"), T("\xE2\x95\x90"), T("\xE2\x95\xAC"), T("\xE2\x95\xA7"),
T("\xE2\x95\xA8"), T("\xE2\x95\xA4"), T("\xE2\x95\xA5"), T("\xE2\x95\x99"),
T("\xE2\x95\x98"), T("\xE2\x95\x92"), T("\xE2\x95\x93"), T("\xE2\x95\xAB"),
T("\xE2\x95\xAA"), T("\xE2\x94\x98"), T("\xE2\x94\x8C"), T("\xE2\x96\x88"),
T("\xE2\x96\x84"), T("\xE2\x96\x8C"), T("\xE2\x96\x90"), T("\xE2\x96\x80"),
T("\xCE\xB1"), T("\xC3\x9F"), T("\xCE\x93"), T("\xCF\x80"),
T("\xCE\xA3"), T("\xCF\x83"), T("\xC2\xB5"), T("\xCF\x84"),
T("\xCE\xA6"), T("\xCE\x98"), T("\xCE\xA9"), T("\xCE\xB4"),
T("\xE2\x88\x9E"), T("\xCF\x86"), T("\xCE\xB5"), T("\xE2\x88\xA9"),
T("\xE2\x89\xA1"), T("\xC2\xB1"), T("\xE2\x89\xA5"), T("\xE2\x89\xA4"),
T("\xE2\x8C\xA0"), T("\xE2\x8C\xA1"), T("\xC3\xB7"), T("\xE2\x89\x88"),
T("\xC2\xB0"), T("\xE2\x88\x99"), T("\xC2\xB7"), T("\xE2\x88\x9A"),
T("\xE2\x81\xBF"), T("\xC2\xB2"), T("\xE2\x96\xA0"), T("\xC2\xA0"),
};
// The following table maps existing 8-bit characters to their corresponding
// UTF8 sequences.
//
const UTF8 *latin1_utf8[256] =
{
T(""), T("\x01"), T("\x02"), T("\x03"),
T("\x04"), T("\x05"), T("\x06"), T("\x07"),
T("\x08"), T("\x09"), T("\x0A"), T("\x0B"),
T("\x0C"), T("\x0D"), T("\x0E"), T("\x0F"),
T("\x10"), T("\x11"), T("\x12"), T("\x13"),
T("\x14"), T("\x15"), T("\x16"), T("\x17"),
T("\x18"), T("\x19"), T("\x1A"), T("\x1B"),
T("\x1C"), T("\x1D"), T("\x1E"), T("\x1F"),
T("\x20"), T("\x21"), T("\x22"), T("\x23"),
T("\x24"), T("\x25"), T("\x26"), T("\x27"),
T("\x28"), T("\x29"), T("\x2A"), T("\x2B"),
T("\x2C"), T("\x2D"), T("\x2E"), T("\x2F"),
T("\x30"), T("\x31"), T("\x32"), T("\x33"),
T("\x34"), T("\x35"), T("\x36"), T("\x37"),
T("\x38"), T("\x39"), T("\x3A"), T("\x3B"),
T("\x3C"), T("\x3D"), T("\x3E"), T("\x3F"),
T("\x40"), T("\x41"), T("\x42"), T("\x43"),
T("\x44"), T("\x45"), T("\x46"), T("\x47"),
T("\x48"), T("\x49"), T("\x4A"), T("\x4B"),
T("\x4C"), T("\x4D"), T("\x4E"), T("\x4F"),
T("\x50"), T("\x51"), T("\x52"), T("\x53"),
T("\x54"), T("\x55"), T("\x56"), T("\x57"),
T("\x58"), T("\x59"), T("\x5A"), T("\x5B"),
T("\x5C"), T("\x5D"), T("\x5E"), T("\x5F"),
T("\x60"), T("\x61"), T("\x62"), T("\x63"),
T("\x64"), T("\x65"), T("\x66"), T("\x67"),
T("\x68"), T("\x69"), T("\x6A"), T("\x6B"),
T("\x6C"), T("\x6D"), T("\x6E"), T("\x6F"),
T("\x70"), T("\x71"), T("\x72"), T("\x73"),
T("\x74"), T("\x75"), T("\x76"), T("\x77"),
T("\x78"), T("\x79"), T("\x7A"), T("\x7B"),
T("\x7C"), T("\x7D"), T("\x7E"), T("\x7F"),
T("\xE2\x82\xAC"), T("\xEF\xBF\xBD"), T("\xE2\x80\x9A"), T("\xC6\x92"),
T("\xE2\x80\x9E"), T("\xE2\x80\xA6"), T("\xE2\x80\xA0"), T("\xE2\x80\xA1"),
T("\xCB\x86"), T("\xE2\x80\xB0"), T("\xC5\xA0"), T("\xE2\x80\xB9"),
T("\xC5\x92"), T("\xEF\xBF\xBD"), T("\xC5\xBD"), T("\xEF\xBF\xBD"),
T("\xEF\xBF\xBD"), T("\xE2\x80\x98"), T("\xE2\x80\x99"), T("\xE2\x80\x9C"),
T("\xE2\x80\x9D"), T("\xE2\x80\xA2"), T("\xE2\x80\x93"), T("\xE2\x80\x94"),
T("\xCB\x9C"), T("\xE2\x84\xA2"), T("\xC5\xA1"), T("\xE2\x80\xBA"),
T("\xC5\x93"), T("\xEF\xBF\xBD"), T("\xC5\xBE"), T("\xC5\xB8"),
T("\xC2\xA0"), T("\xC2\xA1"), T("\xC2\xA2"), T("\xC2\xA3"),
T("\xC2\xA4"), T("\xC2\xA5"), T("\xC2\xA6"), T("\xC2\xA7"),
T("\xC2\xA8"), T("\xC2\xA9"), T("\xC2\xAA"), T("\xC2\xAB"),
T("\xC2\xAC"), T("\xC2\xAD"), T("\xC2\xAE"), T("\xC2\xAF"),
T("\xC2\xB0"), T("\xC2\xB1"), T("\xC2\xB2"), T("\xC2\xB3"),
T("\xC2\xB4"), T("\xC2\xB5"), T("\xC2\xB6"), T("\xC2\xB7"),
T("\xC2\xB8"), T("\xC2\xB9"), T("\xC2\xBA"), T("\xC2\xBB"),
T("\xC2\xBC"), T("\xC2\xBD"), T("\xC2\xBE"), T("\xC2\xBF"),
T("\xC3\x80"), T("\xC3\x81"), T("\xC3\x82"), T("\xC3\x83"),
T("\xC3\x84"), T("\xC3\x85"), T("\xC3\x86"), T("\xC3\x87"),
T("\xC3\x88"), T("\xC3\x89"), T("\xC3\x8A"), T("\xC3\x8B"),
T("\xC3\x8C"), T("\xC3\x8D"), T("\xC3\x8E"), T("\xC3\x8F"),
T("\xC3\x90"), T("\xC3\x91"), T("\xC3\x92"), T("\xC3\x93"),
T("\xC3\x94"), T("\xC3\x95"), T("\xC3\x96"), T("\xC3\x97"),
T("\xC3\x98"), T("\xC3\x99"), T("\xC3\x9A"), T("\xC3\x9B"),
T("\xC3\x9C"), T("\xC3\x9D"), T("\xC3\x9E"), T("\xC3\x9F"),
T("\xC3\xA0"), T("\xC3\xA1"), T("\xC3\xA2"), T("\xC3\xA3"),
T("\xC3\xA4"), T("\xC3\xA5"), T("\xC3\xA6"), T("\xC3\xA7"),
T("\xC3\xA8"), T("\xC3\xA9"), T("\xC3\xAA"), T("\xC3\xAB"),
T("\xC3\xAC"), T("\xC3\xAD"), T("\xC3\xAE"), T("\xC3\xAF"),
T("\xC3\xB0"), T("\xC3\xB1"), T("\xC3\xB2"), T("\xC3\xB3"),
T("\xC3\xB4"), T("\xC3\xB5"), T("\xC3\xB6"), T("\xC3\xB7"),
T("\xC3\xB8"), T("\xC3\xB9"), T("\xC3\xBA"), T("\xC3\xBB"),
T("\xC3\xBC"), T("\xC3\xBD"), T("\xC3\xBE"), T("\xC3\xBF"),
};
// The following table maps latin2 characters to their corresponding
// UTF8 sequences.
//
const UTF8 *latin2_utf8[256] =
{
T(""), T("\x01"), T("\x02"), T("\x03"),
T("\x04"), T("\x05"), T("\x06"), T("\x07"),
T("\x08"), T("\x09"), T("\x0A"), T("\x0B"),
T("\x0C"), T("\x0D"), T("\x0E"), T("\x0F"),
T("\x10"), T("\x11"), T("\x12"), T("\x13"),
T("\x14"), T("\x15"), T("\x16"), T("\x17"),
T("\x18"), T("\x19"), T("\x1A"), T("\x1B"),
T("\x1C"), T("\x1D"), T("\x1E"), T("\x1F"),
T("\x20"), T("\x21"), T("\x22"), T("\x23"),
T("\x24"), T("\x25"), T("\x26"), T("\x27"),
T("\x28"), T("\x29"), T("\x2A"), T("\x2B"),
T("\x2C"), T("\x2D"), T("\x2E"), T("\x2F"),
T("\x30"), T("\x31"), T("\x32"), T("\x33"),
T("\x34"), T("\x35"), T("\x36"), T("\x37"),
T("\x38"), T("\x39"), T("\x3A"), T("\x3B"),
T("\x3C"), T("\x3D"), T("\x3E"), T("\x3F"),
T("\x40"), T("\x41"), T("\x42"), T("\x43"),
T("\x44"), T("\x45"), T("\x46"), T("\x47"),
T("\x48"), T("\x49"), T("\x4A"), T("\x4B"),
T("\x4C"), T("\x4D"), T("\x4E"), T("\x4F"),
T("\x50"), T("\x51"), T("\x52"), T("\x53"),
T("\x54"), T("\x55"), T("\x56"), T("\x57"),
T("\x58"), T("\x59"), T("\x5A"), T("\x5B"),
T("\x5C"), T("\x5D"), T("\x5E"), T("\x5F"),
T("\x60"), T("\x61"), T("\x62"), T("\x63"),
T("\x64"), T("\x65"), T("\x66"), T("\x67"),
T("\x68"), T("\x69"), T("\x6A"), T("\x6B"),
T("\x6C"), T("\x6D"), T("\x6E"), T("\x6F"),
T("\x70"), T("\x71"), T("\x72"), T("\x73"),
T("\x74"), T("\x75"), T("\x76"), T("\x77"),
T("\x78"), T("\x79"), T("\x7A"), T("\x7B"),
T("\x7C"), T("\x7D"), T("\x7E"), T("\x7F"),
T("\xC2\x80"), T("\xC2\x81"), T("\xC2\x82"), T("\xC2\x83"),
T("\xC2\x84"), T("\xC2\x85"), T("\xC2\x86"), T("\xC2\x87"),
T("\xC2\x88"), T("\xC2\x89"), T("\xC2\x8A"), T("\xC2\x8B"),
T("\xC2\x8C"), T("\xC2\x8D"), T("\xC2\x8E"), T("\xC2\x8F"),
T("\xC2\x90"), T("\xC2\x91"), T("\xC2\x92"), T("\xC2\x93"),
T("\xC2\x94"), T("\xC2\x95"), T("\xC2\x96"), T("\xC2\x97"),
T("\xC2\x98"), T("\xC2\x99"), T("\xC2\x9A"), T("\xC2\x9B"),
T("\xC2\x9C"), T("\xC2\x9D"), T("\xC2\x9E"), T("\xC2\x9F"),
T("\xC2\xA0"), T("\xC4\x84"), T("\xCB\x98"), T("\xC5\x81"),
T("\xC2\xA4"), T("\xC4\xBD"), T("\xC5\x9A"), T("\xC2\xA7"),
T("\xC2\xA8"), T("\xC5\xA0"), T("\xC5\x9E"), T("\xC5\xA4"),
T("\xC5\xB9"), T("\xC2\xAD"), T("\xC5\xBD"), T("\xC5\xBB"),
T("\xC2\xB0"), T("\xC4\x85"), T("\xCB\x9B"), T("\xC5\x82"),
T("\xC2\xB4"), T("\xC4\xBE"), T("\xC5\x9B"), T("\xCB\x87"),
T("\xC2\xB8"), T("\xC5\xA1"), T("\xC5\x9F"), T("\xC5\xA5"),
T("\xC5\xBA"), T("\xCB\x9D"), T("\xC5\xBE"), T("\xC5\xBC"),
T("\xC5\x94"), T("\xC3\x81"), T("\xC3\x82"), T("\xC4\x82"),
T("\xC3\x84"), T("\xC4\xB9"), T("\xC4\x86"), T("\xC3\x87"),
T("\xC4\x8C"), T("\xC3\x89"), T("\xC4\x98"), T("\xC3\x8B"),
T("\xC4\x9A"), T("\xC3\x8D"), T("\xC3\x8E"), T("\xC4\x8E"),
T("\xC4\x90"), T("\xC5\x83"), T("\xC5\x87"), T("\xC3\x93"),
T("\xC3\x94"), T("\xC5\x90"), T("\xC3\x96"), T("\xC3\x97"),
T("\xC5\x98"), T("\xC5\xAE"), T("\xC3\x9A"), T("\xC5\xB0"),
T("\xC3\x9C"), T("\xC3\x9D"), T("\xC5\xA2"), T("\xC3\x9F"),
T("\xC5\x95"), T("\xC3\xA1"), T("\xC3\xA2"), T("\xC4\x83"),
T("\xC3\xA4"), T("\xC4\xBA"), T("\xC4\x87"), T("\xC3\xA7"),
T("\xC4\x8D"), T("\xC3\xA9"), T("\xC4\x99"), T("\xC3\xAB"),
T("\xC4\x9B"), T("\xC3\xAD"), T("\xC3\xAE"), T("\xC4\x8F"),
T("\xC4\x91"), T("\xC5\x84"), T("\xC5\x88"), T("\xC3\xB3"),
T("\xC3\xB4"), T("\xC5\x91"), T("\xC3\xB6"), T("\xC3\xB7"),
T("\xC5\x99"), T("\xC5\xAF"), T("\xC3\xBA"), T("\xC5\xB1"),
T("\xC3\xBC"), T("\xC3\xBD"), T("\xC5\xA3"), T("\xCB\x99"),
};
/*! \brief Validates UTF8 string and returns number of code points contained therein.
*
* \param pString UTF8 string.
* \param nString Resulting number of code points in pString.
* \return true for valid, false for invalid.
*/
bool utf8_strlen(const UTF8 *pString, size_t &nString)
{
nString = 0;
int i = 0;
while ('\0' != pString[i])
{
unsigned char t = utf8_FirstByte[pString[i]];
if (UTF8_CONTINUE <= t)
{
return false;
}
int j;
for (j = i + 1; j < i + t; j++)
{
if ( '\0' == pString[j]
|| UTF8_CONTINUE != utf8_FirstByte[pString[j]])
{
return false;
}
}
UTF32 cp = utf8_decode_raw(pString + i, t);
if (!utf8_is_valid_scalar(cp, t))
{
return false;
}
nString++;
i = i + t;
}
return true;
}
bool utf8_strlen(const UTF8 *pString, mux_cursor &nString)
{
LBUF_OFFSET nPoints = 0;
LBUF_OFFSET nBytes = 0;
while ('\0' != pString[nBytes])
{
unsigned char t = utf8_FirstByte[pString[nBytes]];
if (UTF8_CONTINUE <= t)
{
nString(nBytes, nPoints);
return false;
}
int j;
for (j = nBytes + 1; j < nBytes + t; j++)
{
if ( '\0' == pString[j]
|| UTF8_CONTINUE != utf8_FirstByte[pString[j]])
{
nString(nBytes, nPoints);
return false;
}
}
UTF32 cp = utf8_decode_raw(pString + nBytes, t);
if (!utf8_is_valid_scalar(cp, t))
{
nString(nBytes, nPoints);
return false;
}
nPoints++;
nBytes = nBytes + t;
}
nString(nBytes, nPoints);
return true;
}
/*! \brief Convert UTF8 to ASCII with '?' for all unsupported characters.
*
* \param pString UTF8 string.
* \return Equivalent string in ASCII codeset.
*/
const UTF8 *ConvertToAscii(const UTF8 *pString)
{
static UTF8 buffer[2*LBUF_SIZE];
UTF8 *q = buffer;
while ('\0' != *pString)
{
*q++ = static_cast<UTF8>(co_dfa_ascii(pString));
pString += utf8_advance_nul(pString);
}
*q = '\0';
return buffer;
}
/*! \brief Convert UTF8 to cp437 with '?' for all unsupported characters.
*
* \param pString UTF8 string.
* \return Equivalent string in latin1 codeset.
*/
const UTF8 *ConvertToCp437(const UTF8 *pString)
{
static UTF8 buffer[2*LBUF_SIZE];
UTF8 *q = buffer;
while ( '\0' != *pString
&& q < buffer + sizeof(buffer) - 1)
{
const UTF8 *p = pString;
int iState = TR_CP437_START_STATE;
do
{
UTF8 ch = *p++;
unsigned char iColumn = tr_cp437_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = tr_cp437_sot[iState];
for (;;)
{
int y = tr_cp437_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = tr_cp437_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_cp437_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < TR_CP437_ACCEPTING_STATES_START);
*q++ = static_cast<char>(iState - TR_CP437_ACCEPTING_STATES_START);
pString += utf8_advance_nul(pString);
}
*q = '\0';
return buffer;
}
/*! \brief Convert UTF8 to latin1 with '?' for all unsupported characters.
*
* \param pString UTF8 string.
* \return Equivalent string in latin1 codeset.
*/
const UTF8 *ConvertToLatin1(const UTF8 *pString)
{
static UTF8 buffer[2*LBUF_SIZE];
UTF8 *q = buffer;
while ( '\0' != *pString
&& q < buffer + sizeof(buffer) - 1)
{
const UTF8 *p = pString;
int iState = TR_LATIN1_START_STATE;
do
{
UTF8 ch = *p++;
unsigned char iColumn = tr_latin1_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = tr_latin1_sot[iState];
for (;;)
{
int y = tr_latin1_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = tr_latin1_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_latin1_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < TR_LATIN1_ACCEPTING_STATES_START);
*q++ = static_cast<char>(iState - TR_LATIN1_ACCEPTING_STATES_START);
pString += utf8_advance_nul(pString);
}
*q = '\0';
return buffer;
}
/*! \brief Convert UTF8 to latin2 with '?' for all unsupported characters.
*
* \param pString UTF8 string.
* \return Equivalent string in latin1 codeset.
*/
const UTF8 *ConvertToLatin2(const UTF8 *pString)
{
static UTF8 buffer[2*LBUF_SIZE];
UTF8 *q = buffer;
while ( '\0' != *pString
&& q < buffer + sizeof(buffer) - 1)
{
const UTF8 *p = pString;
int iState = TR_LATIN2_START_STATE;
do
{
UTF8 ch = *p++;
unsigned char iColumn = tr_latin2_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = tr_latin2_sot[iState];
for (;;)
{
int y = tr_latin2_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = tr_latin2_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_latin2_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < TR_LATIN2_ACCEPTING_STATES_START);
*q++ = static_cast<char>(iState - TR_LATIN2_ACCEPTING_STATES_START);
pString += utf8_advance_nul(pString);
}
*q = '\0';
return buffer;
}
/*! \brief Return ConsoleWidth property for single code point.
*
* \param pCodePoint UTF8 string.
* \return Width to allow in formatting.
*/
int ConsoleWidth(const UTF8 *pCodePoint)
{
const UTF8 *p = pCodePoint;
int iState = TR_WIDTHS_START_STATE;
do
{
unsigned char ch = *p++;
unsigned char iColumn = tr_widths_itt[static_cast<unsigned char>(ch)];
unsigned short iOffset = tr_widths_sot[iState];
for (;;)
{
int y = tr_widths_sbt[iOffset];
if (y < 128)
{
// RUN phrase.
//
if (iColumn < y)
{
iState = tr_widths_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_widths_sbt[iOffset+iColumn+1];
break;
}
else
{
iColumn = static_cast<unsigned char>(iColumn - y);
iOffset = static_cast<unsigned short>(iOffset + y + 1);
}
}
}
} while (iState < TR_WIDTHS_ACCEPTING_STATES_START);
return (iState - TR_WIDTHS_ACCEPTING_STATES_START);
}
// C-callable wrapper for use from color_ops.c (libmux.so internal).
//
extern "C" LIBMUX_API int co_console_width(const unsigned char *pCodePoint)
{
return ConsoleWidth(pCodePoint);
}
// ColorTable — maps ASCII characters to color index flags.
//
const unsigned int ColorTable[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F
// 0x40-0x47
0,
0,
COLOR_INDEX_BG + COLOR_INDEX_BLUE,
COLOR_INDEX_BG + COLOR_INDEX_CYAN,
0,
0,
0,
COLOR_INDEX_BG + COLOR_INDEX_GREEN,
// 0x48-0x4F
0,
0,
0,
0,
0,
COLOR_INDEX_BG + COLOR_INDEX_MAGENTA,
0,
0,
// 0x50-0x57
//
0,
0,
COLOR_INDEX_BG + COLOR_INDEX_RED,
0,
0,
0,
0,
COLOR_INDEX_BG + COLOR_INDEX_WHITE,
// 0x58-0x5F
//
COLOR_INDEX_BG + COLOR_INDEX_BLACK,
COLOR_INDEX_BG + COLOR_INDEX_YELLOW,
0,
0,
0,
0,
0,
0,
// 0x60-0x67
0,
0,
COLOR_INDEX_FG + COLOR_INDEX_BLUE,
COLOR_INDEX_FG + COLOR_INDEX_CYAN,
0,
0,
COLOR_INDEX_BLINK,
COLOR_INDEX_FG + COLOR_INDEX_GREEN,
// 0x68-0x6F
//
COLOR_INDEX_INTENSE,
COLOR_INDEX_INVERSE,
0,
0,
0,
COLOR_INDEX_FG + COLOR_INDEX_MAGENTA,
COLOR_INDEX_RESET,
0,
// 0x70-0x77
//
0,
0,
COLOR_INDEX_FG + COLOR_INDEX_RED,
0,
0,
COLOR_INDEX_UNDERLINE,
0,
COLOR_INDEX_FG + COLOR_INDEX_WHITE,
// 0x78-0x7F
//
COLOR_INDEX_FG + COLOR_INDEX_BLACK,
COLOR_INDEX_FG + COLOR_INDEX_YELLOW,
0,
0,
0,
0,
0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF
};
bool parse_rgb(size_t n, const UTF8 *p, RGB &rgb)
{
UTF8 ch;
if ( 7 == n
&& '#' == p[0])
{
// Look for RRGGBB in hexidecimal.
//
for (int i = 1; i < 7; i++)
{
ch = p[i];
if ( !('0' <= ch && ch <= '9')
&& !('a' <= ch && ch <= 'f')
&& !('A' <= ch && ch <= 'F'))
{
return false;
}
}
rgb.r = (mux_hex2dec(p[1]) << 4) | mux_hex2dec(p[2]);
rgb.g = (mux_hex2dec(p[3]) << 4) | mux_hex2dec(p[4]);
rgb.b = (mux_hex2dec(p[5]) << 4) | mux_hex2dec(p[6]);
return true;
}
int nSpaces = 0;
int nDigits = 0;
for (size_t i = 0; i < n; i++)
{
ch = p[i];
if (mux_isspace(ch))
{
if ( 3 < nDigits
|| 0 == nDigits
|| 1 < nSpaces)
{
return false;
}
if (0 == nSpaces)
{
rgb.r = mux_atoi64(p+i-nDigits);
if (rgb.r < 0 || 255 < rgb.r)
{
return false;
}
}
else
{
rgb.g = mux_atoi64(p+i-nDigits);
if (rgb.g < 0 || 255 < rgb.g)
{
return false;
}
}
nDigits = 0;
nSpaces++;
}
else if (!mux_isdigit(ch))
{
return false;
}
else
{
nDigits++;
}
}
if ( 3 < nDigits
|| 0 == nDigits
|| 2 != nSpaces)
{
return false;
}
rgb.b = mux_atoi64(p+n-nDigits-1);
if (rgb.b < 0 || 255 < rgb.b)
{
return false;
}
return true;
}
// sRGB to CIELAB conversion (D65 illuminant)
//
// Pipeline: sRGB (0-255) -> linear RGB (0-1) -> XYZ (D65) -> CIELAB
// Output is integer-scaled: L*100, a*100, b*100
//
static inline double srgb_to_linear(int c)
{
double v = c / 255.0;
return (v <= 0.04045) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
}
static inline double cie_f(double t)
{
return (t > 0.008856) ? cbrt(t) : 7.787 * t + 16.0 / 116.0;
}
inline void rgb2lab(RGB *rgb, LABi *labi)
{
double lr = srgb_to_linear(rgb->r);
double lg = srgb_to_linear(rgb->g);
double lb = srgb_to_linear(rgb->b);
double x = (lr * 0.4124564 + lg * 0.3575761 + lb * 0.1804375) / 0.95047;
double y = (lr * 0.2126729 + lg * 0.7151522 + lb * 0.0721750) / 1.00000;
double z = (lr * 0.0193339 + lg * 0.1191920 + lb * 0.9503041) / 1.08883;
double fx = cie_f(x), fy = cie_f(y), fz = cie_f(z);
double L = 116.0 * fy - 16.0;
double a = 500.0 * (fx - fy);
double b = 200.0 * (fy - fz);
labi->L = static_cast<int>(L * 100.0 + 0.5);
labi->a = static_cast<int>(a * 100.0 + (a >= 0 ? 0.5 : -0.5));
labi->b = static_cast<int>(b * 100.0 + (b >= 0 ? 0.5 : -0.5));
}
inline void cs2rgb(ColorState cs, RGB *rgb)
{
rgb->r = static_cast<int>((cs & 0xFF0000) >> 16);
rgb->g = static_cast<int>((cs & 0x00FF00) >> 8);
rgb->b = static_cast<int>((cs & 0x0000FF));
}
inline ColorState rgb2cs(RGB *rgb)
{
ColorState cs;
cs = (static_cast<ColorState>(rgb->r) << 16)
| (static_cast<ColorState>(rgb->g) << 8)
| (static_cast<ColorState>(rgb->b));
return cs;
}
// All 256 entries of the palette are included in this table, but the palette
// is divided into two non-overlapping trees -- one for when xterm is supported,
// and one for when it is not.
//
// Since elements 0 through 15 do not have dependable RGB vales, we usually
// avoid using them when we have xterm support. xterm uses the values below,
// but other clients do not, and these values are usually user-configurable.
// However, if we are forced to map to the 16-color palette, the 16-color tree
// is used.
//
#define PALETTE16_ROOT 2
#define PALETTE256_ROOT 72
#define PALETTE_SIZE (sizeof(palette)/sizeof(palette[0]))
PALETTE_ENTRY palette[] =
{
{ { 0, 0, 0 }, { 0, 0, 0 }, { 12, 8 }, 0, 0},
{ { 187, 0, 0 }, { 3884, 6344, 5323 }, { 0, 5 }, 1, 1},
{ { 0, 187, 0 }, { 6617, -6826, 6588 }, { 1, 11 }, 2, 2},
{ { 187, 187, 0 }, { 7361, -1707, 7483 }, { -1, -1 }, 3, 3},
{ { 0, 0, 187 }, { 2225, 6272, -8543 }, { -1, -1 }, 4, 4},
{ { 187, 0, 187 }, { 4445, 7781, -4818 }, { 13, 9 }, 5, 5},
{ { 0, 187, 187 }, { 6884, -3809, -1119 }, { 14, 10 }, 6, 6},
{ { 187, 187, 187 }, { 7588, 0, 0 }, { -1, -1 }, 7, 7},
{ { 85, 85, 85 }, { 3615, 0, 0 }, { -1, -1 }, 0, 8},
{ { 255, 85, 85 }, { 6027, 6421, 3655 }, { -1, -1 }, 1, 9},
{ { 85, 255, 85 }, { 8897, -7423, 6593 }, { -1, -1 }, 2, 10},
{ { 255, 255, 85 }, { 9741, -1942, 7731 }, { 6, 15 }, 3, 11},
{ { 85, 85, 255 }, { 4651, 5110, -8420 }, { 4, -1 }, 4, 12},
{ { 255, 85, 255 }, { 6573, 8258, -5221 }, { -1, -1 }, 5, 13},
{ { 85, 255, 255 }, { 9198, -4245, -1274 }, { -1, -1 }, 6, 14},
{ { 255, 255, 255 }, { 10000, 0, 0 }, { 7, 3 }, 7, 15},
{ { 0, 0, 0 }, { 0, 0, 0 }, { -1, -1 }, 0, 0},
{ { 0, 0, 95 }, { 746, 3839, -5234 }, { -1, -1 }, 4, 4},
{ { 0, 0, 135 }, { 1411, 4937, -6724 }, { 20, 54 }, 4, 4},
{ { 0, 0, 175 }, { 2042, 5971, -8133 }, { -1, -1 }, 4, 4},
{ { 0, 0, 215 }, { 2646, 6962, -9483 }, { 19, 55 }, 4, 4},
{ { 0, 0, 255 }, { 3230, 7919, -10786 }, { -1, -1 }, 4, 4},
{ { 0, 95, 0 }, { 3436, -4184, 4038 }, { -1, -1 }, 2, 2},
{ { 0, 95, 95 }, { 3600, -2335, -686 }, { 16, 24 }, 6, 8},
{ { 0, 95, 135 }, { 3772, -828, -2884 }, { -1, -1 }, 6, 8},
{ { 0, 95, 175 }, { 4004, 805, -4908 }, { -1, -1 }, 7, 8},
{ { 0, 95, 215 }, { 4290, 2423, -6767 }, { -1, -1 }, 4, 12},
{ { 0, 95, 255 }, { 4618, 3961, -8484 }, { 56, 170 }, 4, 12},
{ { 0, 135, 0 }, { 4867, -5373, 5185 }, { -1, -1 }, 2, 2},
{ { 0, 135, 95 }, { 4968, -4147, 1287 }, { 22, 65 }, 6, 6},
{ { 0, 135, 135 }, { 5078, -2998, -881 }, { -1, -1 }, 6, 6},
{ { 0, 135, 175 }, { 5231, -1609, -2967 }, { -1, -1 }, 6, 6},
{ { 0, 135, 215 }, { 5427, -98, -4935 }, { 31, 67 }, 7, 8},
{ { 0, 135, 255 }, { 5663, 1444, -6783 }, { -1, -1 }, 4, 12},
{ { 0, 175, 0 }, { 6222, -6498, 6272 }, { -1, -1 }, 2, 2},
{ { 0, 175, 95 }, { 6291, -5627, 3055 }, { 245, 70 }, 2, 2},
{ { 0, 175, 135 }, { 6368, -4753, 999 }, { -1, -1 }, 6, 6},
{ { 0, 175, 175 }, { 6477, -3626, -1066 }, { -1, -1 }, 6, 6},
{ { 0, 175, 215 }, { 6618, -2318, -3066 }, { -1, -1 }, 6, 6},
{ { 0, 175, 255 }, { 6793, -902, -4979 }, { -1, -1 }, 6, 6},
{ { 0, 215, 0 }, { 7520, -7577, 7313 }, { 77, 112 }, 2, 2},
{ { 0, 215, 95 }, { 7571, -6924, 4642 }, { -1, -1 }, 2, 2},
{ { 0, 215, 135 }, { 7628, -6244, 2736 }, { -1, -1 }, 2, 2},
{ { 0, 215, 175 }, { 7710, -5332, 741 }, { -1, -1 }, 6, 6},
{ { 0, 215, 215 }, { 7817, -4228, -1242 }, { 43, 80 }, 6, 6},
{ { 0, 215, 255 }, { 7951, -2980, -3174 }, { 38, 81 }, 6, 6},
{ { 0, 255, 0 }, { 8773, -8618, 8318 }, { -1, -1 }, 2, 10},
{ { 0, 255, 95 }, { 8813, -8108, 6078 }, { -1, -1 }, 2, 10},
{ { 0, 255, 135 }, { 8857, -7565, 4337 }, { 113, 155 }, 2, 10},
{ { 0, 255, 175 }, { 8921, -6819, 2441 }, { -1, -1 }, 2, 10},
{ { 0, 255, 215 }, { 9005, -5890, 505 }, { -1, -1 }, 6, 14},
{ { 0, 255, 255 }, { 9111, -4809, -1413 }, { 50, 86 }, 6, 14},
{ { 95, 0, 0 }, { 1762, 3888, 2721 }, { -1, -1 }, 1, 1},
{ { 95, 0, 95 }, { 2106, 4769, -2953 }, { -1, -1 }, 5, 5},
{ { 95, 0, 135 }, { 2427, 5511, -5011 }, { 17, 91 }, 5, 5},
{ { 95, 0, 175 }, { 2819, 6350, -6819 }, { -1, -1 }, 4, 4},
{ { 95, 0, 215 }, { 3257, 7228, -8450 }, { 18, 92 }, 4, 4},
{ { 95, 0, 255 }, { 3721, 8116, -9954 }, { 21, 93 }, 4, 4},
{ { 95, 95, 0 }, { 3893, -1046, 4587 }, { 29, 64 }, 3, 3},
{ { 95, 95, 95 }, { 4032, 0, 0 }, { 61, 101 }, 7, 8},
{ { 95, 95, 135 }, { 4179, 972, -2218 }, { 25, 26 }, 7, 8},
{ { 95, 95, 175 }, { 4382, 2136, -4283 }, { 236, 68 }, 5, 8},
{ { 95, 95, 215 }, { 4634, 3391, -6192 }, { 99, 134 }, 4, 12},
{ { 95, 95, 255 }, { 4930, 4665, -7961 }, { -1, -1 }, 4, 12},
{ { 95, 135, 0 }, { 5157, -3111, 5536 }, { 28, 100 }, 3, 3},
{ { 95, 135, 95 }, { 5249, -2237, 1719 }, { -1, -1 }, 6, 8},
{ { 95, 135, 135 }, { 5350, -1376, -446 }, { 30, 37 }, 7, 8},
{ { 95, 135, 175 }, { 5492, -286, -2541 }, { -1, -1 }, 7, 8},
{ { 95, 135, 215 }, { 5675, 952, -4526 }, { 103, 104 }, 7, 7},
{ { 95, 135, 255 }, { 5895, 2267, -6396 }, { 33, 105 }, 4, 12},
{ { 95, 175, 0 }, { 6424, -4820, 6517 }, { 34, 71 }, 2, 2},
{ { 95, 175, 95 }, { 6490, -4117, 3349 }, { -1, -1 }, 2, 2},
{ { 95, 175, 135 }, { 6562, -3396, 1301 }, { 140, 228 }, 6, 6},
{ { 95, 175, 175 }, { 6666, -2446, -763 }, { -1, -1 }, 6, 6},
{ { 95, 175, 215 }, { 6802, -1319, -2768 }, { 39, 75 }, 6, 6},
{ { 95, 175, 255 }, { 6969, -71, -4690 }, { -1, -1 }, 7, 7},
{ { 95, 215, 0 }, { 7670, -6288, 7495 }, { -1, -1 }, 2, 2},
{ { 95, 215, 95 }, { 7720, -5722, 4854 }, { 41, 47 }, 2, 2},
{ { 95, 215, 135 }, { 7774, -5127, 2957 }, { 42, 114 }, 2, 2},
{ { 95, 215, 175 }, { 7853, -4321, 966 }, { 44, 78 }, 6, 6},
{ { 95, 215, 215 }, { 7958, -3332, -1018 }, { -1, -1 }, 6, 6},
{ { 95, 215, 255 }, { 8088, -2201, -2952 }, { -1, -1 }, 6, 6},
{ { 95, 255, 0 }, { 8890, -7597, 8460 }, { -1, -1 }, 2, 10},
{ { 95, 255, 95 }, { 8929, -7135, 6239 }, { -1, -1 }, 2, 10},
{ { 95, 255, 135 }, { 8972, -6642, 4506 }, { 83, 120 }, 2, 10},
{ { 95, 255, 175 }, { 9034, -5961, 2614 }, { 49, 121 }, 2, 10},
{ { 95, 255, 215 }, { 9117, -5106, 680 }, { -1, -1 }, 6, 14},
{ { 95, 255, 255 }, { 9221, -4104, -1238 }, { 122, 194 }, 6, 14},
{ { 135, 0, 0 }, { 2717, 4993, 4014 }, { 52, 131 }, 1, 1},
{ { 135, 0, 95 }, { 2936, 5573, -1590 }, { 53, 97 }, 5, 5},
{ { 135, 0, 135 }, { 3158, 6124, -3792 }, { 27, 133 }, 5, 5},
{ { 135, 0, 175 }, { 3449, 6804, -5761 }, { -1, -1 }, 5, 5},
{ { 135, 0, 215 }, { 3795, 7565, -7543 }, { 57, 128 }, 4, 4},
{ { 135, 0, 255 }, { 4180, 8371, -9179 }, { -1, -1 }, 4, 4},
{ { 135, 95, 0 }, { 4327, 913, 5093 }, { -1, -1 }, 3, 3},
{ { 135, 95, 95 }, { 4447, 1631, 651 }, { 243, 130 }, 7, 8},
{ { 135, 95, 135 }, { 4575, 2337, -1577 }, { -1, -1 }, 7, 8},
{ { 135, 95, 175 }, { 4753, 3230, -3670 }, { -1, -1 }, 5, 5},
{ { 135, 95, 215 }, { 4979, 4244, -5618 }, { -1, -1 }, 5, 12},
{ { 135, 95, 255 }, { 5246, 5322, -7432 }, { 63, 135 }, 4, 12},
{ { 135, 135, 0 }, { 5453, -1344, 5890 }, { -1, -1 }, 3, 3},
{ { 135, 135, 95 }, { 5539, -677, 2158 }, { 241, 246 }, 7, 8},
{ { 135, 135, 135 }, { 5632, 0, 0 }, { -1, -1 }, 7, 7},
{ { 135, 135, 175 }, { 5763, 883, -2102 }, { 32, 66 }, 7, 7},
{ { 135, 135, 215 }, { 5933, 1918, -4102 }, { 69, 139 }, 7, 7},
{ { 135, 135, 255 }, { 6139, 3051, -5992 }, { -1, -1 }, 5, 12},
{ { 135, 175, 0 }, { 6637, -3334, 6775 }, { -1, -1 }, 3, 3},
{ { 135, 175, 95 }, { 6700, -2753, 3658 }, { 106, 149 }, 3, 3},
{ { 135, 175, 135 }, { 6769, -2148, 1621 }, { 73, -1 }, 7, 7},
{ { 135, 175, 175 }, { 6868, -1338, -441 }, { -1, -1 }, 7, 7},
{ { 135, 175, 215 }, { 6998, -359, -2451 }, { 74, 248 }, 7, 7},
{ { 135, 175, 255 }, { 7157, 745, -4381 }, { 110, 212 }, 7, 7},
{ { 135, 215, 0 }, { 7832, -5059, 7691 }, { 76, 46 }, 2, 2},
{ { 135, 215, 95 }, { 7880, -4565, 5082 }, { 40, 142 }, 2, 2},
{ { 135, 215, 135 }, { 7933, -4042, 3195 }, { -1, -1 }, 6, 6},
{ { 135, 215, 175 }, { 8009, -3327, 1209 }, { 79, 116 }, 6, 6},
{ { 135, 215, 215 }, { 8110, -2441, -775 }, { 45, 108 }, 6, 6},
{ { 135, 215, 255 }, { 8236, -1415, -2712 }, { 146, 153 }, 7, 7},
{ { 135, 255, 0 }, { 9017, -6577, 8614 }, { 82, 154 }, 2, 10},
{ { 135, 255, 95 }, { 9055, -6160, 6414 }, { 84, 118 }, 2, 10},
{ { 135, 255, 135 }, { 9097, -5712, 4689 }, { -1, -1 }, 2, 10},
{ { 135, 255, 175 }, { 9158, -5090, 2803 }, { -1, -1 }, 6, 14},
{ { 135, 255, 215 }, { 9239, -4305, 871 }, { 51, 85 }, 6, 14},
{ { 135, 255, 255 }, { 9340, -3378, -1048 }, { -1, -1 }, 6, 14},
{ { 175, 0, 0 }, { 3621, 6039, 5057 }, { 132, 125 }, 1, 1},
{ { 175, 0, 95 }, { 3774, 6450, -244 }, { 162, 161 }, 5, 9},
{ { 175, 0, 135 }, { 3935, 6865, -2513 }, { -1, -1 }, 5, 5},
{ { 175, 0, 175 }, { 4155, 7407, -4586 }, { -1, -1 }, 5, 5},
{ { 175, 0, 215 }, { 4426, 8046, -6485 }, { 127, -1 }, 5, 5},
{ { 175, 0, 255 }, { 4741, 8752, -8236 }, { -1, -1 }, 4, 4},
{ { 175, 95, 0 }, { 4864, 2733, 5703 }, { 94, -1 }, 1, 1},
{ { 175, 95, 95 }, { 4965, 3235, 1454 }, { -1, -1 }, 7, 8},
{ { 175, 95, 135 }, { 5075, 3748, -774 }, { 89, 88 }, 7, 8},
{ { 175, 95, 175 }, { 5228, 4425, -2893 }, { 124, 204 }, 5, 5},
{ { 175, 95, 215 }, { 5424, 5228, -4881 }, { 98, 141 }, 5, 5},
{ { 175, 95, 255 }, { 5660, 6118, -6741 }, { -1, -1 }, 5, 12},
{ { 175, 135, 0 }, { 5846, 507, 6350 }, { -1, -1 }, 3, 3},
{ { 175, 135, 95 }, { 5922, 1007, 2735 }, { -1, -1 }, 7, 7},
{ { 175, 135, 135 }, { 6006, 1527, 589 }, { 137, 247 }, 7, 7},
{ { 175, 135, 175 }, { 6125, 2223, -1518 }, { 96, -1 }, 7, 7},
{ { 175, 135, 215 }, { 6280, 3063, -3534 }, { 59, 90 }, 7, 7},
{ { 175, 135, 255 }, { 6469, 4011, -5447 }, { -1, -1 }, 5, 12},
{ { 175, 175, 0 }, { 6931, -1625, 7124 }, { 107, 184 }, 3, 3},
{ { 175, 175, 95 }, { 6990, -1160, 4080 }, { -1, -1 }, 3, 3},
{ { 175, 175, 135 }, { 7054, -669, 2058 }, { -1, -1 }, 7, 7},
{ { 175, 175, 175 }, { 7147, 0, 0 }, { -1, -1 }, 7, 7},
{ { 175, 175, 215 }, { 7268, 824, -2014 }, { -1, -1 }, 7, 7},
{ { 175, 175, 255 }, { 7418, 1772, -3954 }, { 189, 182 }, 7, 7},
{ { 175, 215, 0 }, { 8058, -3551, 7963 }, { -1, -1 }, 3, 3},
{ { 175, 215, 95 }, { 8104, -3135, 5399 }, { -1, -1 }, 3, 3},
{ { 175, 215, 135 }, { 8155, -2689, 3528 }, { 151, 48 }, 3, 3},
{ { 175, 215, 175 }, { 8228, -2074, 1548 }, { 115, 87 }, 7, 7},
{ { 175, 215, 215 }, { 8324, -1303, -434 }, { 250, 195 }, 7, 7},
{ { 175, 215, 255 }, { 8445, -399, -2375 }, { -1, -1 }, 7, 7},
{ { 175, 255, 0 }, { 9197, -5270, 8831 }, { -1, -1 }, 2, 10},
{ { 175, 255, 95 }, { 9234, -4904, 6661 }, { 119, 227 }, 2, 10},
{ { 175, 255, 135 }, { 9274, -4508, 4948 }, { -1, -1 }, 2, 10},
{ { 175, 255, 175 }, { 9333, -3956, 3070 }, { -1, -1 }, 6, 14},
{ { 175, 255, 215 }, { 9411, -3254, 1142 }, { 123, 159 }, 6, 14},
{ { 175, 255, 255 }, { 9510, -2417, -777 }, { -1, -1 }, 6, 14},
{ { 215, 0, 0 }, { 4487, 7041, 5908 }, { -1, -1 }, 1, 1},
{ { 215, 0, 95 }, { 4601, 7349, 1053 }, { 160, -1 }, 1, 9},
{ { 215, 0, 135 }, { 4724, 7671, -1235 }, { 126, 163 }, 5, 5},
{ { 215, 0, 175 }, { 4894, 8105, -3368 }, { -1, -1 }, 5, 5},
{ { 215, 0, 215 }, { 5110, 8636, -5348 }, { -1, -1 }, 5, 5},
{ { 215, 0, 255 }, { 5367, 9245, -7188 }, { 129, 201 }, 5, 13},
{ { 215, 95, 0 }, { 5470, 4355, 6373 }, { -1, -1 }, 1, 1},
{ { 215, 95, 95 }, { 5554, 4720, 2349 }, { 169, 202 }, 1, 9},
{ { 215, 95, 135 }, { 5647, 5103, 135 }, { -1, -1 }, 7, 9},
{ { 215, 95, 175 }, { 5778, 5623, -2000 }, { 168, 174 }, 5, 5},
{ { 215, 95, 215 }, { 5947, 6260, -4020 }, { 62, 171 }, 5, 5},
{ { 215, 95, 255 }, { 6153, 6990, -5924 }, { 165, 200 }, 5, 13},
{ { 215, 135, 0 }, { 6316, 2286, 6890 }, { 136, -1 }, 3, 3},
{ { 215, 135, 95 }, { 6384, 2663, 3419 }, { 138, 172 }, 7, 9},
{ { 215, 135, 135 }, { 6459, 3063, 1294 }, { -1, -1 }, 7, 7},
{ { 215, 135, 175 }, { 6565, 3610, -813 }, { -1, -1 }, 7, 7},
{ { 215, 135, 215 }, { 6704, 4286, -2843 }, { 207, 177 }, 5, 5},
{ { 215, 135, 255 }, { 6875, 5069, -4779 }, { -1, -1 }, 5, 13},
{ { 215, 175, 0 }, { 7296, 143, 7553 }, { 143, 179 }, 3, 3},
{ { 215, 175, 95 }, { 7350, 512, 4600 }, { -1, -1 }, 3, 3},
{ { 215, 175, 135 }, { 7410, 906, 2601 }, { 181, 178 }, 7, 7},
{ { 215, 175, 175 }, { 7495, 1450, 549 }, { 144, 252 }, 7, 7},
{ { 215, 175, 215 }, { 7608, 2132, -1468 }, { 183, 225 }, 7, 7},
{ { 215, 175, 255 }, { 7748, 2932, -3418 }, { 213, 219 }, 7, 7},
{ { 215, 215, 0 }, { 8347, -1895, 8306 }, { 148, -1 }, 3, 3},
{ { 215, 215, 95 }, { 8390, -1549, 5801 }, { 214, 254 }, 3, 3},
{ { 215, 215, 135 }, { 8438, -1177, 3949 }, { -1, -1 }, 3, 3},
{ { 215, 215, 175 }, { 8507, -658, 1980 }, { 253, 220 }, 7, 7},
{ { 215, 215, 215 }, { 8598, 0, 0 }, { -1, -1 }, 7, 7},
{ { 215, 215, 255 }, { 8713, 781, -1944 }, { 117, 152 }, 7, 7},
{ { 215, 255, 0 }, { 9430, -3767, 9110 }, { -1, -1 }, 3, 11},
{ { 215, 255, 95 }, { 9465, -3451, 6978 }, { 156, 192 }, 3, 11},
{ { 215, 255, 135 }, { 9504, -3109, 5283 }, { -1, -1 }, 3, 11},
{ { 215, 255, 175 }, { 9561, -2628, 3414 }, { 157, -1 }, 3, 15},
{ { 215, 255, 215 }, { 9636, -2012, 1491 }, { 158, 193 }, 7, 15},
{ { 215, 255, 255 }, { 9730, -1272, -427 }, { -1, -1 }, 7, 15},
{ { 255, 0, 0 }, { 5324, 8009, 6720 }, { -1, -1 }, 1, 1},
{ { 255, 0, 95 }, { 5413, 8249, 2291 }, { 196, -1 }, 1, 9},
{ { 255, 0, 135 }, { 5509, 8505, 17 }, { 205, 197 }, 5, 9},
{ { 255, 0, 175 }, { 5645, 8859, -2145 }, { -1, -1 }, 5, 5},
{ { 255, 0, 215 }, { 5820, 9303, -4177 }, { 164, -1 }, 5, 13},
{ { 255, 0, 255 }, { 6032, 9823, -6082 }, { -1, -1 }, 5, 13},
{ { 255, 95, 0 }, { 6118, 5801, 7073 }, { 166, 203 }, 1, 1},
{ { 255, 95, 95 }, { 6189, 6077, 3294 }, { -1, -1 }, 1, 9},
{ { 255, 95, 135 }, { 6268, 6372, 1106 }, { 167, 198 }, 1, 9},
{ { 255, 95, 175 }, { 6379, 6781, -1033 }, { 199, 206 }, 5, 5},
{ { 255, 95, 215 }, { 6524, 7293, -3077 }, { -1, -1 }, 5, 13},
{ { 255, 95, 255 }, { 6703, 7895, -5017 }, { -1, -1 }, 5, 13},
{ { 255, 135, 0 }, { 6846, 3935, 7486 }, { -1, -1 }, 1, 1},
{ { 255, 135, 95 }, { 6905, 4226, 4178 }, { 216, 215 }, 1, 9},
{ { 255, 135, 135 }, { 6971, 4538, 2083 }, { -1, -1 }, 1, 9},
{ { 255, 135, 175 }, { 7066, 4971, -18 }, { 175, -1 }, 7, 9},
{ { 255, 135, 215 }, { 7189, 5518, -2058 }, { 176, 211 }, 5, 13},
{ { 255, 135, 255 }, { 7342, 6164, -4013 }, { -1, -1 }, 5, 13},
{ { 255, 175, 0 }, { 7724, 1872, 8047 }, { 180, 209 }, 3, 3},
{ { 255, 175, 95 }, { 7773, 2165, 5200 }, { 208, -1 }, 3, 3},
{ { 255, 175, 135 }, { 7827, 2482, 3230 }, { 210, 217 }, 7, 7},
{ { 255, 175, 175 }, { 7905, 2924, 1190 }, { -1, -1 }, 7, 7},
{ { 255, 175, 215 }, { 8008, 3486, -827 }, { -1, -1 }, 7, 7},
{ { 255, 175, 255 }, { 8137, 4155, -2786 }, { -1, -1 }, 7, 13},
{ { 255, 215, 0 }, { 8693, -192, 8713 }, { 186, 229 }, 3, 11},
{ { 255, 215, 95 }, { 8733, 93, 6278 }, { -1, -1 }, 3, 3},
{ { 255, 215, 135 }, { 8778, 402, 4451 }, { 221, -1 }, 3, 3},
{ { 255, 215, 175 }, { 8843, 836, 2496 }, { 255, 222 }, 7, 15},
{ { 255, 215, 215 }, { 8928, 1392, 520 }, { -1, -1 }, 7, 15},
{ { 255, 215, 255 }, { 9036, 2059, -1425 }, { 218, -1 }, 7, 15},
{ { 255, 255, 0 }, { 9714, -2155, 9448 }, { 190, -1 }, 3, 11},
{ { 255, 255, 95 }, { 9747, -1887, 7362 }, { 191, 226 }, 3, 11},
{ { 255, 255, 135 }, { 9785, -1594, 5688 }, { 150, 251 }, 3, 11},
{ { 255, 255, 175 }, { 9838, -1180, 3833 }, { -1, -1 }, 3, 11},
{ { 255, 255, 215 }, { 9910, -647, 1916 }, { -1, -1 }, 7, 15},
{ { 255, 255, 255 }, { 10000, 0, 0 }, { -1, -1 }, 7, 15},
{ { 8, 8, 8 }, { 219, 0, 0 }, { 23, 234 }, 0, 0},
{ { 18, 18, 18 }, { 546, 0, 0 }, { -1, -1 }, 0, 0},
{ { 28, 28, 28 }, { 1027, 0, 0 }, { 233, 235 }, 0, 0},
{ { 38, 38, 38 }, { 1516, 0, 0 }, { -1, -1 }, 0, 0},
{ { 48, 48, 48 }, { 1987, 0, 0 }, { 232, 237 }, 0, 8},
{ { 58, 58, 58 }, { 2442, 0, 0 }, { 60, 239 }, 0, 8},
{ { 68, 68, 68 }, { 2885, 0, 0 }, { -1, -1 }, 0, 8},
{ { 78, 78, 78 }, { 3318, 0, 0 }, { 238, 240 }, 0, 8},
{ { 88, 88, 88 }, { 3741, 0, 0 }, { -1, -1 }, 0, 8},
{ { 98, 98, 98 }, { 4155, 0, 0 }, { 58, 95 }, 7, 8},
{ { 108, 108, 108 }, { 4563, 0, 0 }, { -1, -1 }, 7, 8},
{ { 118, 118, 118 }, { 4964, 0, 0 }, { 242, 244 }, 7, 8},
{ { 128, 128, 128 }, { 5359, 0, 0 }, { -1, -1 }, 7, 8},
{ { 138, 138, 138 }, { 5748, 0, 0 }, { 102, 36 }, 7, 7},
{ { 148, 148, 148 }, { 6132, 0, 0 }, { 35, 173 }, 7, 7},
{ { 158, 158, 158 }, { 6511, 0, 0 }, { -1, -1 }, 7, 7},
{ { 168, 168, 168 }, { 6887, 0, 0 }, { 109, 145 }, 7, 7},
{ { 178, 178, 178 }, { 7257, 0, 0 }, { 111, 147 }, 7, 7},
{ { 188, 188, 188 }, { 7625, 0, 0 }, { -1, -1 }, 7, 7},
{ { 198, 198, 198 }, { 7988, 0, 0 }, { 249, 185 }, 7, 7},
{ { 208, 208, 208 }, { 8348, 0, 0 }, { -1, -1 }, 7, 7},
{ { 218, 218, 218 }, { 8705, 0, 0 }, { 188, 230 }, 7, 7},
{ { 228, 228, 228 }, { 9059, 0, 0 }, { 187, 223 }, 7, 15},
{ { 238, 238, 238 }, { 9410, 0, 0 }, { 224, 231 }, 7, 15},
};
// CIE76 color difference: squared Euclidean distance in CIELAB.
//
int64_t diff(const LABi &lab1, const LABi &lab2)
{
int64_t dL = static_cast<int64_t>(lab1.L - lab2.L);
int64_t da = static_cast<int64_t>(lab1.a - lab2.a);
int64_t db = static_cast<int64_t>(lab1.b - lab2.b);
int64_t r = dL*dL + da*da + db*db;
return r;
}
void NearestIndex_tree_a(int iHere, const LABi &labi, int &iBest, int64_t &rBest);
void NearestIndex_tree_b(int iHere, const LABi &labi, int &iBest, int64_t &rBest);
void NearestIndex_tree_L(int iHere, const LABi &labi, int &iBest, int64_t &rBest)
{
if (-1 == iHere)
{
return;
}
if (-1 == iBest)
{
iBest = iHere;
rBest = diff(labi, palette[iBest].labi);
}
int64_t rHere = diff(labi, palette[iHere].labi);
if (rHere < rBest)
{
iBest = iHere;
rBest = rHere;
}
int64_t d = static_cast<int64_t>(labi.L - palette[iHere].labi.L);
int iNearChild = (d < 0)?0:1;
NearestIndex_tree_a(palette[iHere].child[iNearChild], labi, iBest, rBest);
int64_t rAxis = d*d;
if (rAxis < rBest)
{
NearestIndex_tree_a(palette[iHere].child[1-iNearChild], labi, iBest, rBest);
}
}
void NearestIndex_tree_a(int iHere, const LABi &labi, int &iBest, int64_t &rBest)
{
if (-1 == iHere)
{
return;
}
if (-1 == iBest)
{
iBest = iHere;
rBest = diff(labi, palette[iBest].labi);
}
int64_t rHere = diff(labi, palette[iHere].labi);
if (rHere < rBest)
{
iBest = iHere;
rBest = rHere;
}
int64_t d = static_cast<int64_t>(labi.a - palette[iHere].labi.a);
int iNearChild = (d < 0)?0:1;
NearestIndex_tree_b(palette[iHere].child[iNearChild], labi, iBest, rBest);
int64_t rAxis = d*d;
if (rAxis < rBest)
{
NearestIndex_tree_b(palette[iHere].child[1-iNearChild], labi, iBest, rBest);
}
}
void NearestIndex_tree_b(int iHere, const LABi &labi, int &iBest, int64_t &rBest)
{
if (-1 == iHere)
{
return;
}
if (-1 == iBest)
{
iBest = iHere;
rBest = diff(labi, palette[iBest].labi);
}
int64_t rHere = diff(labi, palette[iHere].labi);
if (rHere < rBest)
{
iBest = iHere;
rBest = rHere;
}
int64_t d = static_cast<int64_t>(labi.b - palette[iHere].labi.b);
int iNearChild = (d < 0)?0:1;
NearestIndex_tree_L(palette[iHere].child[iNearChild], labi, iBest, rBest);
int64_t rAxis = d*d;
if (rAxis < rBest)
{
NearestIndex_tree_L(palette[iHere].child[1-iNearChild], labi, iBest, rBest);
}
}
int FindNearestPaletteEntry(RGB &rgb, bool fColor256)
{
LABi labi;
rgb2lab(&rgb, &labi);
int64_t d;
int j = -1;
NearestIndex_tree_L(fColor256 ? PALETTE256_ROOT : PALETTE16_ROOT, labi, j, d);
return j;
}
int FindNearestPalette8Entry(RGB &rgb)
{
LABi labi;
rgb2lab(&rgb, &labi);
int iNearest = 0;
int64_t rNearest = diff(labi, palette[0].labi);
for (int i = 1; i < 8; i++)
{
int64_t r = diff(labi, palette[i].labi);
if (r < rNearest)
{
rNearest = r;
iNearest = i;
}
}
return iNearest;
}
// C-callable wrappers for CIE97 + K-d tree nearest-color search.
//
extern "C" LIBMUX_API int co_nearest_xterm256(const unsigned char *rgb)
{
RGB c;
c.r = rgb[0];
c.g = rgb[1];
c.b = rgb[2];
return FindNearestPaletteEntry(c, true);
}
extern "C" LIBMUX_API int co_nearest_xterm16(const unsigned char *rgb)
{
RGB c;
c.r = rgb[0];
c.g = rgb[1];
c.b = rgb[2];
return FindNearestPaletteEntry(c, false);
}
#define CS_FOREGROUND UINT64_C(0x0000000001FFFFFF)
#define CS_FOREGROUND_RED UINT64_C(0x0000000000FF0000)
#define CS_FOREGROUND_GREEN UINT64_C(0x000000000000FF00)
#define CS_FOREGROUND_BLUE UINT64_C(0x00000000000000FF)
#define CS_FG_BLACK UINT64_C(0x0000000001000000) // FOREGROUND BLACK (0,0,0)
#define CS_FG_RED UINT64_C(0x0000000001000001) // FOREGROUND RED (187,0,0)
#define CS_FG_GREEN UINT64_C(0x0000000001000002) // FOREGROUND GREEN (0,187,0)
#define CS_FG_YELLOW UINT64_C(0x0000000001000003) // FOREGROUND YELLOW (187,187,0)
#define CS_FG_BLUE UINT64_C(0x0000000001000004) // FOREGROUND BLUE (0,0,187)
#define CS_FG_MAGENTA UINT64_C(0x0000000001000005) // FOREGROUND MAGENTA (187,0,187)
#define CS_FG_CYAN UINT64_C(0x0000000001000006) // FOREGROUND CYAN (0,187,187)
#define CS_FG_WHITE UINT64_C(0x0000000001000007) // FOREGROUND WHITE (187,187,187)
#define CS_FG_INDEXED UINT64_C(0x0000000001000000)
#define CS_FG(x) (CS_FG_INDEXED | static_cast<uint64_t>(x))
#define CS_FG_FIELD(x) ((x) & UINT64_C(0x0000000000FFFFFF))
#define CS_FG_FIELD_INDEXED(x) ((x) & UINT64_C(0x00000000000000FF))
#define CS_FG_DEFAULT CS_FG(NUM_FG)
#define CS_BACKGROUND UINT64_C(0x01FFFFFF00000000)
#define CS_BACKGROUND_RED UINT64_C(0x00FF000000000000)
#define CS_BACKGROUND_GREEN UINT64_C(0x0000FF0000000000)
#define CS_BACKGROUND_BLUE UINT64_C(0x000000FF00000000)
#define CS_BG_BLACK UINT64_C(0x0100000000000000) // BACKGROUND BLACK (0,0,0)
#define CS_BG_RED UINT64_C(0x0100000100000000) // BACKGROUND RED (187,0,0)
#define CS_BG_GREEN UINT64_C(0x0100000200000000) // BACKGROUND GREEN (0,187,0)
#define CS_BG_YELLOW UINT64_C(0x0100000300000000) // BACKGROUND YELLOW (187,187,0)
#define CS_BG_BLUE UINT64_C(0x0100000400000000) // BACKGROUND BLUE (0,0,187)
#define CS_BG_MAGENTA UINT64_C(0x0100000500000000) // BACKGROUND MAGENTA (187,0,187)
#define CS_BG_CYAN UINT64_C(0x0100000600000000) // BACKGROUND CYAN (0,187,187)
#define CS_BG_WHITE UINT64_C(0x0100000700000000) // BACKGROUND WHITE (187,187,187)
#define CS_BG_INDEXED UINT64_C(0x0100000000000000)
#define CS_BG(x) (CS_BG_INDEXED | (static_cast<uint64_t>(x) << 32))
#define CS_BG_FIELD(x) (((x) & UINT64_C(0x00FFFFFF00000000)) >> 32)
#define CS_BG_FIELD_INDEXED(x) (((x) & UINT64_C(0x000000FF00000000)) >> 32)
#define CS_BG_DEFAULT CS_BG(NUM_BG)
#define CS_INTENSE UINT64_C(0x0000000010000000)
#define CS_INVERSE UINT64_C(0x0000000020000000)
#define CS_UNDERLINE UINT64_C(0x0000000040000000)
#define CS_BLINK UINT64_C(0x0000000080000000)
#define CS_ATTRS UINT64_C(0x00000000F0000000)
#define CS_ALLBITS UINT64_C(0x01FFFFFFF1FFFFFF)
#define CS_NORMAL (CS_FG_DEFAULT|CS_BG_DEFAULT)
#define CS_NOBLEED (CS_FG_WHITE|CS_BG_DEFAULT)
// XTERM_FG(0) through XTERM_FG(7) is equivalent to ANSI_BLACK...ANSI_WHITE.
// Even for 256-color-capable clients, the latter are used instead of the former.
// Similiarly for XTERM_BG(0) through XTERM_BG(0).
//
const MUX_COLOR_SET aColors[] =
{
{ 0, 0, "", 0, T(""), 0, T(""), 0}, // COLOR_NOTCOLOR
{ CS_NORMAL, CS_ALLBITS, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1, T(COLOR_RESET), 3, T("%xn"), 3}, // COLOR_INDEX_RESET
{ CS_INTENSE, CS_INTENSE, ANSI_HILITE, sizeof(ANSI_HILITE)-1, T(COLOR_INTENSE), 3, T("%xh"), 3}, // COLOR_INDEX_ATTR, COLOR_INDEX_INTENSE
{ CS_UNDERLINE, CS_UNDERLINE, ANSI_UNDER, sizeof(ANSI_UNDER)-1, T(COLOR_UNDERLINE), 3, T("%xu"), 3}, // COLOR_INDEX_UNDERLINE
{ CS_BLINK, CS_BLINK, ANSI_BLINK, sizeof(ANSI_BLINK)-1, T(COLOR_BLINK), 3, T("%xf"), 3}, // COLOR_INDEX_BLINK
{ CS_INVERSE, CS_INVERSE, ANSI_INVERSE, sizeof(ANSI_INVERSE)-1, T(COLOR_INVERSE), 3, T("%xi"), 3}, // COLOR_INDEX_INVERSE
{ CS_FG_BLACK, CS_FOREGROUND, ANSI_BLACK, sizeof(ANSI_BLACK)-1, T(COLOR_FG_BLACK), 3, T("%xx"), 3}, // COLOR_INDEX_FG
{ CS_FG_RED, CS_FOREGROUND, ANSI_RED, sizeof(ANSI_RED)-1, T(COLOR_FG_RED), 3, T("%xr"), 3},
{ CS_FG_GREEN, CS_FOREGROUND, ANSI_GREEN, sizeof(ANSI_GREEN)-1, T(COLOR_FG_GREEN), 3, T("%xg"), 3},
{ CS_FG_YELLOW, CS_FOREGROUND, ANSI_YELLOW, sizeof(ANSI_YELLOW)-1, T(COLOR_FG_YELLOW), 3, T("%xy"), 3},
{ CS_FG_BLUE, CS_FOREGROUND, ANSI_BLUE, sizeof(ANSI_BLUE)-1, T(COLOR_FG_BLUE), 3, T("%xb"), 3},
{ CS_FG_MAGENTA, CS_FOREGROUND, ANSI_MAGENTA, sizeof(ANSI_MAGENTA)-1, T(COLOR_FG_MAGENTA), 3, T("%xm"), 3},
{ CS_FG_CYAN, CS_FOREGROUND, ANSI_CYAN, sizeof(ANSI_CYAN)-1, T(COLOR_FG_CYAN), 3, T("%xc"), 3},
{ CS_FG_WHITE, CS_FOREGROUND, ANSI_WHITE, sizeof(ANSI_WHITE)-1, T(COLOR_FG_WHITE), 3, T("%xw"), 3}, // COLOR_INDEX_FG_WHITE
{ CS_FG( 8), CS_FOREGROUND, XTERM_FG( 8), sizeof(XTERM_FG( 8))-1, T(COLOR_FG_555555), 3, T("NU8"), 6}, // These eight are converted into something else.
{ CS_FG( 9), CS_FOREGROUND, XTERM_FG( 9), sizeof(XTERM_FG( 9))-1, T(COLOR_FG_FF5555), 3, T("NU9"), 6}, // .
{ CS_FG( 10), CS_FOREGROUND, XTERM_FG( 10), sizeof(XTERM_FG( 10))-1, T(COLOR_FG_55FF55), 3, T("NU10"), 6}, // .
{ CS_FG( 11), CS_FOREGROUND, XTERM_FG( 11), sizeof(XTERM_FG( 11))-1, T(COLOR_FG_FFFF55), 3, T("NU11"), 6}, // .
{ CS_FG( 12), CS_FOREGROUND, XTERM_FG( 12), sizeof(XTERM_FG( 12))-1, T(COLOR_FG_5555FF), 3, T("NU12"), 6}, // .
{ CS_FG( 13), CS_FOREGROUND, XTERM_FG( 13), sizeof(XTERM_FG( 13))-1, T(COLOR_FG_FF55FF), 3, T("NU13"), 6}, // .
{ CS_FG( 14), CS_FOREGROUND, XTERM_FG( 14), sizeof(XTERM_FG( 14))-1, T(COLOR_FG_55FFFF), 3, T("NU14"), 6}, // .
{ CS_FG( 15), CS_FOREGROUND, XTERM_FG( 15), sizeof(XTERM_FG( 15))-1, T(COLOR_FG_FFFFFF_1),3, T("NU15"), 6}, // -
{ CS_FG( 16), CS_FOREGROUND, XTERM_FG( 16), sizeof(XTERM_FG( 16))-1, T(COLOR_FG_000000), 3, T("%x<#000000>"), 11},
{ CS_FG( 17), CS_FOREGROUND, XTERM_FG( 17), sizeof(XTERM_FG( 17))-1, T(COLOR_FG_00005F), 3, T("%x<#00005F>"), 11},
{ CS_FG( 18), CS_FOREGROUND, XTERM_FG( 18), sizeof(XTERM_FG( 18))-1, T(COLOR_FG_000087), 3, T("%x<#000087>"), 11},
{ CS_FG( 19), CS_FOREGROUND, XTERM_FG( 19), sizeof(XTERM_FG( 19))-1, T(COLOR_FG_0000AF), 3, T("%x<#0000AF>"), 11},
{ CS_FG( 20), CS_FOREGROUND, XTERM_FG( 20), sizeof(XTERM_FG( 20))-1, T(COLOR_FG_0000D7), 3, T("%x<#0000D7>"), 11},
{ CS_FG( 21), CS_FOREGROUND, XTERM_FG( 21), sizeof(XTERM_FG( 21))-1, T(COLOR_FG_0000FF), 3, T("%x<#0000FF>"), 11},
{ CS_FG( 22), CS_FOREGROUND, XTERM_FG( 22), sizeof(XTERM_FG( 22))-1, T(COLOR_FG_005F00), 3, T("%x<#005F00>"), 11},
{ CS_FG( 23), CS_FOREGROUND, XTERM_FG( 23), sizeof(XTERM_FG( 23))-1, T(COLOR_FG_005F5F), 3, T("%x<#005F5F>"), 11},
{ CS_FG( 24), CS_FOREGROUND, XTERM_FG( 24), sizeof(XTERM_FG( 24))-1, T(COLOR_FG_005F87), 3, T("%x<#005F87>"), 11},
{ CS_FG( 25), CS_FOREGROUND, XTERM_FG( 25), sizeof(XTERM_FG( 25))-1, T(COLOR_FG_005FAF), 3, T("%x<#005FAF>"), 11},
{ CS_FG( 26), CS_FOREGROUND, XTERM_FG( 26), sizeof(XTERM_FG( 26))-1, T(COLOR_FG_005FD7), 3, T("%x<#005FD7>"), 11},
{ CS_FG( 27), CS_FOREGROUND, XTERM_FG( 27), sizeof(XTERM_FG( 27))-1, T(COLOR_FG_005FFF), 3, T("%x<#005FFF>"), 11},
{ CS_FG( 28), CS_FOREGROUND, XTERM_FG( 28), sizeof(XTERM_FG( 28))-1, T(COLOR_FG_008700), 3, T("%x<#008700>"), 11},
{ CS_FG( 29), CS_FOREGROUND, XTERM_FG( 29), sizeof(XTERM_FG( 29))-1, T(COLOR_FG_00875F), 3, T("%x<#00875F>"), 11},
{ CS_FG( 30), CS_FOREGROUND, XTERM_FG( 30), sizeof(XTERM_FG( 30))-1, T(COLOR_FG_008785), 3, T("%x<#008785>"), 11},
{ CS_FG( 31), CS_FOREGROUND, XTERM_FG( 31), sizeof(XTERM_FG( 31))-1, T(COLOR_FG_0087AF), 3, T("%x<#0087AF>"), 11},
{ CS_FG( 32), CS_FOREGROUND, XTERM_FG( 32), sizeof(XTERM_FG( 32))-1, T(COLOR_FG_0087D7), 3, T("%x<#0087D7>"), 11},
{ CS_FG( 33), CS_FOREGROUND, XTERM_FG( 33), sizeof(XTERM_FG( 33))-1, T(COLOR_FG_0087FF), 3, T("%x<#0087FF>"), 11},
{ CS_FG( 34), CS_FOREGROUND, XTERM_FG( 34), sizeof(XTERM_FG( 34))-1, T(COLOR_FG_00AF00), 3, T("%x<#00AF00>"), 11},
{ CS_FG( 35), CS_FOREGROUND, XTERM_FG( 35), sizeof(XTERM_FG( 35))-1, T(COLOR_FG_00AF5F), 3, T("%x<#00AF5F>"), 11},
{ CS_FG( 36), CS_FOREGROUND, XTERM_FG( 36), sizeof(XTERM_FG( 36))-1, T(COLOR_FG_00AF87), 3, T("%x<#00AF87>"), 11},
{ CS_FG( 37), CS_FOREGROUND, XTERM_FG( 37), sizeof(XTERM_FG( 37))-1, T(COLOR_FG_00AFAF), 3, T("%x<#00AFAF>"), 11},
{ CS_FG( 38), CS_FOREGROUND, XTERM_FG( 38), sizeof(XTERM_FG( 38))-1, T(COLOR_FG_00AFD7), 3, T("%x<#00AFD7>"), 11},
{ CS_FG( 39), CS_FOREGROUND, XTERM_FG( 39), sizeof(XTERM_FG( 39))-1, T(COLOR_FG_00AFFF), 3, T("%x<#00AFFF>"), 11},
{ CS_FG( 40), CS_FOREGROUND, XTERM_FG( 40), sizeof(XTERM_FG( 40))-1, T(COLOR_FG_00D700), 3, T("%x<#00D700>"), 11},
{ CS_FG( 41), CS_FOREGROUND, XTERM_FG( 41), sizeof(XTERM_FG( 41))-1, T(COLOR_FG_00D75F), 3, T("%x<#00D75F>"), 11},
{ CS_FG( 42), CS_FOREGROUND, XTERM_FG( 42), sizeof(XTERM_FG( 42))-1, T(COLOR_FG_00D787), 3, T("%x<#00D787>"), 11},
{ CS_FG( 43), CS_FOREGROUND, XTERM_FG( 43), sizeof(XTERM_FG( 43))-1, T(COLOR_FG_00D7AF), 3, T("%x<#00D7AF>"), 11},
{ CS_FG( 44), CS_FOREGROUND, XTERM_FG( 44), sizeof(XTERM_FG( 44))-1, T(COLOR_FG_00D7D7), 3, T("%x<#00D7D7>"), 11},
{ CS_FG( 45), CS_FOREGROUND, XTERM_FG( 45), sizeof(XTERM_FG( 45))-1, T(COLOR_FG_00D7FF), 3, T("%x<#00D7FF>"), 11},
{ CS_FG( 46), CS_FOREGROUND, XTERM_FG( 46), sizeof(XTERM_FG( 46))-1, T(COLOR_FG_00FF00), 3, T("%x<#00FF00>"), 11},
{ CS_FG( 47), CS_FOREGROUND, XTERM_FG( 47), sizeof(XTERM_FG( 47))-1, T(COLOR_FG_00FF5A), 3, T("%x<#00FF5A>"), 11},
{ CS_FG( 48), CS_FOREGROUND, XTERM_FG( 48), sizeof(XTERM_FG( 48))-1, T(COLOR_FG_00FF87), 3, T("%x<#00FF87>"), 11},
{ CS_FG( 49), CS_FOREGROUND, XTERM_FG( 49), sizeof(XTERM_FG( 49))-1, T(COLOR_FG_00FFAF), 3, T("%x<#00FFAF>"), 11},
{ CS_FG( 50), CS_FOREGROUND, XTERM_FG( 50), sizeof(XTERM_FG( 50))-1, T(COLOR_FG_00FFD7), 3, T("%x<#00FFD7>"), 11},
{ CS_FG( 51), CS_FOREGROUND, XTERM_FG( 51), sizeof(XTERM_FG( 51))-1, T(COLOR_FG_00FFFF), 3, T("%x<#00FFFF>"), 11},
{ CS_FG( 52), CS_FOREGROUND, XTERM_FG( 52), sizeof(XTERM_FG( 52))-1, T(COLOR_FG_5F0000), 3, T("%x<#5F0000>"), 11},
{ CS_FG( 53), CS_FOREGROUND, XTERM_FG( 53), sizeof(XTERM_FG( 53))-1, T(COLOR_FG_5F005F), 3, T("%x<#5F005F>"), 11},
{ CS_FG( 54), CS_FOREGROUND, XTERM_FG( 54), sizeof(XTERM_FG( 54))-1, T(COLOR_FG_5F0087), 3, T("%x<#5F0087>"), 11},
{ CS_FG( 55), CS_FOREGROUND, XTERM_FG( 55), sizeof(XTERM_FG( 55))-1, T(COLOR_FG_5F00AF), 3, T("%x<#5F00AF>"), 11},
{ CS_FG( 56), CS_FOREGROUND, XTERM_FG( 56), sizeof(XTERM_FG( 56))-1, T(COLOR_FG_5F00D7), 3, T("%x<#5F00D7>"), 11},
{ CS_FG( 57), CS_FOREGROUND, XTERM_FG( 57), sizeof(XTERM_FG( 57))-1, T(COLOR_FG_5F00FF), 3, T("%x<#5F00FF>"), 11},
{ CS_FG( 58), CS_FOREGROUND, XTERM_FG( 58), sizeof(XTERM_FG( 58))-1, T(COLOR_FG_5F5F00), 3, T("%x<#5F5F00>"), 11},
{ CS_FG( 59), CS_FOREGROUND, XTERM_FG( 59), sizeof(XTERM_FG( 59))-1, T(COLOR_FG_5F5F5F), 3, T("%x<#5F5F5F>"), 11},
{ CS_FG( 60), CS_FOREGROUND, XTERM_FG( 60), sizeof(XTERM_FG( 60))-1, T(COLOR_FG_5F5F87), 3, T("%x<#5F5F87>"), 11},
{ CS_FG( 61), CS_FOREGROUND, XTERM_FG( 61), sizeof(XTERM_FG( 61))-1, T(COLOR_FG_5F5FAF), 3, T("%x<#5F5FAF>"), 11},
{ CS_FG( 62), CS_FOREGROUND, XTERM_FG( 62), sizeof(XTERM_FG( 62))-1, T(COLOR_FG_5F5FD7), 3, T("%x<#5F5FD7>"), 11},
{ CS_FG( 63), CS_FOREGROUND, XTERM_FG( 63), sizeof(XTERM_FG( 63))-1, T(COLOR_FG_5F5FFF), 3, T("%x<#5F5FFF>"), 11},
{ CS_FG( 64), CS_FOREGROUND, XTERM_FG( 64), sizeof(XTERM_FG( 64))-1, T(COLOR_FG_5F8700), 3, T("%x<#5F8700>"), 11},
{ CS_FG( 65), CS_FOREGROUND, XTERM_FG( 65), sizeof(XTERM_FG( 65))-1, T(COLOR_FG_5F875F), 3, T("%x<#5F875F>"), 11},
{ CS_FG( 66), CS_FOREGROUND, XTERM_FG( 66), sizeof(XTERM_FG( 66))-1, T(COLOR_FG_5F8787), 3, T("%x<#5F8787>"), 11},
{ CS_FG( 67), CS_FOREGROUND, XTERM_FG( 67), sizeof(XTERM_FG( 67))-1, T(COLOR_FG_5F87AF), 3, T("%x<#5F87AF>"), 11},
{ CS_FG( 68), CS_FOREGROUND, XTERM_FG( 68), sizeof(XTERM_FG( 68))-1, T(COLOR_FG_5F87D7), 3, T("%x<#5F87D7>"), 11},
{ CS_FG( 69), CS_FOREGROUND, XTERM_FG( 69), sizeof(XTERM_FG( 69))-1, T(COLOR_FG_5F87FF), 3, T("%x<#5F87FF>"), 11},
{ CS_FG( 70), CS_FOREGROUND, XTERM_FG( 70), sizeof(XTERM_FG( 70))-1, T(COLOR_FG_5FAF00), 3, T("%x<#5FAF00>"), 11},
{ CS_FG( 71), CS_FOREGROUND, XTERM_FG( 71), sizeof(XTERM_FG( 71))-1, T(COLOR_FG_5FAF5F), 3, T("%x<#5FAF5F>"), 11},
{ CS_FG( 72), CS_FOREGROUND, XTERM_FG( 72), sizeof(XTERM_FG( 72))-1, T(COLOR_FG_5FAF87), 3, T("%x<#5FAF87>"), 11},
{ CS_FG( 73), CS_FOREGROUND, XTERM_FG( 73), sizeof(XTERM_FG( 73))-1, T(COLOR_FG_5FAFAF), 3, T("%x<#5FAFAF>"), 11},
{ CS_FG( 74), CS_FOREGROUND, XTERM_FG( 74), sizeof(XTERM_FG( 74))-1, T(COLOR_FG_5FAFD7), 3, T("%x<#5FAFD7>"), 11},
{ CS_FG( 75), CS_FOREGROUND, XTERM_FG( 75), sizeof(XTERM_FG( 75))-1, T(COLOR_FG_5FAFFF), 3, T("%x<#5FAFFF>"), 11},
{ CS_FG( 76), CS_FOREGROUND, XTERM_FG( 76), sizeof(XTERM_FG( 76))-1, T(COLOR_FG_5FD700), 3, T("%x<#5FD700>"), 11},
{ CS_FG( 77), CS_FOREGROUND, XTERM_FG( 77), sizeof(XTERM_FG( 77))-1, T(COLOR_FG_5FD75F), 3, T("%x<#5FD75F>"), 11},
{ CS_FG( 78), CS_FOREGROUND, XTERM_FG( 78), sizeof(XTERM_FG( 78))-1, T(COLOR_FG_5FD787), 3, T("%x<#5FD787>"), 11},
{ CS_FG( 79), CS_FOREGROUND, XTERM_FG( 79), sizeof(XTERM_FG( 79))-1, T(COLOR_FG_5FD7AF), 3, T("%x<#5FD7AF>"), 11},
{ CS_FG( 80), CS_FOREGROUND, XTERM_FG( 80), sizeof(XTERM_FG( 80))-1, T(COLOR_FG_5FD7D7), 3, T("%x<#5FD7D7>"), 11},
{ CS_FG( 81), CS_FOREGROUND, XTERM_FG( 81), sizeof(XTERM_FG( 81))-1, T(COLOR_FG_5FD7FF), 3, T("%x<#5FD7FF>"), 11},
{ CS_FG( 82), CS_FOREGROUND, XTERM_FG( 82), sizeof(XTERM_FG( 82))-1, T(COLOR_FG_5FFF00), 3, T("%x<#5FFF00>"), 11},
{ CS_FG( 83), CS_FOREGROUND, XTERM_FG( 83), sizeof(XTERM_FG( 83))-1, T(COLOR_FG_5FFF5F), 3, T("%x<#5FFF5F>"), 11},
{ CS_FG( 84), CS_FOREGROUND, XTERM_FG( 84), sizeof(XTERM_FG( 84))-1, T(COLOR_FG_5FFF87), 3, T("%x<#5FFF87>"), 11},
{ CS_FG( 85), CS_FOREGROUND, XTERM_FG( 85), sizeof(XTERM_FG( 85))-1, T(COLOR_FG_5FFFAF), 3, T("%x<#5FFFAF>"), 11},
{ CS_FG( 86), CS_FOREGROUND, XTERM_FG( 86), sizeof(XTERM_FG( 86))-1, T(COLOR_FG_5FFFD7), 3, T("%x<#5FFFD7>"), 11},
{ CS_FG( 87), CS_FOREGROUND, XTERM_FG( 87), sizeof(XTERM_FG( 87))-1, T(COLOR_FG_5FFFFF), 3, T("%x<#5FFFFF>"), 11},
{ CS_FG( 88), CS_FOREGROUND, XTERM_FG( 88), sizeof(XTERM_FG( 88))-1, T(COLOR_FG_870000), 3, T("%x<#870000>"), 11},
{ CS_FG( 89), CS_FOREGROUND, XTERM_FG( 89), sizeof(XTERM_FG( 89))-1, T(COLOR_FG_87005F), 3, T("%x<#87005F>"), 11},
{ CS_FG( 90), CS_FOREGROUND, XTERM_FG( 90), sizeof(XTERM_FG( 90))-1, T(COLOR_FG_870087), 3, T("%x<#870087>"), 11},
{ CS_FG( 91), CS_FOREGROUND, XTERM_FG( 91), sizeof(XTERM_FG( 91))-1, T(COLOR_FG_8700AF), 3, T("%x<#8700AF>"), 11},
{ CS_FG( 92), CS_FOREGROUND, XTERM_FG( 92), sizeof(XTERM_FG( 92))-1, T(COLOR_FG_8700D7), 3, T("%x<#8700D7>"), 11},
{ CS_FG( 93), CS_FOREGROUND, XTERM_FG( 93), sizeof(XTERM_FG( 93))-1, T(COLOR_FG_8700FF), 3, T("%x<#8700FF>"), 11},
{ CS_FG( 94), CS_FOREGROUND, XTERM_FG( 94), sizeof(XTERM_FG( 94))-1, T(COLOR_FG_875F00), 3, T("%x<#875F00>"), 11},
{ CS_FG( 95), CS_FOREGROUND, XTERM_FG( 95), sizeof(XTERM_FG( 95))-1, T(COLOR_FG_875F5F), 3, T("%x<#875F5F>"), 11},
{ CS_FG( 96), CS_FOREGROUND, XTERM_FG( 96), sizeof(XTERM_FG( 96))-1, T(COLOR_FG_875F87), 3, T("%x<#875F87>"), 11},
{ CS_FG( 97), CS_FOREGROUND, XTERM_FG( 97), sizeof(XTERM_FG( 97))-1, T(COLOR_FG_875FAF), 3, T("%x<#875FAF>"), 11},
{ CS_FG( 98), CS_FOREGROUND, XTERM_FG( 98), sizeof(XTERM_FG( 98))-1, T(COLOR_FG_875FD7), 3, T("%x<#875FD7>"), 11},
{ CS_FG( 99), CS_FOREGROUND, XTERM_FG( 99), sizeof(XTERM_FG( 99))-1, T(COLOR_FG_875FFF), 3, T("%x<#875FFF>"), 11},
{ CS_FG(100), CS_FOREGROUND, XTERM_FG(100), sizeof(XTERM_FG(100))-1, T(COLOR_FG_878700), 3, T("%x<#878700>"), 11},
{ CS_FG(101), CS_FOREGROUND, XTERM_FG(101), sizeof(XTERM_FG(101))-1, T(COLOR_FG_87875F), 3, T("%x<#87875F>"), 11},
{ CS_FG(102), CS_FOREGROUND, XTERM_FG(102), sizeof(XTERM_FG(102))-1, T(COLOR_FG_878787), 3, T("%x<#878787>"), 11},
{ CS_FG(103), CS_FOREGROUND, XTERM_FG(103), sizeof(XTERM_FG(103))-1, T(COLOR_FG_8787AF), 3, T("%x<#8787AF>"), 11},
{ CS_FG(104), CS_FOREGROUND, XTERM_FG(104), sizeof(XTERM_FG(104))-1, T(COLOR_FG_8787D7), 3, T("%x<#8787D7>"), 11},
{ CS_FG(105), CS_FOREGROUND, XTERM_FG(105), sizeof(XTERM_FG(105))-1, T(COLOR_FG_8787FF), 3, T("%x<#8787FF>"), 11},
{ CS_FG(106), CS_FOREGROUND, XTERM_FG(106), sizeof(XTERM_FG(106))-1, T(COLOR_FG_87AF00), 3, T("%x<#87AF00>"), 11},
{ CS_FG(107), CS_FOREGROUND, XTERM_FG(107), sizeof(XTERM_FG(107))-1, T(COLOR_FG_87AF5F), 3, T("%x<#87AF5F>"), 11},
{ CS_FG(108), CS_FOREGROUND, XTERM_FG(108), sizeof(XTERM_FG(108))-1, T(COLOR_FG_87AF87), 3, T("%x<#87AF87>"), 11},
{ CS_FG(109), CS_FOREGROUND, XTERM_FG(109), sizeof(XTERM_FG(109))-1, T(COLOR_FG_87AFAF), 3, T("%x<#87AFAF>"), 11},
{ CS_FG(110), CS_FOREGROUND, XTERM_FG(110), sizeof(XTERM_FG(110))-1, T(COLOR_FG_87AFD7), 3, T("%x<#87AFD7>"), 11},
{ CS_FG(111), CS_FOREGROUND, XTERM_FG(111), sizeof(XTERM_FG(111))-1, T(COLOR_FG_87AFFF), 3, T("%x<#87AFFF>"), 11},
{ CS_FG(112), CS_FOREGROUND, XTERM_FG(112), sizeof(XTERM_FG(112))-1, T(COLOR_FG_87D700), 3, T("%x<#87D700>"), 11},
{ CS_FG(113), CS_FOREGROUND, XTERM_FG(113), sizeof(XTERM_FG(113))-1, T(COLOR_FG_87D75A), 3, T("%x<#87D75A>"), 11},
{ CS_FG(114), CS_FOREGROUND, XTERM_FG(114), sizeof(XTERM_FG(114))-1, T(COLOR_FG_87D787), 3, T("%x<#87D787>"), 11},
{ CS_FG(115), CS_FOREGROUND, XTERM_FG(115), sizeof(XTERM_FG(115))-1, T(COLOR_FG_87D7AF), 3, T("%x<#87D7AF>"), 11},
{ CS_FG(116), CS_FOREGROUND, XTERM_FG(116), sizeof(XTERM_FG(116))-1, T(COLOR_FG_87D7D7), 3, T("%x<#87D7D7>"), 11},
{ CS_FG(117), CS_FOREGROUND, XTERM_FG(117), sizeof(XTERM_FG(117))-1, T(COLOR_FG_87D7FF), 3, T("%x<#87D7FF>"), 11},
{ CS_FG(118), CS_FOREGROUND, XTERM_FG(118), sizeof(XTERM_FG(118))-1, T(COLOR_FG_87FF00), 3, T("%x<#87FF00>"), 11},
{ CS_FG(119), CS_FOREGROUND, XTERM_FG(119), sizeof(XTERM_FG(119))-1, T(COLOR_FG_87FF5F), 3, T("%x<#87FF5F>"), 11},
{ CS_FG(120), CS_FOREGROUND, XTERM_FG(120), sizeof(XTERM_FG(120))-1, T(COLOR_FG_87FF87), 3, T("%x<#87FF87>"), 11},
{ CS_FG(121), CS_FOREGROUND, XTERM_FG(121), sizeof(XTERM_FG(121))-1, T(COLOR_FG_87FFAF), 3, T("%x<#87FFAF>"), 11},
{ CS_FG(122), CS_FOREGROUND, XTERM_FG(122), sizeof(XTERM_FG(122))-1, T(COLOR_FG_87FFD7), 3, T("%x<#87FFD7>"), 11},
{ CS_FG(123), CS_FOREGROUND, XTERM_FG(123), sizeof(XTERM_FG(123))-1, T(COLOR_FG_87FFFF), 3, T("%x<#87FFFF>"), 11},
{ CS_FG(124), CS_FOREGROUND, XTERM_FG(124), sizeof(XTERM_FG(124))-1, T(COLOR_FG_AF0000), 3, T("%x<#AF0000>"), 11},
{ CS_FG(125), CS_FOREGROUND, XTERM_FG(125), sizeof(XTERM_FG(125))-1, T(COLOR_FG_AF005F), 3, T("%x<#AF005F>"), 11},
{ CS_FG(126), CS_FOREGROUND, XTERM_FG(126), sizeof(XTERM_FG(126))-1, T(COLOR_FG_AF0087), 3, T("%x<#AF0087>"), 11},
{ CS_FG(127), CS_FOREGROUND, XTERM_FG(127), sizeof(XTERM_FG(127))-1, T(COLOR_FG_AF00AF), 3, T("%x<#AF00AF>"), 11},
{ CS_FG(128), CS_FOREGROUND, XTERM_FG(128), sizeof(XTERM_FG(128))-1, T(COLOR_FG_AF00D7), 3, T("%x<#AF00D7>"), 11},
{ CS_FG(129), CS_FOREGROUND, XTERM_FG(129), sizeof(XTERM_FG(129))-1, T(COLOR_FG_AF00FF), 3, T("%x<#AF00FF>"), 11},
{ CS_FG(130), CS_FOREGROUND, XTERM_FG(130), sizeof(XTERM_FG(130))-1, T(COLOR_FG_AF5F00), 3, T("%x<#AF5F00>"), 11},
{ CS_FG(131), CS_FOREGROUND, XTERM_FG(131), sizeof(XTERM_FG(131))-1, T(COLOR_FG_AF5F5F), 3, T("%x<#AF5F5F>"), 11},
{ CS_FG(132), CS_FOREGROUND, XTERM_FG(132), sizeof(XTERM_FG(132))-1, T(COLOR_FG_AF5F87), 3, T("%x<#AF5F87>"), 11},
{ CS_FG(133), CS_FOREGROUND, XTERM_FG(133), sizeof(XTERM_FG(133))-1, T(COLOR_FG_AF5FAF), 3, T("%x<#AF5FAF>"), 11},
{ CS_FG(134), CS_FOREGROUND, XTERM_FG(134), sizeof(XTERM_FG(134))-1, T(COLOR_FG_AF5FD7), 3, T("%x<#AF5FD7>"), 11},
{ CS_FG(135), CS_FOREGROUND, XTERM_FG(135), sizeof(XTERM_FG(135))-1, T(COLOR_FG_AF5FFF), 3, T("%x<#AF5FFF>"), 11},
{ CS_FG(136), CS_FOREGROUND, XTERM_FG(136), sizeof(XTERM_FG(136))-1, T(COLOR_FG_AF8700), 3, T("%x<#AF8700>"), 11},
{ CS_FG(137), CS_FOREGROUND, XTERM_FG(137), sizeof(XTERM_FG(137))-1, T(COLOR_FG_AF875F), 3, T("%x<#AF875F>"), 11},
{ CS_FG(138), CS_FOREGROUND, XTERM_FG(138), sizeof(XTERM_FG(138))-1, T(COLOR_FG_AF8787), 3, T("%x<#AF8787>"), 11},
{ CS_FG(139), CS_FOREGROUND, XTERM_FG(139), sizeof(XTERM_FG(139))-1, T(COLOR_FG_AF87AF), 3, T("%x<#AF87AF>"), 11},
{ CS_FG(140), CS_FOREGROUND, XTERM_FG(140), sizeof(XTERM_FG(140))-1, T(COLOR_FG_AF87D7), 3, T("%x<#AF87D7>"), 11},
{ CS_FG(141), CS_FOREGROUND, XTERM_FG(141), sizeof(XTERM_FG(141))-1, T(COLOR_FG_AF87FF), 3, T("%x<#AF87FF>"), 11},
{ CS_FG(142), CS_FOREGROUND, XTERM_FG(142), sizeof(XTERM_FG(142))-1, T(COLOR_FG_AFAF00), 3, T("%x<#AFAF00>"), 11},
{ CS_FG(143), CS_FOREGROUND, XTERM_FG(143), sizeof(XTERM_FG(143))-1, T(COLOR_FG_AFAF5F), 3, T("%x<#AFAF5F>"), 11},
{ CS_FG(144), CS_FOREGROUND, XTERM_FG(144), sizeof(XTERM_FG(144))-1, T(COLOR_FG_AFAF87), 3, T("%x<#AFAF87>"), 11},
{ CS_FG(145), CS_FOREGROUND, XTERM_FG(145), sizeof(XTERM_FG(145))-1, T(COLOR_FG_AFAFAF), 3, T("%x<#AFAFAF>"), 11},
{ CS_FG(146), CS_FOREGROUND, XTERM_FG(146), sizeof(XTERM_FG(146))-1, T(COLOR_FG_AFAFD7), 3, T("%x<#AFAFD7>"), 11},
{ CS_FG(147), CS_FOREGROUND, XTERM_FG(147), sizeof(XTERM_FG(147))-1, T(COLOR_FG_AFAFFF), 3, T("%x<#AFAFFF>"), 11},
{ CS_FG(148), CS_FOREGROUND, XTERM_FG(148), sizeof(XTERM_FG(148))-1, T(COLOR_FG_AFD700), 3, T("%x<#AFD700>"), 11},
{ CS_FG(149), CS_FOREGROUND, XTERM_FG(149), sizeof(XTERM_FG(149))-1, T(COLOR_FG_AFD75F), 3, T("%x<#AFD75F>"), 11},
{ CS_FG(150), CS_FOREGROUND, XTERM_FG(150), sizeof(XTERM_FG(150))-1, T(COLOR_FG_AFD787), 3, T("%x<#AFD787>"), 11},
{ CS_FG(151), CS_FOREGROUND, XTERM_FG(151), sizeof(XTERM_FG(151))-1, T(COLOR_FG_AFD7AF), 3, T("%x<#AFD7AF>"), 11},
{ CS_FG(152), CS_FOREGROUND, XTERM_FG(152), sizeof(XTERM_FG(152))-1, T(COLOR_FG_AFD7D7), 3, T("%x<#AFD7D7>"), 11},
{ CS_FG(153), CS_FOREGROUND, XTERM_FG(153), sizeof(XTERM_FG(153))-1, T(COLOR_FG_AFD7FF), 3, T("%x<#AFD7FF>"), 11},
{ CS_FG(154), CS_FOREGROUND, XTERM_FG(154), sizeof(XTERM_FG(154))-1, T(COLOR_FG_AFFF00), 3, T("%x<#AFFF00>"), 11},
{ CS_FG(155), CS_FOREGROUND, XTERM_FG(155), sizeof(XTERM_FG(155))-1, T(COLOR_FG_AFFF5F), 3, T("%x<#AFFF5F>"), 11},
{ CS_FG(156), CS_FOREGROUND, XTERM_FG(156), sizeof(XTERM_FG(156))-1, T(COLOR_FG_AFFF87), 3, T("%x<#AFFF87>"), 11},
{ CS_FG(157), CS_FOREGROUND, XTERM_FG(157), sizeof(XTERM_FG(157))-1, T(COLOR_FG_AFFFAF), 3, T("%x<#AFFFAF>"), 11},
{ CS_FG(158), CS_FOREGROUND, XTERM_FG(158), sizeof(XTERM_FG(158))-1, T(COLOR_FG_AFFFD7), 3, T("%x<#AFFFD7>"), 11},
{ CS_FG(159), CS_FOREGROUND, XTERM_FG(159), sizeof(XTERM_FG(159))-1, T(COLOR_FG_AFFFFF), 3, T("%x<#AFFFFF>"), 11},
{ CS_FG(160), CS_FOREGROUND, XTERM_FG(160), sizeof(XTERM_FG(160))-1, T(COLOR_FG_D70000), 3, T("%x<#D70000>"), 11},
{ CS_FG(161), CS_FOREGROUND, XTERM_FG(161), sizeof(XTERM_FG(161))-1, T(COLOR_FG_D7005F), 3, T("%x<#D7005F>"), 11},
{ CS_FG(162), CS_FOREGROUND, XTERM_FG(162), sizeof(XTERM_FG(162))-1, T(COLOR_FG_D70087), 3, T("%x<#D70087>"), 11},
{ CS_FG(163), CS_FOREGROUND, XTERM_FG(163), sizeof(XTERM_FG(163))-1, T(COLOR_FG_D700AF), 3, T("%x<#D700AF>"), 11},
{ CS_FG(164), CS_FOREGROUND, XTERM_FG(164), sizeof(XTERM_FG(164))-1, T(COLOR_FG_D700D7), 3, T("%x<#D700D7>"), 11},
{ CS_FG(165), CS_FOREGROUND, XTERM_FG(165), sizeof(XTERM_FG(165))-1, T(COLOR_FG_D700FF), 3, T("%x<#D700FF>"), 11},
{ CS_FG(166), CS_FOREGROUND, XTERM_FG(166), sizeof(XTERM_FG(166))-1, T(COLOR_FG_D75F00), 3, T("%x<#D75F00>"), 11},
{ CS_FG(167), CS_FOREGROUND, XTERM_FG(167), sizeof(XTERM_FG(167))-1, T(COLOR_FG_D75F5F), 3, T("%x<#D75F5F>"), 11},
{ CS_FG(168), CS_FOREGROUND, XTERM_FG(168), sizeof(XTERM_FG(168))-1, T(COLOR_FG_D75F87), 3, T("%x<#D75F87>"), 11},
{ CS_FG(169), CS_FOREGROUND, XTERM_FG(169), sizeof(XTERM_FG(169))-1, T(COLOR_FG_D75FAF), 3, T("%x<#D75FAF>"), 11},
{ CS_FG(170), CS_FOREGROUND, XTERM_FG(170), sizeof(XTERM_FG(170))-1, T(COLOR_FG_D75FD7), 3, T("%x<#D75FD7>"), 11},
{ CS_FG(171), CS_FOREGROUND, XTERM_FG(171), sizeof(XTERM_FG(171))-1, T(COLOR_FG_D75FFF), 3, T("%x<#D75FFF>"), 11},
{ CS_FG(172), CS_FOREGROUND, XTERM_FG(172), sizeof(XTERM_FG(172))-1, T(COLOR_FG_D78700), 3, T("%x<#D78700>"), 11},
{ CS_FG(173), CS_FOREGROUND, XTERM_FG(173), sizeof(XTERM_FG(173))-1, T(COLOR_FG_D7875A), 3, T("%x<#D7875A>"), 11},
{ CS_FG(174), CS_FOREGROUND, XTERM_FG(174), sizeof(XTERM_FG(174))-1, T(COLOR_FG_D78787), 3, T("%x<#D78787>"), 11},
{ CS_FG(175), CS_FOREGROUND, XTERM_FG(175), sizeof(XTERM_FG(175))-1, T(COLOR_FG_D787AF), 3, T("%x<#D787AF>"), 11},
{ CS_FG(176), CS_FOREGROUND, XTERM_FG(176), sizeof(XTERM_FG(176))-1, T(COLOR_FG_D787D7), 3, T("%x<#D787D7>"), 11},
{ CS_FG(177), CS_FOREGROUND, XTERM_FG(177), sizeof(XTERM_FG(177))-1, T(COLOR_FG_D787FF), 3, T("%x<#D787FF>"), 11},
{ CS_FG(178), CS_FOREGROUND, XTERM_FG(178), sizeof(XTERM_FG(178))-1, T(COLOR_FG_D7AF00), 3, T("%x<#D7AF00>"), 11},
{ CS_FG(179), CS_FOREGROUND, XTERM_FG(179), sizeof(XTERM_FG(179))-1, T(COLOR_FG_D7AF5A), 3, T("%x<#D7AF5A>"), 11},
{ CS_FG(180), CS_FOREGROUND, XTERM_FG(180), sizeof(XTERM_FG(180))-1, T(COLOR_FG_D7AF87), 3, T("%x<#D7AF87>"), 11},
{ CS_FG(181), CS_FOREGROUND, XTERM_FG(181), sizeof(XTERM_FG(181))-1, T(COLOR_FG_D7AFAF), 3, T("%x<#D7AFAF>"), 11},
{ CS_FG(182), CS_FOREGROUND, XTERM_FG(182), sizeof(XTERM_FG(182))-1, T(COLOR_FG_D7AFD7), 3, T("%x<#D7AFD7>"), 11},
{ CS_FG(183), CS_FOREGROUND, XTERM_FG(183), sizeof(XTERM_FG(183))-1, T(COLOR_FG_D7AFFF), 3, T("%x<#D7AFFF>"), 11},
{ CS_FG(184), CS_FOREGROUND, XTERM_FG(184), sizeof(XTERM_FG(184))-1, T(COLOR_FG_D7D700), 3, T("%x<#D7D700>"), 11},
{ CS_FG(185), CS_FOREGROUND, XTERM_FG(185), sizeof(XTERM_FG(185))-1, T(COLOR_FG_D7D75F), 3, T("%x<#D7D75F>"), 11},
{ CS_FG(186), CS_FOREGROUND, XTERM_FG(186), sizeof(XTERM_FG(186))-1, T(COLOR_FG_D7D787), 3, T("%x<#D7D787>"), 11},
{ CS_FG(187), CS_FOREGROUND, XTERM_FG(187), sizeof(XTERM_FG(187))-1, T(COLOR_FG_D7D7AF), 3, T("%x<#D7D7AF>"), 11},
{ CS_FG(188), CS_FOREGROUND, XTERM_FG(188), sizeof(XTERM_FG(188))-1, T(COLOR_FG_D7D7D7), 3, T("%x<#D7D7D7>"), 11},
{ CS_FG(189), CS_FOREGROUND, XTERM_FG(189), sizeof(XTERM_FG(189))-1, T(COLOR_FG_D7D7FF), 3, T("%x<#D7D7FF>"), 11},
{ CS_FG(190), CS_FOREGROUND, XTERM_FG(190), sizeof(XTERM_FG(190))-1, T(COLOR_FG_D7FF00), 3, T("%x<#D7FF00>"), 11},
{ CS_FG(191), CS_FOREGROUND, XTERM_FG(191), sizeof(XTERM_FG(191))-1, T(COLOR_FG_D7FF5F), 3, T("%x<#D7FF5F>"), 11},
{ CS_FG(192), CS_FOREGROUND, XTERM_FG(192), sizeof(XTERM_FG(192))-1, T(COLOR_FG_D7FF87), 3, T("%x<#D7FF87>"), 11},
{ CS_FG(193), CS_FOREGROUND, XTERM_FG(193), sizeof(XTERM_FG(193))-1, T(COLOR_FG_D7FFAF), 3, T("%x<#D7FFAF>"), 11},
{ CS_FG(194), CS_FOREGROUND, XTERM_FG(194), sizeof(XTERM_FG(194))-1, T(COLOR_FG_D7FFD7), 3, T("%x<#D7FFD7>"), 11},
{ CS_FG(195), CS_FOREGROUND, XTERM_FG(195), sizeof(XTERM_FG(195))-1, T(COLOR_FG_D7FFFF), 3, T("%x<#D7FFFF>"), 11},
{ CS_FG(196), CS_FOREGROUND, XTERM_FG(196), sizeof(XTERM_FG(196))-1, T(COLOR_FG_FF0000), 3, T("%x<#FF0000>"), 11},
{ CS_FG(197), CS_FOREGROUND, XTERM_FG(197), sizeof(XTERM_FG(197))-1, T(COLOR_FG_FF005F), 3, T("%x<#FF005F>"), 11},
{ CS_FG(198), CS_FOREGROUND, XTERM_FG(198), sizeof(XTERM_FG(198))-1, T(COLOR_FG_FF0087), 3, T("%x<#FF0087>"), 11},
{ CS_FG(199), CS_FOREGROUND, XTERM_FG(199), sizeof(XTERM_FG(199))-1, T(COLOR_FG_FF00AF), 3, T("%x<#FF00AF>"), 11},
{ CS_FG(200), CS_FOREGROUND, XTERM_FG(200), sizeof(XTERM_FG(200))-1, T(COLOR_FG_FF00D7), 3, T("%x<#FF00D7>"), 11},
{ CS_FG(201), CS_FOREGROUND, XTERM_FG(201), sizeof(XTERM_FG(201))-1, T(COLOR_FG_FF00FF), 3, T("%x<#FF00FF>"), 11},
{ CS_FG(202), CS_FOREGROUND, XTERM_FG(202), sizeof(XTERM_FG(202))-1, T(COLOR_FG_FF5F00), 3, T("%x<#FF5F00>"), 11},
{ CS_FG(203), CS_FOREGROUND, XTERM_FG(203), sizeof(XTERM_FG(203))-1, T(COLOR_FG_FF5F5F), 3, T("%x<#FF5F5F>"), 11},
{ CS_FG(204), CS_FOREGROUND, XTERM_FG(204), sizeof(XTERM_FG(204))-1, T(COLOR_FG_FF5F87), 3, T("%x<#FF5F87>"), 11},
{ CS_FG(205), CS_FOREGROUND, XTERM_FG(205), sizeof(XTERM_FG(205))-1, T(COLOR_FG_FF5FAF), 3, T("%x<#FF5FAF>"), 11},
{ CS_FG(206), CS_FOREGROUND, XTERM_FG(206), sizeof(XTERM_FG(206))-1, T(COLOR_FG_FF5FD7), 3, T("%x<#FF5FD7>"), 11},
{ CS_FG(207), CS_FOREGROUND, XTERM_FG(207), sizeof(XTERM_FG(207))-1, T(COLOR_FG_FF5FFF), 3, T("%x<#FF5FFF>"), 11},
{ CS_FG(208), CS_FOREGROUND, XTERM_FG(208), sizeof(XTERM_FG(208))-1, T(COLOR_FG_FF8700), 3, T("%x<#FF8700>"), 11},
{ CS_FG(209), CS_FOREGROUND, XTERM_FG(209), sizeof(XTERM_FG(209))-1, T(COLOR_FG_FF875F), 3, T("%x<#FF875F>"), 11},
{ CS_FG(210), CS_FOREGROUND, XTERM_FG(210), sizeof(XTERM_FG(210))-1, T(COLOR_FG_FF8787), 3, T("%x<#FF8787>"), 11},
{ CS_FG(211), CS_FOREGROUND, XTERM_FG(211), sizeof(XTERM_FG(211))-1, T(COLOR_FG_FF87AF), 3, T("%x<#FF87AF>"), 11},
{ CS_FG(212), CS_FOREGROUND, XTERM_FG(212), sizeof(XTERM_FG(212))-1, T(COLOR_FG_FF87D7), 3, T("%x<#FF87D7>"), 11},
{ CS_FG(213), CS_FOREGROUND, XTERM_FG(213), sizeof(XTERM_FG(213))-1, T(COLOR_FG_FF87FF), 3, T("%x<#FF87FF>"), 11},
{ CS_FG(214), CS_FOREGROUND, XTERM_FG(214), sizeof(XTERM_FG(214))-1, T(COLOR_FG_FFAF00), 3, T("%x<#FFAF00>"), 11},
{ CS_FG(215), CS_FOREGROUND, XTERM_FG(215), sizeof(XTERM_FG(215))-1, T(COLOR_FG_FFAF5F), 3, T("%x<#FFAF5F>"), 11},
{ CS_FG(216), CS_FOREGROUND, XTERM_FG(216), sizeof(XTERM_FG(216))-1, T(COLOR_FG_FFAF87), 3, T("%x<#FFAF87>"), 11},
{ CS_FG(217), CS_FOREGROUND, XTERM_FG(217), sizeof(XTERM_FG(217))-1, T(COLOR_FG_FFAFAF), 3, T("%x<#FFAFAF>"), 11},
{ CS_FG(218), CS_FOREGROUND, XTERM_FG(218), sizeof(XTERM_FG(218))-1, T(COLOR_FG_FFAFD7), 3, T("%x<#FFAFD7>"), 11},
{ CS_FG(219), CS_FOREGROUND, XTERM_FG(219), sizeof(XTERM_FG(219))-1, T(COLOR_FG_FFAFFF), 3, T("%x<#FFAFFF>"), 11},
{ CS_FG(220), CS_FOREGROUND, XTERM_FG(220), sizeof(XTERM_FG(220))-1, T(COLOR_FG_FFD700), 3, T("%x<#FFD700>"), 11},
{ CS_FG(221), CS_FOREGROUND, XTERM_FG(221), sizeof(XTERM_FG(221))-1, T(COLOR_FG_FFD75F), 3, T("%x<#FFD75F>"), 11},
{ CS_FG(222), CS_FOREGROUND, XTERM_FG(222), sizeof(XTERM_FG(222))-1, T(COLOR_FG_FFD787), 3, T("%x<#FFD787>"), 11},
{ CS_FG(223), CS_FOREGROUND, XTERM_FG(223), sizeof(XTERM_FG(223))-1, T(COLOR_FG_FFD7AF), 3, T("%x<#FFD7AF>"), 11},
{ CS_FG(224), CS_FOREGROUND, XTERM_FG(224), sizeof(XTERM_FG(224))-1, T(COLOR_FG_FFD7D7), 3, T("%x<#FFD7D7>"), 11},
{ CS_FG(225), CS_FOREGROUND, XTERM_FG(225), sizeof(XTERM_FG(225))-1, T(COLOR_FG_FFD7FF), 3, T("%x<#FFD7FF>"), 11},
{ CS_FG(226), CS_FOREGROUND, XTERM_FG(226), sizeof(XTERM_FG(226))-1, T(COLOR_FG_FFFF00), 3, T("%x<#FFFF00>"), 11},
{ CS_FG(227), CS_FOREGROUND, XTERM_FG(227), sizeof(XTERM_FG(227))-1, T(COLOR_FG_FFFF5F), 3, T("%x<#FFFF5F>"), 11},
{ CS_FG(228), CS_FOREGROUND, XTERM_FG(228), sizeof(XTERM_FG(228))-1, T(COLOR_FG_FFFF87), 3, T("%x<#FFFF87>"), 11},
{ CS_FG(229), CS_FOREGROUND, XTERM_FG(229), sizeof(XTERM_FG(229))-1, T(COLOR_FG_FFFFAF), 3, T("%x<#FFFFAF>"), 11},
{ CS_FG(230), CS_FOREGROUND, XTERM_FG(230), sizeof(XTERM_FG(230))-1, T(COLOR_FG_FFFFD7), 3, T("%x<#FFFFD7>"), 11},
{ CS_FG(231), CS_FOREGROUND, XTERM_FG(231), sizeof(XTERM_FG(231))-1, T(COLOR_FG_FFFFFF_2),3, T("%x<#FFFFFF>"), 11},
{ CS_FG(232), CS_FOREGROUND, XTERM_FG(232), sizeof(XTERM_FG(232))-1, T(COLOR_FG_080808), 3, T("%x<#080808>"), 11},
{ CS_FG(233), CS_FOREGROUND, XTERM_FG(233), sizeof(XTERM_FG(233))-1, T(COLOR_FG_121212), 3, T("%x<#121212>"), 11},
{ CS_FG(234), CS_FOREGROUND, XTERM_FG(234), sizeof(XTERM_FG(234))-1, T(COLOR_FG_1C1C1C), 3, T("%x<#1C1C1C>"), 11},
{ CS_FG(235), CS_FOREGROUND, XTERM_FG(235), sizeof(XTERM_FG(235))-1, T(COLOR_FG_262626), 3, T("%x<#262626>"), 11},
{ CS_FG(236), CS_FOREGROUND, XTERM_FG(236), sizeof(XTERM_FG(236))-1, T(COLOR_FG_303030), 3, T("%x<#303030>"), 11},
{ CS_FG(237), CS_FOREGROUND, XTERM_FG(237), sizeof(XTERM_FG(237))-1, T(COLOR_FG_3A3A3A), 3, T("%x<#3A3A3A>"), 11},
{ CS_FG(238), CS_FOREGROUND, XTERM_FG(238), sizeof(XTERM_FG(238))-1, T(COLOR_FG_444444), 3, T("%x<#444444>"), 11},
{ CS_FG(239), CS_FOREGROUND, XTERM_FG(239), sizeof(XTERM_FG(239))-1, T(COLOR_FG_4E4E4E), 3, T("%x<#4E4E4E>"), 11},
{ CS_FG(240), CS_FOREGROUND, XTERM_FG(240), sizeof(XTERM_FG(240))-1, T(COLOR_FG_585858), 3, T("%x<#585858>"), 11},
{ CS_FG(241), CS_FOREGROUND, XTERM_FG(241), sizeof(XTERM_FG(241))-1, T(COLOR_FG_626262), 3, T("%x<#626262>"), 11},
{ CS_FG(242), CS_FOREGROUND, XTERM_FG(242), sizeof(XTERM_FG(242))-1, T(COLOR_FG_6C6C6C), 3, T("%x<#6C6C6C>"), 11},
{ CS_FG(243), CS_FOREGROUND, XTERM_FG(243), sizeof(XTERM_FG(243))-1, T(COLOR_FG_767676), 3, T("%x<#767676>"), 11},
{ CS_FG(244), CS_FOREGROUND, XTERM_FG(244), sizeof(XTERM_FG(244))-1, T(COLOR_FG_808080), 3, T("%x<#808080>"), 11},
{ CS_FG(245), CS_FOREGROUND, XTERM_FG(245), sizeof(XTERM_FG(245))-1, T(COLOR_FG_8A8A8A), 3, T("%x<#8A8A8A>"), 11},
{ CS_FG(246), CS_FOREGROUND, XTERM_FG(246), sizeof(XTERM_FG(246))-1, T(COLOR_FG_949494), 3, T("%x<#949494>"), 11},
{ CS_FG(247), CS_FOREGROUND, XTERM_FG(247), sizeof(XTERM_FG(247))-1, T(COLOR_FG_9E9E9E), 3, T("%x<#9E9E9E>"), 11},
{ CS_FG(248), CS_FOREGROUND, XTERM_FG(248), sizeof(XTERM_FG(248))-1, T(COLOR_FG_A8A8A8), 3, T("%x<#A8A8A8>"), 11},
{ CS_FG(249), CS_FOREGROUND, XTERM_FG(249), sizeof(XTERM_FG(249))-1, T(COLOR_FG_B2B2B2), 3, T("%x<#B2B2B2>"), 11},
{ CS_FG(250), CS_FOREGROUND, XTERM_FG(250), sizeof(XTERM_FG(250))-1, T(COLOR_FG_BCBCBC), 3, T("%x<#BCBCBC>"), 11},
{ CS_FG(251), CS_FOREGROUND, XTERM_FG(251), sizeof(XTERM_FG(251))-1, T(COLOR_FG_C6C6C6), 3, T("%x<#C6C6C6>"), 11},
{ CS_FG(252), CS_FOREGROUND, XTERM_FG(252), sizeof(XTERM_FG(252))-1, T(COLOR_FG_D0D0D0), 3, T("%x<#D0D0D0>"), 11},
{ CS_FG(253), CS_FOREGROUND, XTERM_FG(253), sizeof(XTERM_FG(253))-1, T(COLOR_FG_DADADA), 3, T("%x<#DADADA>"), 11},
{ CS_FG(254), CS_FOREGROUND, XTERM_FG(254), sizeof(XTERM_FG(254))-1, T(COLOR_FG_E4E4E4), 3, T("%x<#E4E4E4>"), 11},
{ CS_FG(255), CS_FOREGROUND, XTERM_FG(255), sizeof(XTERM_FG(255))-1, T(COLOR_FG_EEEEEE), 3, T("%x<#EEEEEE>"), 11},
{ CS_BG_BLACK, CS_BACKGROUND, ANSI_BBLACK, sizeof(ANSI_BBLACK)-1, T(COLOR_BG_BLACK), 3, T("%xX"), 3}, // COLOR_INDEX_BG
{ CS_BG_RED, CS_BACKGROUND, ANSI_BRED, sizeof(ANSI_BRED)-1, T(COLOR_BG_RED), 3, T("%xR"), 3},
{ CS_BG_GREEN, CS_BACKGROUND, ANSI_BGREEN, sizeof(ANSI_BGREEN)-1, T(COLOR_BG_GREEN), 3, T("%xG"), 3},
{ CS_BG_YELLOW, CS_BACKGROUND, ANSI_BYELLOW, sizeof(ANSI_BYELLOW)-1, T(COLOR_BG_YELLOW), 3, T("%xY"), 3},
{ CS_BG_BLUE, CS_BACKGROUND, ANSI_BBLUE, sizeof(ANSI_BBLUE)-1, T(COLOR_BG_BLUE), 3, T("%xB"), 3},
{ CS_BG_MAGENTA, CS_BACKGROUND, ANSI_BMAGENTA, sizeof(ANSI_BMAGENTA)-1, T(COLOR_BG_MAGENTA), 3, T("%xM"), 3},
{ CS_BG_CYAN, CS_BACKGROUND, ANSI_BCYAN, sizeof(ANSI_BCYAN)-1, T(COLOR_BG_CYAN), 3, T("%xC"), 3},
{ CS_BG_WHITE, CS_BACKGROUND, ANSI_BWHITE, sizeof(ANSI_BWHITE)-1, T(COLOR_BG_WHITE), 3, T("%xW"), 3},
{ CS_BG( 8), CS_BACKGROUND, ANSI_BBLACK, sizeof(ANSI_BBLACK)-1, T(COLOR_BG_555555), 3, T("%xX"), 3}, // These eight are never used.
{ CS_BG( 9), CS_BACKGROUND, ANSI_BRED, sizeof(ANSI_BRED)-1, T(COLOR_BG_FF5555), 3, T("%xR"), 3}, // .
{ CS_BG( 10), CS_BACKGROUND, ANSI_BGREEN, sizeof(ANSI_BGREEN)-1, T(COLOR_BG_55FF55), 3, T("%xG"), 3}, // .
{ CS_BG( 11), CS_BACKGROUND, ANSI_BYELLOW, sizeof(ANSI_BYELLOW)-1, T(COLOR_BG_FFFF55), 3, T("%xY"), 3}, // .
{ CS_BG( 12), CS_BACKGROUND, ANSI_BBLUE, sizeof(ANSI_BBLUE)-1, T(COLOR_BG_5555FF), 3, T("%xB"), 3}, // .
{ CS_BG( 13), CS_BACKGROUND, ANSI_BMAGENTA, sizeof(ANSI_BMAGENTA)-1, T(COLOR_BG_FF55FF), 3, T("%xM"), 3}, // .
{ CS_BG( 14), CS_BACKGROUND, ANSI_BCYAN, sizeof(ANSI_BCYAN)-1, T(COLOR_BG_55FFFF), 3, T("%xC"), 3}, // .
{ CS_BG( 15), CS_BACKGROUND, ANSI_BWHITE, sizeof(ANSI_BWHITE)-1, T(COLOR_BG_FFFFFF_1),3, T("%xW"), 3}, // -
{ CS_BG( 16), CS_BACKGROUND, XTERM_BG( 16), sizeof(XTERM_BG( 16))-1, T(COLOR_BG_000000), 3, T("%X<#000000>"), 11},
{ CS_BG( 17), CS_BACKGROUND, XTERM_BG( 17), sizeof(XTERM_BG( 17))-1, T(COLOR_BG_00005F), 3, T("%X<#00005F>"), 11},
{ CS_BG( 18), CS_BACKGROUND, XTERM_BG( 18), sizeof(XTERM_BG( 18))-1, T(COLOR_BG_000087), 3, T("%X<#000087>"), 11},
{ CS_BG( 19), CS_BACKGROUND, XTERM_BG( 19), sizeof(XTERM_BG( 19))-1, T(COLOR_BG_0000AF), 3, T("%X<#0000AF>"), 11},
{ CS_BG( 20), CS_BACKGROUND, XTERM_BG( 20), sizeof(XTERM_BG( 20))-1, T(COLOR_BG_0000D7), 3, T("%X<#0000D7>"), 11},
{ CS_BG( 21), CS_BACKGROUND, XTERM_BG( 21), sizeof(XTERM_BG( 21))-1, T(COLOR_BG_0000FF), 3, T("%X<#0000FF>"), 11},
{ CS_BG( 22), CS_BACKGROUND, XTERM_BG( 22), sizeof(XTERM_BG( 22))-1, T(COLOR_BG_005F00), 3, T("%X<#005F00>"), 11},
{ CS_BG( 23), CS_BACKGROUND, XTERM_BG( 23), sizeof(XTERM_BG( 23))-1, T(COLOR_BG_005F5F), 3, T("%X<#005F5F>"), 11},
{ CS_BG( 24), CS_BACKGROUND, XTERM_BG( 24), sizeof(XTERM_BG( 24))-1, T(COLOR_BG_005F87), 3, T("%X<#005F87>"), 11},
{ CS_BG( 25), CS_BACKGROUND, XTERM_BG( 25), sizeof(XTERM_BG( 25))-1, T(COLOR_BG_005FAF), 3, T("%X<#005FAF>"), 11},
{ CS_BG( 26), CS_BACKGROUND, XTERM_BG( 26), sizeof(XTERM_BG( 26))-1, T(COLOR_BG_005FD7), 3, T("%X<#005FD7>"), 11},
{ CS_BG( 27), CS_BACKGROUND, XTERM_BG( 27), sizeof(XTERM_BG( 27))-1, T(COLOR_BG_005FFF), 3, T("%X<#005FFF>"), 11},
{ CS_BG( 28), CS_BACKGROUND, XTERM_BG( 28), sizeof(XTERM_BG( 28))-1, T(COLOR_BG_008700), 3, T("%X<#008700>"), 11},
{ CS_BG( 29), CS_BACKGROUND, XTERM_BG( 29), sizeof(XTERM_BG( 29))-1, T(COLOR_BG_00875F), 3, T("%X<#00875F>"), 11},
{ CS_BG( 30), CS_BACKGROUND, XTERM_BG( 30), sizeof(XTERM_BG( 30))-1, T(COLOR_BG_008785), 3, T("%X<#008785>"), 11},
{ CS_BG( 31), CS_BACKGROUND, XTERM_BG( 31), sizeof(XTERM_BG( 31))-1, T(COLOR_BG_0087AF), 3, T("%X<#0087AF>"), 11},
{ CS_BG( 32), CS_BACKGROUND, XTERM_BG( 32), sizeof(XTERM_BG( 32))-1, T(COLOR_BG_0087D7), 3, T("%X<#0087D7>"), 11},
{ CS_BG( 33), CS_BACKGROUND, XTERM_BG( 33), sizeof(XTERM_BG( 33))-1, T(COLOR_BG_0087FF), 3, T("%X<#0087FF>"), 11},
{ CS_BG( 34), CS_BACKGROUND, XTERM_BG( 34), sizeof(XTERM_BG( 34))-1, T(COLOR_BG_00AF00), 3, T("%X<#00AF00>"), 11},
{ CS_BG( 35), CS_BACKGROUND, XTERM_BG( 35), sizeof(XTERM_BG( 35))-1, T(COLOR_BG_00AF5F), 3, T("%X<#00AF5F>"), 11},
{ CS_BG( 36), CS_BACKGROUND, XTERM_BG( 36), sizeof(XTERM_BG( 36))-1, T(COLOR_BG_00AF87), 3, T("%X<#00AF87>"), 11},
{ CS_BG( 37), CS_BACKGROUND, XTERM_BG( 37), sizeof(XTERM_BG( 37))-1, T(COLOR_BG_00AFAF), 3, T("%X<#00AFAF>"), 11},
{ CS_BG( 38), CS_BACKGROUND, XTERM_BG( 38), sizeof(XTERM_BG( 38))-1, T(COLOR_BG_00AFD7), 3, T("%X<#00AFD7>"), 11},
{ CS_BG( 39), CS_BACKGROUND, XTERM_BG( 39), sizeof(XTERM_BG( 39))-1, T(COLOR_BG_00AFFF), 3, T("%X<#00AFFF>"), 11},
{ CS_BG( 40), CS_BACKGROUND, XTERM_BG( 40), sizeof(XTERM_BG( 40))-1, T(COLOR_BG_00D700), 3, T("%X<#00D700>"), 11},
{ CS_BG( 41), CS_BACKGROUND, XTERM_BG( 41), sizeof(XTERM_BG( 41))-1, T(COLOR_BG_00D75F), 3, T("%X<#00D75F>"), 11},
{ CS_BG( 42), CS_BACKGROUND, XTERM_BG( 42), sizeof(XTERM_BG( 42))-1, T(COLOR_BG_00D787), 3, T("%X<#00D787>"), 11},
{ CS_BG( 43), CS_BACKGROUND, XTERM_BG( 43), sizeof(XTERM_BG( 43))-1, T(COLOR_BG_00D7AF), 3, T("%X<#00D7AF>"), 11},
{ CS_BG( 44), CS_BACKGROUND, XTERM_BG( 44), sizeof(XTERM_BG( 44))-1, T(COLOR_BG_00D7D7), 3, T("%X<#00D7D7>"), 11},
{ CS_BG( 45), CS_BACKGROUND, XTERM_BG( 45), sizeof(XTERM_BG( 45))-1, T(COLOR_BG_00D7FF), 3, T("%X<#00D7FF>"), 11},
{ CS_BG( 46), CS_BACKGROUND, XTERM_BG( 46), sizeof(XTERM_BG( 46))-1, T(COLOR_BG_00FF00), 3, T("%X<#00FF00>"), 11},
{ CS_BG( 47), CS_BACKGROUND, XTERM_BG( 47), sizeof(XTERM_BG( 47))-1, T(COLOR_BG_00FF5A), 3, T("%X<#00FF5A>"), 11},
{ CS_BG( 48), CS_BACKGROUND, XTERM_BG( 48), sizeof(XTERM_BG( 48))-1, T(COLOR_BG_00FF87), 3, T("%X<#00FF87>"), 11},
{ CS_BG( 49), CS_BACKGROUND, XTERM_BG( 49), sizeof(XTERM_BG( 49))-1, T(COLOR_BG_00FFAF), 3, T("%X<#00FFAF>"), 11},
{ CS_BG( 50), CS_BACKGROUND, XTERM_BG( 50), sizeof(XTERM_BG( 50))-1, T(COLOR_BG_00FFD7), 3, T("%X<#00FFD7>"), 11},
{ CS_BG( 51), CS_BACKGROUND, XTERM_BG( 51), sizeof(XTERM_BG( 51))-1, T(COLOR_BG_00FFFF), 3, T("%X<#00FFFF>"), 11},
{ CS_BG( 52), CS_BACKGROUND, XTERM_BG( 52), sizeof(XTERM_BG( 52))-1, T(COLOR_BG_5F0000), 3, T("%X<#5F0000>"), 11},
{ CS_BG( 53), CS_BACKGROUND, XTERM_BG( 53), sizeof(XTERM_BG( 53))-1, T(COLOR_BG_5F005F), 3, T("%X<#5F005F>"), 11},
{ CS_BG( 54), CS_BACKGROUND, XTERM_BG( 54), sizeof(XTERM_BG( 54))-1, T(COLOR_BG_5F0087), 3, T("%X<#5F0087>"), 11},
{ CS_BG( 55), CS_BACKGROUND, XTERM_BG( 55), sizeof(XTERM_BG( 55))-1, T(COLOR_BG_5F00AF), 3, T("%X<#5F00AF>"), 11},
{ CS_BG( 56), CS_BACKGROUND, XTERM_BG( 56), sizeof(XTERM_BG( 56))-1, T(COLOR_BG_5F00D7), 3, T("%X<#5F00D7>"), 11},
{ CS_BG( 57), CS_BACKGROUND, XTERM_BG( 57), sizeof(XTERM_BG( 57))-1, T(COLOR_BG_5F00FF), 3, T("%X<#5F00FF>"), 11},
{ CS_BG( 58), CS_BACKGROUND, XTERM_BG( 58), sizeof(XTERM_BG( 58))-1, T(COLOR_BG_5F5F00), 3, T("%X<#5F5F00>"), 11},
{ CS_BG( 59), CS_BACKGROUND, XTERM_BG( 59), sizeof(XTERM_BG( 59))-1, T(COLOR_BG_5F5F5F), 3, T("%X<#5F5F5F>"), 11},
{ CS_BG( 60), CS_BACKGROUND, XTERM_BG( 60), sizeof(XTERM_BG( 60))-1, T(COLOR_BG_5F5F87), 3, T("%X<#5F5F87>"), 11},
{ CS_BG( 61), CS_BACKGROUND, XTERM_BG( 61), sizeof(XTERM_BG( 61))-1, T(COLOR_BG_5F5FAF), 3, T("%X<#5F5FAF>"), 11},
{ CS_BG( 62), CS_BACKGROUND, XTERM_BG( 62), sizeof(XTERM_BG( 62))-1, T(COLOR_BG_5F5FD7), 3, T("%X<#5F5FD7>"), 11},
{ CS_BG( 63), CS_BACKGROUND, XTERM_BG( 63), sizeof(XTERM_BG( 63))-1, T(COLOR_BG_5F5FFF), 3, T("%X<#5F5FFF>"), 11},
{ CS_BG( 64), CS_BACKGROUND, XTERM_BG( 64), sizeof(XTERM_BG( 64))-1, T(COLOR_BG_5F8700), 3, T("%X<#5F8700>"), 11},
{ CS_BG( 65), CS_BACKGROUND, XTERM_BG( 65), sizeof(XTERM_BG( 65))-1, T(COLOR_BG_5F875F), 3, T("%X<#5F875F>"), 11},
{ CS_BG( 66), CS_BACKGROUND, XTERM_BG( 66), sizeof(XTERM_BG( 66))-1, T(COLOR_BG_5F8787), 3, T("%X<#5F8787>"), 11},
{ CS_BG( 67), CS_BACKGROUND, XTERM_BG( 67), sizeof(XTERM_BG( 67))-1, T(COLOR_BG_5F87AF), 3, T("%X<#5F87AF>"), 11},
{ CS_BG( 68), CS_BACKGROUND, XTERM_BG( 68), sizeof(XTERM_BG( 68))-1, T(COLOR_BG_5F87D7), 3, T("%X<#5F87D7>"), 11},
{ CS_BG( 69), CS_BACKGROUND, XTERM_BG( 69), sizeof(XTERM_BG( 69))-1, T(COLOR_BG_5F87FF), 3, T("%X<#5F87FF>"), 11},
{ CS_BG( 70), CS_BACKGROUND, XTERM_BG( 70), sizeof(XTERM_BG( 70))-1, T(COLOR_BG_5FAF00), 3, T("%X<#5FAF00>"), 11},
{ CS_BG( 71), CS_BACKGROUND, XTERM_BG( 71), sizeof(XTERM_BG( 71))-1, T(COLOR_BG_5FAF5F), 3, T("%X<#5FAF5F>"), 11},
{ CS_BG( 72), CS_BACKGROUND, XTERM_BG( 72), sizeof(XTERM_BG( 72))-1, T(COLOR_BG_5FAF87), 3, T("%X<#5FAF87>"), 11},
{ CS_BG( 73), CS_BACKGROUND, XTERM_BG( 73), sizeof(XTERM_BG( 73))-1, T(COLOR_BG_5FAFAF), 3, T("%X<#5FAFAF>"), 11},
{ CS_BG( 74), CS_BACKGROUND, XTERM_BG( 74), sizeof(XTERM_BG( 74))-1, T(COLOR_BG_5FAFD7), 3, T("%X<#5FAFD7>"), 11},
{ CS_BG( 75), CS_BACKGROUND, XTERM_BG( 75), sizeof(XTERM_BG( 75))-1, T(COLOR_BG_5FAFFF), 3, T("%X<#5FAFFF>"), 11},
{ CS_BG( 76), CS_BACKGROUND, XTERM_BG( 76), sizeof(XTERM_BG( 76))-1, T(COLOR_BG_5FD700), 3, T("%X<#5FD700>"), 11},
{ CS_BG( 77), CS_BACKGROUND, XTERM_BG( 77), sizeof(XTERM_BG( 77))-1, T(COLOR_BG_5FD75F), 3, T("%X<#5FD75F>"), 11},
{ CS_BG( 78), CS_BACKGROUND, XTERM_BG( 78), sizeof(XTERM_BG( 78))-1, T(COLOR_BG_5FD787), 3, T("%X<#5FD787>"), 11},
{ CS_BG( 79), CS_BACKGROUND, XTERM_BG( 79), sizeof(XTERM_BG( 79))-1, T(COLOR_BG_5FD7AF), 3, T("%X<#5FD7AF>"), 11},
{ CS_BG( 80), CS_BACKGROUND, XTERM_BG( 80), sizeof(XTERM_BG( 80))-1, T(COLOR_BG_5FD7D7), 3, T("%X<#5FD7D7>"), 11},
{ CS_BG( 81), CS_BACKGROUND, XTERM_BG( 81), sizeof(XTERM_BG( 81))-1, T(COLOR_BG_5FD7FF), 3, T("%X<#5FD7FF>"), 11},
{ CS_BG( 82), CS_BACKGROUND, XTERM_BG( 82), sizeof(XTERM_BG( 82))-1, T(COLOR_BG_5FFF00), 3, T("%X<#5FFF00>"), 11},
{ CS_BG( 83), CS_BACKGROUND, XTERM_BG( 83), sizeof(XTERM_BG( 83))-1, T(COLOR_BG_5FFF5F), 3, T("%X<#5FFF5F>"), 11},
{ CS_BG( 84), CS_BACKGROUND, XTERM_BG( 84), sizeof(XTERM_BG( 84))-1, T(COLOR_BG_5FFF87), 3, T("%X<#5FFF87>"), 11},
{ CS_BG( 85), CS_BACKGROUND, XTERM_BG( 85), sizeof(XTERM_BG( 85))-1, T(COLOR_BG_5FFFAF), 3, T("%X<#5FFFAF>"), 11},
{ CS_BG( 86), CS_BACKGROUND, XTERM_BG( 86), sizeof(XTERM_BG( 86))-1, T(COLOR_BG_5FFFD7), 3, T("%X<#5FFFD7>"), 11},
{ CS_BG( 87), CS_BACKGROUND, XTERM_BG( 87), sizeof(XTERM_BG( 87))-1, T(COLOR_BG_5FFFFF), 3, T("%X<#5FFFFF>"), 11},
{ CS_BG( 88), CS_BACKGROUND, XTERM_BG( 88), sizeof(XTERM_BG( 88))-1, T(COLOR_BG_870000), 3, T("%X<#870000>"), 11},
{ CS_BG( 89), CS_BACKGROUND, XTERM_BG( 89), sizeof(XTERM_BG( 89))-1, T(COLOR_BG_87005F), 3, T("%X<#87005F>"), 11},
{ CS_BG( 90), CS_BACKGROUND, XTERM_BG( 90), sizeof(XTERM_BG( 90))-1, T(COLOR_BG_870087), 3, T("%X<#870087>"), 11},
{ CS_BG( 91), CS_BACKGROUND, XTERM_BG( 91), sizeof(XTERM_BG( 91))-1, T(COLOR_BG_8700AF), 3, T("%X<#8700AF>"), 11},
{ CS_BG( 92), CS_BACKGROUND, XTERM_BG( 92), sizeof(XTERM_BG( 92))-1, T(COLOR_BG_8700D7), 3, T("%X<#8700D7>"), 11},
{ CS_BG( 93), CS_BACKGROUND, XTERM_BG( 93), sizeof(XTERM_BG( 93))-1, T(COLOR_BG_8700FF), 3, T("%X<#8700FF>"), 11},
{ CS_BG( 94), CS_BACKGROUND, XTERM_BG( 94), sizeof(XTERM_BG( 94))-1, T(COLOR_BG_875F00), 3, T("%X<#875F00>"), 11},
{ CS_BG( 95), CS_BACKGROUND, XTERM_BG( 95), sizeof(XTERM_BG( 95))-1, T(COLOR_BG_875F5F), 3, T("%X<#875F5F>"), 11},
{ CS_BG( 96), CS_BACKGROUND, XTERM_BG( 96), sizeof(XTERM_BG( 96))-1, T(COLOR_BG_875F87), 3, T("%X<#875F87>"), 11},
{ CS_BG( 97), CS_BACKGROUND, XTERM_BG( 97), sizeof(XTERM_BG( 97))-1, T(COLOR_BG_875FAF), 3, T("%X<#875FAF>"), 11},
{ CS_BG( 98), CS_BACKGROUND, XTERM_BG( 98), sizeof(XTERM_BG( 98))-1, T(COLOR_BG_875FD7), 3, T("%X<#875FD7>"), 11},
{ CS_BG( 99), CS_BACKGROUND, XTERM_BG( 99), sizeof(XTERM_BG( 99))-1, T(COLOR_BG_875FFF), 3, T("%X<#875FFF>"), 11},
{ CS_BG(100), CS_BACKGROUND, XTERM_BG(100), sizeof(XTERM_BG(100))-1, T(COLOR_BG_878700), 3, T("%X<#878700>"), 11},
{ CS_BG(101), CS_BACKGROUND, XTERM_BG(101), sizeof(XTERM_BG(101))-1, T(COLOR_BG_87875F), 3, T("%X<#87875F>"), 11},
{ CS_BG(102), CS_BACKGROUND, XTERM_BG(102), sizeof(XTERM_BG(102))-1, T(COLOR_BG_878787), 3, T("%X<#878787>"), 11},
{ CS_BG(103), CS_BACKGROUND, XTERM_BG(103), sizeof(XTERM_BG(103))-1, T(COLOR_BG_8787AF), 3, T("%X<#8787AF>"), 11},
{ CS_BG(104), CS_BACKGROUND, XTERM_BG(104), sizeof(XTERM_BG(104))-1, T(COLOR_BG_8787D7), 3, T("%X<#8787D7>"), 11},
{ CS_BG(105), CS_BACKGROUND, XTERM_BG(105), sizeof(XTERM_BG(105))-1, T(COLOR_BG_8787FF), 3, T("%X<#8787FF>"), 11},
{ CS_BG(106), CS_BACKGROUND, XTERM_BG(106), sizeof(XTERM_BG(106))-1, T(COLOR_BG_87AF00), 3, T("%X<#87AF00>"), 11},
{ CS_BG(107), CS_BACKGROUND, XTERM_BG(107), sizeof(XTERM_BG(107))-1, T(COLOR_BG_87AF5F), 3, T("%X<#87AF5F>"), 11},
{ CS_BG(108), CS_BACKGROUND, XTERM_BG(108), sizeof(XTERM_BG(108))-1, T(COLOR_BG_87AF87), 3, T("%X<#87AF87>"), 11},
{ CS_BG(109), CS_BACKGROUND, XTERM_BG(109), sizeof(XTERM_BG(109))-1, T(COLOR_BG_87AFAF), 3, T("%X<#87AFAF>"), 11},
{ CS_BG(110), CS_BACKGROUND, XTERM_BG(110), sizeof(XTERM_BG(110))-1, T(COLOR_BG_87AFD7), 3, T("%X<#87AFD7>"), 11},
{ CS_BG(111), CS_BACKGROUND, XTERM_BG(111), sizeof(XTERM_BG(111))-1, T(COLOR_BG_87AFFF), 3, T("%X<#87AFFF>"), 11},
{ CS_BG(112), CS_BACKGROUND, XTERM_BG(112), sizeof(XTERM_BG(112))-1, T(COLOR_BG_87D700), 3, T("%X<#87D700>"), 11},
{ CS_BG(113), CS_BACKGROUND, XTERM_BG(113), sizeof(XTERM_BG(113))-1, T(COLOR_BG_87D75A), 3, T("%X<#87D75A>"), 11},
{ CS_BG(114), CS_BACKGROUND, XTERM_BG(114), sizeof(XTERM_BG(114))-1, T(COLOR_BG_87D787), 3, T("%X<#87D787>"), 11},
{ CS_BG(115), CS_BACKGROUND, XTERM_BG(115), sizeof(XTERM_BG(115))-1, T(COLOR_BG_87D7AF), 3, T("%X<#87D7AF>"), 11},
{ CS_BG(116), CS_BACKGROUND, XTERM_BG(116), sizeof(XTERM_BG(116))-1, T(COLOR_BG_87D7D7), 3, T("%X<#87D7D7>"), 11},
{ CS_BG(117), CS_BACKGROUND, XTERM_BG(117), sizeof(XTERM_BG(117))-1, T(COLOR_BG_87D7FF), 3, T("%X<#87D7FF>"), 11},
{ CS_BG(118), CS_BACKGROUND, XTERM_BG(118), sizeof(XTERM_BG(118))-1, T(COLOR_BG_87FF00), 3, T("%X<#87FF00>"), 11},
{ CS_BG(119), CS_BACKGROUND, XTERM_BG(119), sizeof(XTERM_BG(119))-1, T(COLOR_BG_87FF5F), 3, T("%X<#87FF5F>"), 11},
{ CS_BG(120), CS_BACKGROUND, XTERM_BG(120), sizeof(XTERM_BG(120))-1, T(COLOR_BG_87FF87), 3, T("%X<#87FF87>"), 11},
{ CS_BG(121), CS_BACKGROUND, XTERM_BG(121), sizeof(XTERM_BG(121))-1, T(COLOR_BG_87FFAF), 3, T("%X<#87FFAF>"), 11},
{ CS_BG(122), CS_BACKGROUND, XTERM_BG(122), sizeof(XTERM_BG(122))-1, T(COLOR_BG_87FFD7), 3, T("%X<#87FFD7>"), 11},
{ CS_BG(123), CS_BACKGROUND, XTERM_BG(123), sizeof(XTERM_BG(123))-1, T(COLOR_BG_87FFFF), 3, T("%X<#87FFFF>"), 11},
{ CS_BG(124), CS_BACKGROUND, XTERM_BG(124), sizeof(XTERM_BG(124))-1, T(COLOR_BG_AF0000), 3, T("%X<#AF0000>"), 11},
{ CS_BG(125), CS_BACKGROUND, XTERM_BG(125), sizeof(XTERM_BG(125))-1, T(COLOR_BG_AF005F), 3, T("%X<#AF005F>"), 11},
{ CS_BG(126), CS_BACKGROUND, XTERM_BG(126), sizeof(XTERM_BG(126))-1, T(COLOR_BG_AF0087), 3, T("%X<#AF0087>"), 11},
{ CS_BG(127), CS_BACKGROUND, XTERM_BG(127), sizeof(XTERM_BG(127))-1, T(COLOR_BG_AF00AF), 3, T("%X<#AF00AF>"), 11},
{ CS_BG(128), CS_BACKGROUND, XTERM_BG(128), sizeof(XTERM_BG(128))-1, T(COLOR_BG_AF00D7), 3, T("%X<#AF00D7>"), 11},
{ CS_BG(129), CS_BACKGROUND, XTERM_BG(129), sizeof(XTERM_BG(129))-1, T(COLOR_BG_AF00FF), 3, T("%X<#AF00FF>"), 11},
{ CS_BG(130), CS_BACKGROUND, XTERM_BG(130), sizeof(XTERM_BG(130))-1, T(COLOR_BG_AF5F00), 3, T("%X<#AF5F00>"), 11},
{ CS_BG(131), CS_BACKGROUND, XTERM_BG(131), sizeof(XTERM_BG(131))-1, T(COLOR_BG_AF5F5F), 3, T("%X<#AF5F5F>"), 11},
{ CS_BG(132), CS_BACKGROUND, XTERM_BG(132), sizeof(XTERM_BG(132))-1, T(COLOR_BG_AF5F87), 3, T("%X<#AF5F87>"), 11},
{ CS_BG(133), CS_BACKGROUND, XTERM_BG(133), sizeof(XTERM_BG(133))-1, T(COLOR_BG_AF5FAF), 3, T("%X<#AF5FAF>"), 11},
{ CS_BG(134), CS_BACKGROUND, XTERM_BG(134), sizeof(XTERM_BG(134))-1, T(COLOR_BG_AF5FD7), 3, T("%X<#AF5FD7>"), 11},
{ CS_BG(135), CS_BACKGROUND, XTERM_BG(135), sizeof(XTERM_BG(135))-1, T(COLOR_BG_AF5FFF), 3, T("%X<#AF5FFF>"), 11},
{ CS_BG(136), CS_BACKGROUND, XTERM_BG(136), sizeof(XTERM_BG(136))-1, T(COLOR_BG_AF8700), 3, T("%X<#AF8700>"), 11},
{ CS_BG(137), CS_BACKGROUND, XTERM_BG(137), sizeof(XTERM_BG(137))-1, T(COLOR_BG_AF875F), 3, T("%X<#AF875F>"), 11},
{ CS_BG(138), CS_BACKGROUND, XTERM_BG(138), sizeof(XTERM_BG(138))-1, T(COLOR_BG_AF8787), 3, T("%X<#AF8787>"), 11},
{ CS_BG(139), CS_BACKGROUND, XTERM_BG(139), sizeof(XTERM_BG(139))-1, T(COLOR_BG_AF87AF), 3, T("%X<#AF87AF>"), 11},
{ CS_BG(140), CS_BACKGROUND, XTERM_BG(140), sizeof(XTERM_BG(140))-1, T(COLOR_BG_AF87D7), 3, T("%X<#AF87D7>"), 11},
{ CS_BG(141), CS_BACKGROUND, XTERM_BG(141), sizeof(XTERM_BG(141))-1, T(COLOR_BG_AF87FF), 3, T("%X<#AF87FF>"), 11},
{ CS_BG(142), CS_BACKGROUND, XTERM_BG(142), sizeof(XTERM_BG(142))-1, T(COLOR_BG_AFAF00), 3, T("%X<#AFAF00>"), 11},
{ CS_BG(143), CS_BACKGROUND, XTERM_BG(143), sizeof(XTERM_BG(143))-1, T(COLOR_BG_AFAF5F), 3, T("%X<#AFAF5F>"), 11},
{ CS_BG(144), CS_BACKGROUND, XTERM_BG(144), sizeof(XTERM_BG(144))-1, T(COLOR_BG_AFAF87), 3, T("%X<#AFAF87>"), 11},
{ CS_BG(145), CS_BACKGROUND, XTERM_BG(145), sizeof(XTERM_BG(145))-1, T(COLOR_BG_AFAFAF), 3, T("%X<#AFAFAF>"), 11},
{ CS_BG(146), CS_BACKGROUND, XTERM_BG(146), sizeof(XTERM_BG(146))-1, T(COLOR_BG_AFAFD7), 3, T("%X<#AFAFD7>"), 11},
{ CS_BG(147), CS_BACKGROUND, XTERM_BG(147), sizeof(XTERM_BG(147))-1, T(COLOR_BG_AFAFFF), 3, T("%X<#AFAFFF>"), 11},
{ CS_BG(148), CS_BACKGROUND, XTERM_BG(148), sizeof(XTERM_BG(148))-1, T(COLOR_BG_AFD700), 3, T("%X<#AFD700>"), 11},
{ CS_BG(149), CS_BACKGROUND, XTERM_BG(149), sizeof(XTERM_BG(149))-1, T(COLOR_BG_AFD75F), 3, T("%X<#AFD75F>"), 11},
{ CS_BG(150), CS_BACKGROUND, XTERM_BG(150), sizeof(XTERM_BG(150))-1, T(COLOR_BG_AFD787), 3, T("%X<#AFD787>"), 11},
{ CS_BG(151), CS_BACKGROUND, XTERM_BG(151), sizeof(XTERM_BG(151))-1, T(COLOR_BG_AFD7AF), 3, T("%X<#AFD7AF>"), 11},
{ CS_BG(152), CS_BACKGROUND, XTERM_BG(152), sizeof(XTERM_BG(152))-1, T(COLOR_BG_AFD7D7), 3, T("%X<#AFD7D7>"), 11},
{ CS_BG(153), CS_BACKGROUND, XTERM_BG(153), sizeof(XTERM_BG(153))-1, T(COLOR_BG_AFD7FF), 3, T("%X<#AFD7FF>"), 11},
{ CS_BG(154), CS_BACKGROUND, XTERM_BG(154), sizeof(XTERM_BG(154))-1, T(COLOR_BG_AFFF00), 3, T("%X<#AFFF00>"), 11},
{ CS_BG(155), CS_BACKGROUND, XTERM_BG(155), sizeof(XTERM_BG(155))-1, T(COLOR_BG_AFFF5F), 3, T("%X<#AFFF5F>"), 11},
{ CS_BG(156), CS_BACKGROUND, XTERM_BG(156), sizeof(XTERM_BG(156))-1, T(COLOR_BG_AFFF87), 3, T("%X<#AFFF87>"), 11},
{ CS_BG(157), CS_BACKGROUND, XTERM_BG(157), sizeof(XTERM_BG(157))-1, T(COLOR_BG_AFFFAF), 3, T("%X<#AFFFAF>"), 11},
{ CS_BG(158), CS_BACKGROUND, XTERM_BG(158), sizeof(XTERM_BG(158))-1, T(COLOR_BG_AFFFD7), 3, T("%X<#AFFFD7>"), 11},
{ CS_BG(159), CS_BACKGROUND, XTERM_BG(159), sizeof(XTERM_BG(159))-1, T(COLOR_BG_AFFFFF), 3, T("%X<#AFFFFF>"), 11},
{ CS_BG(160), CS_BACKGROUND, XTERM_BG(160), sizeof(XTERM_BG(160))-1, T(COLOR_BG_D70000), 3, T("%X<#D70000>"), 11},
{ CS_BG(161), CS_BACKGROUND, XTERM_BG(161), sizeof(XTERM_BG(161))-1, T(COLOR_BG_D7005F), 3, T("%X<#D7005F>"), 11},
{ CS_BG(162), CS_BACKGROUND, XTERM_BG(162), sizeof(XTERM_BG(162))-1, T(COLOR_BG_D70087), 3, T("%X<#D70087>"), 11},
{ CS_BG(163), CS_BACKGROUND, XTERM_BG(163), sizeof(XTERM_BG(163))-1, T(COLOR_BG_D700AF), 3, T("%X<#D700AF>"), 11},
{ CS_BG(164), CS_BACKGROUND, XTERM_BG(164), sizeof(XTERM_BG(164))-1, T(COLOR_BG_D700D7), 3, T("%X<#D700D7>"), 11},
{ CS_BG(165), CS_BACKGROUND, XTERM_BG(165), sizeof(XTERM_BG(165))-1, T(COLOR_BG_D700FF), 3, T("%X<#D700FF>"), 11},
{ CS_BG(166), CS_BACKGROUND, XTERM_BG(166), sizeof(XTERM_BG(166))-1, T(COLOR_BG_D75F00), 3, T("%X<#D75F00>"), 11},
{ CS_BG(167), CS_BACKGROUND, XTERM_BG(167), sizeof(XTERM_BG(167))-1, T(COLOR_BG_D75F5F), 3, T("%X<#D75F5F>"), 11},
{ CS_BG(168), CS_BACKGROUND, XTERM_BG(168), sizeof(XTERM_BG(168))-1, T(COLOR_BG_D75F87), 3, T("%X<#D75F87>"), 11},
{ CS_BG(169), CS_BACKGROUND, XTERM_BG(169), sizeof(XTERM_BG(169))-1, T(COLOR_BG_D75FAF), 3, T("%X<#D75FAF>"), 11},
{ CS_BG(170), CS_BACKGROUND, XTERM_BG(170), sizeof(XTERM_BG(170))-1, T(COLOR_BG_D75FD7), 3, T("%X<#D75FD7>"), 11},
{ CS_BG(171), CS_BACKGROUND, XTERM_BG(171), sizeof(XTERM_BG(171))-1, T(COLOR_BG_D75FFF), 3, T("%X<#D75FFF>"), 11},
{ CS_BG(172), CS_BACKGROUND, XTERM_BG(172), sizeof(XTERM_BG(172))-1, T(COLOR_BG_D78700), 3, T("%X<#D78700>"), 11},
{ CS_BG(173), CS_BACKGROUND, XTERM_BG(173), sizeof(XTERM_BG(173))-1, T(COLOR_BG_D7875A), 3, T("%X<#D7875A>"), 11},
{ CS_BG(174), CS_BACKGROUND, XTERM_BG(174), sizeof(XTERM_BG(174))-1, T(COLOR_BG_D78787), 3, T("%X<#D78787>"), 11},
{ CS_BG(175), CS_BACKGROUND, XTERM_BG(175), sizeof(XTERM_BG(175))-1, T(COLOR_BG_D787AF), 3, T("%X<#D787AF>"), 11},
{ CS_BG(176), CS_BACKGROUND, XTERM_BG(176), sizeof(XTERM_BG(176))-1, T(COLOR_BG_D787D7), 3, T("%X<#D787D7>"), 11},
{ CS_BG(177), CS_BACKGROUND, XTERM_BG(177), sizeof(XTERM_BG(177))-1, T(COLOR_BG_D787FF), 3, T("%X<#D787FF>"), 11},
{ CS_BG(178), CS_BACKGROUND, XTERM_BG(178), sizeof(XTERM_BG(178))-1, T(COLOR_BG_D7AF00), 3, T("%X<#D7AF00>"), 11},
{ CS_BG(179), CS_BACKGROUND, XTERM_BG(179), sizeof(XTERM_BG(179))-1, T(COLOR_BG_D7AF5A), 3, T("%X<#D7AF5A>"), 11},
{ CS_BG(180), CS_BACKGROUND, XTERM_BG(180), sizeof(XTERM_BG(180))-1, T(COLOR_BG_D7AF87), 3, T("%X<#D7AF87>"), 11},
{ CS_BG(181), CS_BACKGROUND, XTERM_BG(181), sizeof(XTERM_BG(181))-1, T(COLOR_BG_D7AFAF), 3, T("%X<#D7AFAF>"), 11},
{ CS_BG(182), CS_BACKGROUND, XTERM_BG(182), sizeof(XTERM_BG(182))-1, T(COLOR_BG_D7AFD7), 3, T("%X<#D7AFD7>"), 11},
{ CS_BG(183), CS_BACKGROUND, XTERM_BG(183), sizeof(XTERM_BG(183))-1, T(COLOR_BG_D7AFFF), 3, T("%X<#D7AFFF>"), 11},
{ CS_BG(184), CS_BACKGROUND, XTERM_BG(184), sizeof(XTERM_BG(184))-1, T(COLOR_BG_D7D700), 3, T("%X<#D7D700>"), 11},
{ CS_BG(185), CS_BACKGROUND, XTERM_BG(185), sizeof(XTERM_BG(185))-1, T(COLOR_BG_D7D75F), 3, T("%X<#D7D75F>"), 11},
{ CS_BG(186), CS_BACKGROUND, XTERM_BG(186), sizeof(XTERM_BG(186))-1, T(COLOR_BG_D7D787), 3, T("%X<#D7D787>"), 11},
{ CS_BG(187), CS_BACKGROUND, XTERM_BG(187), sizeof(XTERM_BG(187))-1, T(COLOR_BG_D7D7AF), 3, T("%X<#D7D7AF>"), 11},
{ CS_BG(188), CS_BACKGROUND, XTERM_BG(188), sizeof(XTERM_BG(188))-1, T(COLOR_BG_D7D7D7), 3, T("%X<#D7D7D7>"), 11},
{ CS_BG(189), CS_BACKGROUND, XTERM_BG(189), sizeof(XTERM_BG(189))-1, T(COLOR_BG_D7D7FF), 3, T("%X<#D7D7FF>"), 11},
{ CS_BG(190), CS_BACKGROUND, XTERM_BG(190), sizeof(XTERM_BG(190))-1, T(COLOR_BG_D7FF00), 3, T("%X<#D7FF00>"), 11},
{ CS_BG(191), CS_BACKGROUND, XTERM_BG(191), sizeof(XTERM_BG(191))-1, T(COLOR_BG_D7FF5F), 3, T("%X<#D7FF5F>"), 11},
{ CS_BG(192), CS_BACKGROUND, XTERM_BG(192), sizeof(XTERM_BG(192))-1, T(COLOR_BG_D7FF87), 3, T("%X<#D7FF87>"), 11},
{ CS_BG(193), CS_BACKGROUND, XTERM_BG(193), sizeof(XTERM_BG(193))-1, T(COLOR_BG_D7FFAF), 3, T("%X<#D7FFAF>"), 11},
{ CS_BG(194), CS_BACKGROUND, XTERM_BG(194), sizeof(XTERM_BG(194))-1, T(COLOR_BG_D7FFD7), 3, T("%X<#D7FFD7>"), 11},
{ CS_BG(195), CS_BACKGROUND, XTERM_BG(195), sizeof(XTERM_BG(195))-1, T(COLOR_BG_D7FFFF), 3, T("%X<#D7FFFF>"), 11},
{ CS_BG(196), CS_BACKGROUND, XTERM_BG(196), sizeof(XTERM_BG(196))-1, T(COLOR_BG_FF0000), 3, T("%X<#FF0000>"), 11},
{ CS_BG(197), CS_BACKGROUND, XTERM_BG(197), sizeof(XTERM_BG(197))-1, T(COLOR_BG_FF005F), 3, T("%X<#FF005F>"), 11},
{ CS_BG(198), CS_BACKGROUND, XTERM_BG(198), sizeof(XTERM_BG(198))-1, T(COLOR_BG_FF0087), 3, T("%X<#FF0087>"), 11},
{ CS_BG(199), CS_BACKGROUND, XTERM_BG(199), sizeof(XTERM_BG(199))-1, T(COLOR_BG_FF00AF), 3, T("%X<#FF00AF>"), 11},
{ CS_BG(200), CS_BACKGROUND, XTERM_BG(200), sizeof(XTERM_BG(200))-1, T(COLOR_BG_FF00D7), 3, T("%X<#FF00D7>"), 11},
{ CS_BG(201), CS_BACKGROUND, XTERM_BG(201), sizeof(XTERM_BG(201))-1, T(COLOR_BG_FF00FF), 3, T("%X<#FF00FF>"), 11},
{ CS_BG(202), CS_BACKGROUND, XTERM_BG(202), sizeof(XTERM_BG(202))-1, T(COLOR_BG_FF5F00), 3, T("%X<#FF5F00>"), 11},
{ CS_BG(203), CS_BACKGROUND, XTERM_BG(203), sizeof(XTERM_BG(203))-1, T(COLOR_BG_FF5F5F), 3, T("%X<#FF5F5F>"), 11},
{ CS_BG(204), CS_BACKGROUND, XTERM_BG(204), sizeof(XTERM_BG(204))-1, T(COLOR_BG_FF5F87), 3, T("%X<#FF5F87>"), 11},
{ CS_BG(205), CS_BACKGROUND, XTERM_BG(205), sizeof(XTERM_BG(205))-1, T(COLOR_BG_FF5FAF), 3, T("%X<#FF5FAF>"), 11},
{ CS_BG(206), CS_BACKGROUND, XTERM_BG(206), sizeof(XTERM_BG(206))-1, T(COLOR_BG_FF5FD7), 3, T("%X<#FF5FD7>"), 11},
{ CS_BG(207), CS_BACKGROUND, XTERM_BG(207), sizeof(XTERM_BG(207))-1, T(COLOR_BG_FF5FFF), 3, T("%X<#FF5FFF>"), 11},
{ CS_BG(208), CS_BACKGROUND, XTERM_BG(208), sizeof(XTERM_BG(208))-1, T(COLOR_BG_FF8700), 3, T("%X<#FF8700>"), 11},
{ CS_BG(209), CS_BACKGROUND, XTERM_BG(209), sizeof(XTERM_BG(209))-1, T(COLOR_BG_FF875F), 3, T("%X<#FF875F>"), 11},
{ CS_BG(210), CS_BACKGROUND, XTERM_BG(210), sizeof(XTERM_BG(210))-1, T(COLOR_BG_FF8787), 3, T("%X<#FF8787>"), 11},
{ CS_BG(211), CS_BACKGROUND, XTERM_BG(211), sizeof(XTERM_BG(211))-1, T(COLOR_BG_FF87AF), 3, T("%X<#FF87AF>"), 11},
{ CS_BG(212), CS_BACKGROUND, XTERM_BG(212), sizeof(XTERM_BG(212))-1, T(COLOR_BG_FF87D7), 3, T("%X<#FF87D7>"), 11},
{ CS_BG(213), CS_BACKGROUND, XTERM_BG(213), sizeof(XTERM_BG(213))-1, T(COLOR_BG_FF87FF), 3, T("%X<#FF87FF>"), 11},
{ CS_BG(214), CS_BACKGROUND, XTERM_BG(214), sizeof(XTERM_BG(214))-1, T(COLOR_BG_FFAF00), 3, T("%X<#FFAF00>"), 11},
{ CS_BG(215), CS_BACKGROUND, XTERM_BG(215), sizeof(XTERM_BG(215))-1, T(COLOR_BG_FFAF5F), 3, T("%X<#FFAF5F>"), 11},
{ CS_BG(216), CS_BACKGROUND, XTERM_BG(216), sizeof(XTERM_BG(216))-1, T(COLOR_BG_FFAF87), 3, T("%X<#FFAF87>"), 11},
{ CS_BG(217), CS_BACKGROUND, XTERM_BG(217), sizeof(XTERM_BG(217))-1, T(COLOR_BG_FFAFAF), 3, T("%X<#FFAFAF>"), 11},
{ CS_BG(218), CS_BACKGROUND, XTERM_BG(218), sizeof(XTERM_BG(218))-1, T(COLOR_BG_FFAFD7), 3, T("%X<#FFAFD7>"), 11},
{ CS_BG(219), CS_BACKGROUND, XTERM_BG(219), sizeof(XTERM_BG(219))-1, T(COLOR_BG_FFAFFF), 3, T("%X<#FFAFFF>"), 11},
{ CS_BG(220), CS_BACKGROUND, XTERM_BG(220), sizeof(XTERM_BG(220))-1, T(COLOR_BG_FFD700), 3, T("%X<#FFD700>"), 11},
{ CS_BG(221), CS_BACKGROUND, XTERM_BG(221), sizeof(XTERM_BG(221))-1, T(COLOR_BG_FFD75F), 3, T("%X<#FFD75F>"), 11},
{ CS_BG(222), CS_BACKGROUND, XTERM_BG(222), sizeof(XTERM_BG(222))-1, T(COLOR_BG_FFD787), 3, T("%X<#FFD787>"), 11},
{ CS_BG(223), CS_BACKGROUND, XTERM_BG(223), sizeof(XTERM_BG(223))-1, T(COLOR_BG_FFD7AF), 3, T("%X<#FFD7AF>"), 11},
{ CS_BG(224), CS_BACKGROUND, XTERM_BG(224), sizeof(XTERM_BG(224))-1, T(COLOR_BG_FFD7D7), 3, T("%X<#FFD7D7>"), 11},
{ CS_BG(225), CS_BACKGROUND, XTERM_BG(225), sizeof(XTERM_BG(225))-1, T(COLOR_BG_FFD7FF), 3, T("%X<#FFD7FF>"), 11},
{ CS_BG(226), CS_BACKGROUND, XTERM_BG(226), sizeof(XTERM_BG(226))-1, T(COLOR_BG_FFFF00), 3, T("%X<#FFFF00>"), 11},
{ CS_BG(227), CS_BACKGROUND, XTERM_BG(227), sizeof(XTERM_BG(227))-1, T(COLOR_BG_FFFF5F), 3, T("%X<#FFFF5F>"), 11},
{ CS_BG(228), CS_BACKGROUND, XTERM_BG(228), sizeof(XTERM_BG(228))-1, T(COLOR_BG_FFFF87), 3, T("%X<#FFFF87>"), 11},
{ CS_BG(229), CS_BACKGROUND, XTERM_BG(229), sizeof(XTERM_BG(229))-1, T(COLOR_BG_FFFFAF), 3, T("%X<#FFFFAF>"), 11},
{ CS_BG(230), CS_BACKGROUND, XTERM_BG(230), sizeof(XTERM_BG(230))-1, T(COLOR_BG_FFFFD7), 3, T("%X<#FFFFD7>"), 11},
{ CS_BG(231), CS_BACKGROUND, XTERM_BG(231), sizeof(XTERM_BG(231))-1, T(COLOR_BG_FFFFFF_2),3, T("%X<#FFFFFF>"), 11},
{ CS_BG(232), CS_BACKGROUND, XTERM_BG(232), sizeof(XTERM_BG(232))-1, T(COLOR_BG_080808), 3, T("%X<#080808>"), 11},
{ CS_BG(233), CS_BACKGROUND, XTERM_BG(233), sizeof(XTERM_BG(233))-1, T(COLOR_BG_121212), 3, T("%X<#121212>"), 11},
{ CS_BG(234), CS_BACKGROUND, XTERM_BG(234), sizeof(XTERM_BG(234))-1, T(COLOR_BG_1C1C1C), 3, T("%X<#1C1C1C>"), 11},
{ CS_BG(235), CS_BACKGROUND, XTERM_BG(235), sizeof(XTERM_BG(235))-1, T(COLOR_BG_262626), 3, T("%X<#262626>"), 11},
{ CS_BG(236), CS_BACKGROUND, XTERM_BG(236), sizeof(XTERM_BG(236))-1, T(COLOR_BG_303030), 3, T("%X<#303030>"), 11},
{ CS_BG(237), CS_BACKGROUND, XTERM_BG(237), sizeof(XTERM_BG(237))-1, T(COLOR_BG_3A3A3A), 3, T("%X<#3A3A3A>"), 11},
{ CS_BG(238), CS_BACKGROUND, XTERM_BG(238), sizeof(XTERM_BG(238))-1, T(COLOR_BG_444444), 3, T("%X<#444444>"), 11},
{ CS_BG(239), CS_BACKGROUND, XTERM_BG(239), sizeof(XTERM_BG(239))-1, T(COLOR_BG_4E4E4E), 3, T("%X<#4E4E4E>"), 11},
{ CS_BG(240), CS_BACKGROUND, XTERM_BG(240), sizeof(XTERM_BG(240))-1, T(COLOR_BG_585858), 3, T("%X<#585858>"), 11},
{ CS_BG(241), CS_BACKGROUND, XTERM_BG(241), sizeof(XTERM_BG(241))-1, T(COLOR_BG_626262), 3, T("%X<#626262>"), 11},
{ CS_BG(242), CS_BACKGROUND, XTERM_BG(242), sizeof(XTERM_BG(242))-1, T(COLOR_BG_6C6C6C), 3, T("%X<#6C6C6C>"), 11},
{ CS_BG(243), CS_BACKGROUND, XTERM_BG(243), sizeof(XTERM_BG(243))-1, T(COLOR_BG_767676), 3, T("%X<#767676>"), 11},
{ CS_BG(244), CS_BACKGROUND, XTERM_BG(244), sizeof(XTERM_BG(244))-1, T(COLOR_BG_808080), 3, T("%X<#808080>"), 11},
{ CS_BG(245), CS_BACKGROUND, XTERM_BG(245), sizeof(XTERM_BG(245))-1, T(COLOR_BG_8A8A8A), 3, T("%X<#8A8A8A>"), 11},
{ CS_BG(246), CS_BACKGROUND, XTERM_BG(246), sizeof(XTERM_BG(246))-1, T(COLOR_BG_949494), 3, T("%X<#949494>"), 11},
{ CS_BG(247), CS_BACKGROUND, XTERM_BG(247), sizeof(XTERM_BG(247))-1, T(COLOR_BG_9E9E9E), 3, T("%X<#9E9E9E>"), 11},
{ CS_BG(248), CS_BACKGROUND, XTERM_BG(248), sizeof(XTERM_BG(248))-1, T(COLOR_BG_A8A8A8), 3, T("%X<#A8A8A8>"), 11},
{ CS_BG(249), CS_BACKGROUND, XTERM_BG(249), sizeof(XTERM_BG(249))-1, T(COLOR_BG_B2B2B2), 3, T("%X<#B2B2B2>"), 11},
{ CS_BG(250), CS_BACKGROUND, XTERM_BG(250), sizeof(XTERM_BG(250))-1, T(COLOR_BG_BCBCBC), 3, T("%X<#BCBCBC>"), 11},
{ CS_BG(251), CS_BACKGROUND, XTERM_BG(251), sizeof(XTERM_BG(251))-1, T(COLOR_BG_C6C6C6), 3, T("%X<#C6C6C6>"), 11},
{ CS_BG(252), CS_BACKGROUND, XTERM_BG(252), sizeof(XTERM_BG(252))-1, T(COLOR_BG_D0D0D0), 3, T("%X<#D0D0D0>"), 11},
{ CS_BG(253), CS_BACKGROUND, XTERM_BG(253), sizeof(XTERM_BG(253))-1, T(COLOR_BG_DADADA), 3, T("%X<#DADADA>"), 11},
{ CS_BG(254), CS_BACKGROUND, XTERM_BG(254), sizeof(XTERM_BG(254))-1, T(COLOR_BG_E4E4E4), 3, T("%X<#E4E4E4>"), 11},
{ CS_BG(255), CS_BACKGROUND, XTERM_BG(255), sizeof(XTERM_BG(255))-1, T(COLOR_BG_EEEEEE), 3, T("%X<#EEEEEE>"), 11},
};
/*! \brief Validate ColorState.
*
* Checks (with assertions) that the given ColorState is valid. This is
* useful during development and debugging, but if any of the assertions are
* false, the process ends.
*
* \param cs ColorState.
* \return None.
*/
inline void ValidateColorState(ColorState cs)
{
const ColorState Mask = static_cast<ColorState>(~(CS_FOREGROUND|CS_BACKGROUND|CS_ATTRS));
mux_assert((Mask & cs) == 0);
mux_assert((CS_FOREGROUND & cs) <= CS_FG_DEFAULT);
mux_assert((CS_BACKGROUND & cs) <= CS_BG_DEFAULT);
}
inline ColorState UpdateColorState(ColorState cs, int iColorCode, const UTF8 *pRaw = nullptr)
{
mux_assert(0 <= iColorCode && iColorCode <= COLOR_INDEX_LAST);
if (COLOR_INDEX_FG_24_CP1 <= iColorCode)
{
// 24-bit color: 2-code-point encoding.
// CP1 carries R high nibble + G, CP2 carries R low nibble + B.
// pRaw points to the 4-byte UTF-8 sequence: F3 Bx xx xx.
//
mux_assert(pRaw != nullptr);
unsigned int payload = mux_color_smp_payload(pRaw);
unsigned int hi = payload >> 8; // 4-bit nibble (CP1) or nibble (CP2)
unsigned int lo = payload & 0xFF; // G (CP1) or B (CP2)
switch (iColorCode)
{
case COLOR_INDEX_FG_24_CP1:
if (CS_FG_INDEXED & cs)
{
cs = (cs & ~CS_FOREGROUND) | rgb2cs(&palette[CS_FG_FIELD_INDEXED(cs)].rgb);
}
cs = (cs & ~CS_FOREGROUND_RED) | (static_cast<ColorState>(hi << 4) << 16);
cs = (cs & ~CS_FOREGROUND_GREEN) | (static_cast<ColorState>(lo) << 8);
break;
case COLOR_INDEX_FG_24_CP2:
if (CS_FG_INDEXED & cs)
{
cs = (cs & ~CS_FOREGROUND) | rgb2cs(&palette[CS_FG_FIELD_INDEXED(cs)].rgb);
}
{
ColorState red = (cs >> 16) & 0xF0;
cs = (cs & ~CS_FOREGROUND_RED) | ((red | hi) << 16);
}
cs = (cs & ~CS_FOREGROUND_BLUE) | static_cast<ColorState>(lo);
break;
case COLOR_INDEX_BG_24_CP1:
if (CS_BG_INDEXED & cs)
{
cs = (cs & ~CS_BACKGROUND) | (rgb2cs(&palette[CS_BG_FIELD_INDEXED(cs)].rgb) << 32);
}
cs = (cs & ~CS_BACKGROUND_RED) | (static_cast<ColorState>(hi << 4) << 48);
cs = (cs & ~CS_BACKGROUND_GREEN) | (static_cast<ColorState>(lo) << 40);
break;
case COLOR_INDEX_BG_24_CP2:
if (CS_BG_INDEXED & cs)
{
cs = (cs & ~CS_BACKGROUND) | (rgb2cs(&palette[CS_BG_FIELD_INDEXED(cs)].rgb) << 32);
}
{
ColorState red = (cs >> 48) & 0xF0;
cs = (cs & ~CS_BACKGROUND_RED) | ((red | hi) << 48);
}
cs = (cs & ~CS_BACKGROUND_BLUE) | (static_cast<ColorState>(lo) << 32);
break;
}
mux_assert((cs & ~CS_ALLBITS) == 0);
return cs;
}
mux_assert(iColorCode < sizeof(aColors)/sizeof(aColors[0]));
return (cs & ~aColors[iColorCode].csMask) | aColors[iColorCode].cs;
}
// Maximum binary transition length is:
//
// COLOR_RESET "\xEF\x94\x80"
// + COLOR_INTENSE "\xEF\x94\x81"
// + COLOR_UNDERLINE "\xEF\x94\x84"
// + COLOR_BLINK "\xEF\x94\x85"
// + COLOR_INVERSE "\xEF\x94\x87"
// + COLOR_FG_RED "\xEF\x98\x81"
// + COLOR_BG_WHITE "\xEF\x9C\x87"
//
// Each of the seven codes is 3 bytes or 21 bytes total. Plus two 24-bit
// SMP code points per layer (4 bytes each), for FG and BG = 4 code points.
//
#define COLOR_MAXIMUM_BINARY_TRANSITION_LENGTH (21+4*4)
// Emit a 4-byte SMP PUA color code point.
// block: 0=FG CP1, 1=FG CP2, 2=BG CP1, 3=BG CP2
// payload: 12-bit value ((nibble << 8) | channel_byte)
//
static inline void EmitSMPColor(UTF8 *buf, unsigned int block, unsigned int payload)
{
buf[0] = 0xF3;
buf[1] = static_cast<UTF8>(0xB0 + block);
buf[2] = static_cast<UTF8>(0x80 | ((payload >> 6) & 0x3F));
buf[3] = static_cast<UTF8>(0x80 | (payload & 0x3F));
}
// Generate the minimal color sequence that will transition from one color state
// to another.
//
static UTF8 *ColorTransitionBinary
(
ColorState csCurrent,
ColorState csNext,
size_t *nTransition
)
{
ValidateColorState(csCurrent);
ValidateColorState(csNext);
static UTF8 Buffer[COLOR_MAXIMUM_BINARY_TRANSITION_LENGTH+1];
if (csCurrent == csNext)
{
*nTransition = 0;
Buffer[0] = '\0';
return Buffer;
}
size_t i = 0;
// Do we need to go through the normal state?
//
if ( ((csCurrent & ~csNext) & CS_ATTRS)
|| ( (csNext & CS_BACKGROUND) == CS_BG_DEFAULT
&& (csCurrent & CS_BACKGROUND) != CS_BG_DEFAULT)
|| ( (csNext & CS_FOREGROUND) == CS_FG_DEFAULT
&& (csCurrent & CS_FOREGROUND) != CS_FG_DEFAULT))
{
memcpy(Buffer + i, COLOR_RESET, sizeof(COLOR_RESET)-1);
i += sizeof(COLOR_RESET)-1;
csCurrent = CS_NORMAL;
}
ColorState tmp = csCurrent ^ csNext;
if (CS_ATTRS & tmp)
{
for (unsigned int iAttr = COLOR_INDEX_ATTR; iAttr < COLOR_INDEX_FG; iAttr++)
{
if (aColors[iAttr].cs == (aColors[iAttr].csMask & tmp))
{
memcpy(Buffer + i, aColors[iAttr].pUTF, aColors[iAttr].nUTF);
i += aColors[iAttr].nUTF;
}
}
}
RGB rgb;
unsigned int iColor;
if (CS_FOREGROUND & tmp)
{
bool fExact;
if (CS_FG_INDEXED & csNext)
{
iColor = static_cast<unsigned int>(CS_FG_FIELD(csNext));
fExact = true;
}
else
{
cs2rgb(CS_FG_FIELD(csNext), &rgb);
iColor = FindNearestPaletteEntry(rgb, true);
fExact = ( palette[iColor].rgb.r == rgb.r
&& palette[iColor].rgb.g == rgb.g
&& palette[iColor].rgb.b == rgb.b);
}
if (iColor < COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[COLOR_INDEX_FG + iColor].pUTF, aColors[COLOR_INDEX_FG + iColor].nUTF);
i += aColors[COLOR_INDEX_FG + iColor].nUTF;
if (!fExact)
{
// 2-code-point FG encoding: CP1 (block 0) + CP2 (block 1)
//
EmitSMPColor(Buffer + i, 0, ((rgb.r >> 4) << 8) | rgb.g);
i += 4;
EmitSMPColor(Buffer + i, 1, ((rgb.r & 0xF) << 8) | rgb.b);
i += 4;
}
}
}
if (CS_BACKGROUND & tmp)
{
bool fExact;
if (CS_BG_INDEXED & csNext)
{
iColor = static_cast<unsigned int>(CS_BG_FIELD(csNext));
fExact = true;
}
else
{
cs2rgb(CS_BG_FIELD(csNext), &rgb);
iColor = FindNearestPaletteEntry(rgb, true);
fExact = ( palette[iColor].rgb.r == rgb.r
&& palette[iColor].rgb.g == rgb.g
&& palette[iColor].rgb.b == rgb.b);
}
if (iColor < COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[COLOR_INDEX_BG + iColor].pUTF, aColors[COLOR_INDEX_BG + iColor].nUTF);
i += aColors[COLOR_INDEX_BG + iColor].nUTF;
if (!fExact)
{
// 2-code-point BG encoding: CP1 (block 2) + CP2 (block 3)
//
EmitSMPColor(Buffer + i, 2, ((rgb.r >> 4) << 8) | rgb.g);
i += 4;
EmitSMPColor(Buffer + i, 3, ((rgb.r & 0xF) << 8) | rgb.b);
i += 4;
}
}
}
Buffer[i] = '\0';
*nTransition = i;
return Buffer;
}
// Maximum binary transition to normal is:
//
// COLOR_RESET "\xEF\x94\x80"
//
// The code is 3 bytes.
//
#define COLOR_MAXIMUM_BINARY_NORMAL 3
// Generate the minimal color sequence that will transition from one color state
// to the normal state.
//
static const UTF8 *ColorBinaryNormal
(
ColorState csCurrent,
size_t *nTransition
)
{
ValidateColorState(csCurrent);
if (csCurrent == CS_NORMAL)
{
*nTransition = 0;
return T("");
}
else
{
*nTransition = sizeof(COLOR_RESET) - 1;
return T(COLOR_RESET);
}
}
// Maximum escape transition length is:
//
// COLOR_RESET "%xn"
// + COLOR_INTENSE "%xh"
// + COLOR_UNDERLINE "%xu"
// + COLOR_BLINK "%xf"
// + COLOR_INVERSE "%xi"
// + COLOR_FG_... "%x<#FFFFFF>"
// + COLOR_BG_... "%x<#FFFFFF>"
//
// Each of the five codes is 3 bytes, and two codes are 11 bytes, or 37 bytes total.
//
#define COLOR_MAXIMUM_ESCAPE_TRANSITION_LENGTH 37
// Generate the minimal color %-sequence that will transition from one color state
// to another.
//
static UTF8 *ColorTransitionEscape
(
ColorState csCurrent,
ColorState csNext,
size_t *nTransition
)
{
ValidateColorState(csCurrent);
ValidateColorState(csNext);
static UTF8 Buffer[COLOR_MAXIMUM_ESCAPE_TRANSITION_LENGTH+1];
if (csCurrent == csNext)
{
*nTransition = 0;
Buffer[0] = '\0';
return Buffer;
}
size_t i = 0;
// Do we need to go through the normal state?
//
if ( ((csCurrent & ~csNext) & CS_ATTRS)
|| ( (csNext & CS_BACKGROUND) == CS_BG_DEFAULT
&& (csCurrent & CS_BACKGROUND) != CS_BG_DEFAULT)
|| ( (csNext & CS_FOREGROUND) == CS_FG_DEFAULT
&& (csCurrent & CS_FOREGROUND) != CS_FG_DEFAULT))
{
memcpy(Buffer + i, aColors[COLOR_INDEX_RESET].pEscape, aColors[COLOR_INDEX_RESET].nEscape);
i += aColors[COLOR_INDEX_RESET].nEscape;
csCurrent = CS_NORMAL;
}
ColorState tmp = csCurrent ^ csNext;
if (CS_ATTRS & tmp)
{
for (unsigned int iAttr = COLOR_INDEX_ATTR; iAttr < COLOR_INDEX_FG; iAttr++)
{
if (aColors[iAttr].cs == (aColors[iAttr].csMask & tmp))
{
memcpy(Buffer + i, aColors[iAttr].pEscape, aColors[iAttr].nEscape);
i += aColors[iAttr].nEscape;
}
}
}
RGB rgb;
unsigned int iColor;
if (CS_FOREGROUND & tmp)
{
if (CS_FG_INDEXED & csNext)
{
iColor = COLOR_INDEX_FG + static_cast<unsigned int>(CS_FG_FIELD(csNext));
if (iColor < COLOR_INDEX_FG + COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[iColor].pEscape, aColors[iColor].nEscape);
i += aColors[iColor].nEscape;
}
}
else
{
cs2rgb(CS_FG_FIELD(csNext), &rgb);
mux_sprintf(Buffer + i, 12, T("%%x<#%02X%02X%02X>"), rgb.r, rgb.g, rgb.b);
i += 11;
}
}
if (CS_BACKGROUND & tmp)
{
if (CS_BG_INDEXED & csNext)
{
iColor = COLOR_INDEX_BG + static_cast<unsigned int>(CS_BG_FIELD(csNext));
if (iColor < COLOR_INDEX_BG + COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[iColor].pEscape, aColors[iColor].nEscape);
i += aColors[iColor].nEscape;
}
}
else
{
cs2rgb(CS_BG_FIELD(csNext), &rgb);
mux_sprintf(Buffer + i, 12, T("%%X<#%02X%02X%02X>"), rgb.r, rgb.g, rgb.b);
i += 11;
}
}
Buffer[i] = '\0';
*nTransition = i;
return Buffer;
}
// Maximum ANSI transition length is:
//
// ANSI_NORMAL "\033[0m"
// + ANSI_HILITE "\033[1m"
// + ANSI_UNDER "\033[4m"
// + ANSI_BLINK "\033[5m"
// + ANSI_INVERSE "\033[7m"
// + ANSI_FG_... "\033[38;5;255m"
// + ANSI_BWHITE "\033[48;5;255m"
//
// Five of the seven codes are 4 bytes, and two are 11 bytes, or 42 bytes total.
//
#define COLOR_MAXIMUM_ANSI_TRANSITION_LENGTH 42
// Generate the minimal ANSI sequence that will transition from one color state
// to another.
//
static UTF8 *ColorTransitionANSI
(
ColorState &csClient,
ColorState csNext,
size_t *nTransition,
bool fNoBleed,
bool fColor256
)
{
ValidateColorState(csClient);
ValidateColorState(csNext);
static UTF8 Buffer[COLOR_MAXIMUM_ANSI_TRANSITION_LENGTH+1];
// First, modify our sense of what 'normal' is.
//
if ( fNoBleed
&& (csNext & CS_FOREGROUND) == CS_FG_DEFAULT)
{
csNext = (csNext & ~CS_FOREGROUND) | CS_FG_WHITE;
}
// Approximate Foreground Color
//
RGB rgb;
unsigned int iColor;
if (fColor256)
{
if (CS_FG_INDEXED & csNext)
{
if (CS_FG_FIELD(csNext) < COLOR_INDEX_DEFAULT)
{
iColor = COLOR_INDEX_FG + static_cast<unsigned int>(CS_FG_FIELD(csNext));
}
else
{
iColor = COLOR_INDEX_FG + COLOR_INDEX_DEFAULT;
}
}
else
{
cs2rgb(CS_FG_FIELD(csNext), &rgb);
iColor = COLOR_INDEX_FG + FindNearestPaletteEntry(rgb, true);
}
}
else
{
if (CS_FG_INDEXED & csNext)
{
if (CS_FG_FIELD(csNext) < COLOR_INDEX_DEFAULT)
{
iColor = COLOR_INDEX_FG + palette[CS_FG_FIELD(csNext)].color16;
}
else
{
iColor = COLOR_INDEX_FG + COLOR_INDEX_DEFAULT;
}
}
else
{
cs2rgb(CS_FG_FIELD(csNext), &rgb);
iColor = COLOR_INDEX_FG + FindNearestPaletteEntry(rgb, false);
}
// For foreground 256-to-16-color down-conversion, we 'borrow' the
// highlite capability. We don't need or want it if the client supports
// 256-color, and there is no highlite capability we can borrow for
// background color. This decision is a prerequisite to the 'return
// to normal' decision below.
//
if (COLOR_INDEX_FG + 8 <= iColor && iColor <= COLOR_INDEX_FG + 15)
{
csNext |= CS_INTENSE;
iColor -= 8;
}
}
if (iColor < COLOR_INDEX_FG + COLOR_INDEX_DEFAULT)
{
csNext = UpdateColorState(csNext, iColor);
}
// Aproximate Background Color
//
if (fColor256)
{
if (CS_BG_INDEXED & csNext)
{
if (CS_BG_FIELD(csNext) < COLOR_INDEX_DEFAULT)
{
iColor = COLOR_INDEX_BG + static_cast<unsigned int>(CS_BG_FIELD(csNext));
}
else
{
iColor = COLOR_INDEX_BG + COLOR_INDEX_DEFAULT;
}
}
else
{
cs2rgb(CS_BG_FIELD(csNext), &rgb);
iColor = COLOR_INDEX_BG + FindNearestPaletteEntry(rgb, true);
}
}
else
{
if (CS_BG_INDEXED & csNext)
{
if (CS_BG_FIELD(csNext) < COLOR_INDEX_DEFAULT)
{
iColor = COLOR_INDEX_BG + palette[CS_BG_FIELD(csNext)].color8;
}
else
{
iColor = COLOR_INDEX_BG + COLOR_INDEX_DEFAULT;
}
}
else
{
cs2rgb(CS_BG_FIELD(csNext), &rgb);
iColor = COLOR_INDEX_BG + FindNearestPalette8Entry(rgb);
}
}
if (iColor < COLOR_INDEX_BG + COLOR_INDEX_DEFAULT)
{
csNext = UpdateColorState(csNext, iColor);
}
if (csClient == csNext)
{
*nTransition = 0;
Buffer[0] = '\0';
return Buffer;
}
size_t i = 0;
// Do we need to go through the normal state?
//
if ( ((csClient & ~csNext) & CS_ATTRS)
|| ( (csNext & CS_BACKGROUND) == CS_BG_DEFAULT
&& (csClient & CS_BACKGROUND) != CS_BG_DEFAULT)
|| ( (csNext & CS_FOREGROUND) == CS_FG_DEFAULT
&& (csClient & CS_FOREGROUND) != CS_FG_DEFAULT))
{
memcpy(Buffer + i, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1);
i += sizeof(ANSI_NORMAL)-1;
csClient = CS_NORMAL;
}
ColorState tmp = csClient ^ csNext;
if (CS_ATTRS & tmp)
{
for (unsigned int iAttr = COLOR_INDEX_ATTR; iAttr < COLOR_INDEX_FG; iAttr++)
{
if ( g_no_flash
&& COLOR_INDEX_BLINK == iAttr)
{
continue;
}
if (aColors[iAttr].cs == (aColors[iAttr].csMask & tmp))
{
memcpy(Buffer + i, aColors[iAttr].pAnsi, aColors[iAttr].nAnsi);
i += aColors[iAttr].nAnsi;
}
}
}
// At this point, all colors are indexed.
//
if (CS_FOREGROUND & tmp)
{
iColor = COLOR_INDEX_FG + static_cast<unsigned int>(CS_FG_FIELD(csNext));
if (iColor < COLOR_INDEX_FG + COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[iColor].pAnsi, aColors[iColor].nAnsi);
i += aColors[iColor].nAnsi;
}
}
if (CS_BACKGROUND & tmp)
{
iColor = COLOR_INDEX_BG + static_cast<unsigned int>(CS_BG_FIELD(csNext));
if (iColor < COLOR_INDEX_BG + COLOR_INDEX_DEFAULT)
{
memcpy(Buffer + i, aColors[iColor].pAnsi, aColors[iColor].nAnsi);
i += aColors[iColor].nAnsi;
}
}
Buffer[i] = '\0';
*nTransition = i;
csClient = csNext;
return Buffer;
}
void LettersToColorState(ColorState &cs, const UTF8 *pIn)
{
cs = CS_NORMAL;
bool fBackground = false;
size_t i = 0;
while ('\0' != pIn[i])
{
unsigned int iColor;
unsigned ch = pIn[i];
if ('<' == ch)
{
i++;
size_t j = i;
while ( '\0' != (ch = pIn[i])
&& '>' != ch)
{
i++;
}
RGB rgb;
if ('>' == ch)
{
if (parse_rgb(i - j, pIn + j, rgb))
{
iColor = FindNearestPaletteEntry(rgb, true);
bool fExact = ( palette[iColor].rgb.r == rgb.r
&& palette[iColor].rgb.g == rgb.g
&& palette[iColor].rgb.b == rgb.b);
if (fBackground)
{
cs = (cs & ~CS_BACKGROUND) | (fExact ? CS_BG(iColor) : (rgb2cs(&rgb) << 32));
}
else
{
cs = (cs & ~CS_FOREGROUND) | (fExact ? CS_FG(iColor) : rgb2cs(&rgb));
}
}
i++;
}
fBackground = false;
}
else if ('/' == ch)
{
fBackground = true;
i++;
}
else
{
iColor = ColorTable[pIn[i]];
if (iColor)
{
cs = UpdateColorState(cs, iColor);
}
fBackground = false;
i++;
}
}
}
UTF8 *LettersToBinary(const UTF8 *pLetters)
{
size_t n;
ColorState cs = CS_NORMAL;
LettersToColorState(cs, pLetters);
return ColorTransitionBinary(CS_NORMAL, cs, &n);
}
enum class HTMLtag
{
kIntense,
kUnderline,
kBlink,
kInverse,
kColor,
kNormal,
};
typedef struct
{
bool fBeginEnd;
HTMLtag kTag;
ColorState cs;
int iStart;
} tag_node;
UTF8 *convert_to_html(const UTF8 *pString)
{
// Converting to HTML is performed in two passes. The first pass
// determines an optimal nesting order of tags. The second pass generates
// the HTML.
//
tag_node List[(LBUF_SIZE-1)/3];
int nList = 0;
int Stack[10];
int nStack = 0;
HTMLtag tagmap[5] = {HTMLtag::kIntense, HTMLtag::kUnderline, HTMLtag::kBlink, HTMLtag::kInverse, HTMLtag::kColor };
int iCopy;
int i = 0;
ColorState csPrev = CS_NORMAL;
ColorState csNext = CS_NORMAL;
unsigned int iCode = COLOR_NOTCOLOR;
if ('\0' != pString[i])
{
iCode = mux_color(pString + i);
if (COLOR_NOTCOLOR == iCode)
{
List[nList].fBeginEnd = true;
List[nList].kTag = HTMLtag::kNormal;
List[nList].cs = CS_NORMAL;
List[nList].iStart = -1;
nList++;
}
}
while ( '\0' != pString[i]
|| csNext != csPrev)
{
iCopy = i;
while ( '\0' != pString[i]
&& COLOR_NOTCOLOR == iCode)
{
i += utf8_advance_nul(pString + i);
iCode = mux_color(pString + i);
}
while (csNext != csPrev)
{
for (unsigned int iAttr = COLOR_INDEX_ATTR; iAttr < COLOR_INDEX_FG + 1; iAttr++)
{
ColorState tmp = csNext ^ csPrev;
HTMLtag kNext = tagmap[iAttr - COLOR_INDEX_ATTR];
bool fOpen = false;
bool fClose = false;
if (iAttr < COLOR_INDEX_FG)
{
// Attribute
//
if (tmp & aColors[iAttr].csMask)
{
if (csNext & aColors[iAttr].csMask)
{
fOpen = true;
}
else
{
fClose = true;
}
}
}
else
{
// Color
//
if (tmp & CS_FOREGROUND)
{
if ( (csPrev & CS_FOREGROUND) == CS_FG_DEFAULT
&& (csNext & CS_FOREGROUND) != CS_FG_DEFAULT)
{
fOpen = true;
}
else if ( (csPrev & CS_FOREGROUND) != CS_FG_DEFAULT
&& (csNext & CS_FOREGROUND) == CS_FG_DEFAULT)
{
fClose = true;
}
else
{
fOpen = true;
fClose = true;
}
}
if (tmp & CS_BACKGROUND)
{
if ( (csPrev & CS_BACKGROUND) == CS_BG_DEFAULT
&& (csNext & CS_BACKGROUND) != CS_BG_DEFAULT)
{
fOpen = true;
}
else if ( (csPrev & CS_BACKGROUND) != CS_BG_DEFAULT
&& (csNext & CS_BACKGROUND) == CS_BG_DEFAULT)
{
fClose = true;
}
else
{
fOpen = true;
fClose = true;
}
}
}
if (fClose)
{
for (int j = nStack - 1; 0 <= j; j--)
{
if (List[Stack[j]].kTag == kNext)
{
if (List[Stack[j]].iStart != List[Stack[nStack-1]].iStart)
{
// Pop other tags and mark in csPrev that they are gone. We'll add them back in the next
// iteration of the loop. We stop at the point where tags can be swapped with the one
// we're interested in.
//
for (int k = nStack - 1; j < k && List[Stack[j]].iStart != List[Stack[nStack-1]].iStart; k--)
{
List[nList] = List[Stack[k]];
List[nList].fBeginEnd = false;
List[nList].iStart = -1;
switch (List[nList].kTag)
{
case HTMLtag::kIntense:
csPrev &= ~CS_INTENSE;
break;
case HTMLtag::kUnderline:
csPrev &= ~CS_UNDERLINE;
break;
case HTMLtag::kBlink:
csPrev &= ~CS_BLINK;
break;
case HTMLtag::kInverse:
csPrev &= ~CS_INVERSE;
break;
case HTMLtag::kColor:
csPrev = (csPrev & ~(CS_FOREGROUND|CS_BACKGROUND)) | CS_NORMAL;
break;
default:
break;
}
nList++;
nStack--;
}
}
if (j != nStack - 1)
{
// Change the order of tags which open at the
// same position so that the one we want to
// close can be popped.
//
tag_node t = List[Stack[j]];
List[Stack[j]] = List[Stack[nStack-1]];
List[Stack[nStack-1]] = t;
j = nStack - 1;
}
List[nList] = List[Stack[j]];
List[nList].fBeginEnd = false;
List[nList].iStart = -1;
switch (List[nList].kTag)
{
case HTMLtag::kIntense:
csPrev &= ~CS_INTENSE;
break;
case HTMLtag::kUnderline:
csPrev &= ~CS_UNDERLINE;
break;
case HTMLtag::kBlink:
csPrev &= ~CS_BLINK;
break;
case HTMLtag::kInverse:
csPrev &= ~CS_INVERSE;
break;
case HTMLtag::kColor:
csPrev = (csPrev & ~(CS_FOREGROUND|CS_BACKGROUND)) | CS_NORMAL;
break;
default:
break;
}
nList++;
nStack--;
if (0 == nStack)
{
List[nList].fBeginEnd = true;
List[nList].kTag = HTMLtag::kNormal;
List[nList].cs = CS_NORMAL;
List[nList].iStart = -1;
nList++;
}
break;
}
}
}
if (fOpen)
{
List[nList].fBeginEnd = true;
List[nList].cs = csNext;
List[nList].kTag = kNext;
List[nList].iStart = -1;
switch (List[nList].kTag)
{
case HTMLtag::kIntense:
csPrev |= CS_INTENSE;
break;
case HTMLtag::kUnderline:
csPrev |= CS_UNDERLINE;
break;
case HTMLtag::kBlink:
csPrev |= CS_BLINK;
break;
case HTMLtag::kInverse:
csPrev |= CS_INVERSE;
break;
case HTMLtag::kColor:
csPrev &= ~(CS_FOREGROUND|CS_BACKGROUND);
csPrev |= (CS_FOREGROUND|CS_BACKGROUND) & csNext;;
break;
default:
break;
}
Stack[nStack++] = nList++;
}
}
}
if (0 < nList)
{
List[nList-1].iStart = iCopy;
}
while ( '\0' != pString[i]
&& COLOR_NOTCOLOR != iCode)
{
csNext = UpdateColorState(csNext, iCode, pString + i);
i += utf8_advance_nul(pString + i);
iCode = mux_color(pString + i);
}
// When CS_INTENSE is active and the foreground is a basic ANSI
// color (0-7), substitute the bright palette entry (8-15) so
// that HTML <COLOR> tags carry the correct RGB value.
//
if ( (csNext & CS_INTENSE)
&& (CS_FG_INDEXED & csNext))
{
unsigned int idx = static_cast<unsigned int>(CS_FG_FIELD(csNext));
if (idx < 8)
{
csNext = (csNext & ~CS_FOREGROUND) | CS_FG(idx + 8);
}
}
}
static UTF8 aBuffer[2*LBUF_SIZE];
UTF8 *pBuffer = aBuffer;
for (int iList = 0; iList < nList; iList++)
{
if (HTMLtag::kNormal != List[iList].kTag)
{
*pBuffer++ = '<';
if (!List[iList].fBeginEnd)
{
*pBuffer++ = '/';
}
switch (List[iList].kTag)
{
case HTMLtag::kIntense:
*pBuffer++ = 'B';
break;
case HTMLtag::kUnderline:
*pBuffer++ = 'U';
break;
case HTMLtag::kBlink:
*pBuffer++ = 'I';
break;
case HTMLtag::kInverse:
*pBuffer++ = 'S';
break;
case HTMLtag::kColor:
if (List[iList].fBeginEnd)
{
ColorState cs = List[iList].cs;
if ( (CS_FOREGROUND & cs) != CS_FG_DEFAULT
&& (CS_FG_INDEXED & cs))
{
cs = (cs & ~CS_FOREGROUND) | rgb2cs(&palette[CS_FG_FIELD(cs)].rgb);
}
if ( (CS_BACKGROUND & cs) != CS_BG_DEFAULT
&& (CS_BG_INDEXED & cs))
{
cs = (cs & ~CS_BACKGROUND) | (rgb2cs(&palette[CS_BG_FIELD(cs)].rgb) << 32);
}
if ((CS_FOREGROUND & cs) == CS_FG_DEFAULT)
{
if ((CS_BACKGROUND & cs) != CS_BG_DEFAULT)
{
mux_sprintf(pBuffer, sizeof(aBuffer) - (pBuffer - aBuffer) - 1, T("COLOR BACK=#%06llX"), CS_BG_FIELD(cs));
pBuffer += strlen(reinterpret_cast<char *>(pBuffer));
}
}
else
{
if ((CS_BACKGROUND & cs) == CS_BG_DEFAULT)
{
mux_sprintf(pBuffer, sizeof(aBuffer) - (pBuffer - aBuffer) - 1, T("COLOR #%06llX"), CS_FG_FIELD(cs));
pBuffer += strlen(reinterpret_cast<char *>(pBuffer));
}
else
{
mux_sprintf(pBuffer, sizeof(aBuffer) - (pBuffer - aBuffer) - 1, T("COLOR #%06llX #%06llX"), CS_FG_FIELD(cs), CS_BG_FIELD(cs));
pBuffer += strlen(reinterpret_cast<char *>(pBuffer));
}
}
}
else
{
mux_sprintf(pBuffer, sizeof(aBuffer) - (pBuffer - aBuffer) - 1, T("COLOR"));
pBuffer += strlen(reinterpret_cast<char *>(pBuffer));
}
break;
default:
break;
}
*pBuffer++ = '>';
}
iCopy = i = List[iList].iStart;
if (0 <= iCopy)
{
if ('\0' != pString[i])
{
iCode = mux_color(pString + i);
}
while ( '\0' != pString[i]
&& COLOR_NOTCOLOR == iCode)
{
i += utf8_advance_nul(pString + i);
iCode = mux_color(pString + i);
}
size_t n = i - iCopy;
if (0 < n)
{
memcpy(pBuffer, pString + List[iList].iStart, n);
pBuffer += n;
}
}
}
*pBuffer = '\0';
return aBuffer;
}
/*! \brief Convert private color code points within a string to ANSI color
* sequences.
*
* This routine converts these internal color code points to ANSI sequences
* which clients will recognize.
*
* Internally, the server uses color code points to represent color. This
* representation is more compact, it simplifies the parser, and it thwarts
* the possibility of softcode generating naked ESC characters. Several
* protocols use the ESC character, so it is helpful if the server controls
* their use.
*
* \param pString String (length LBUF_SIZE-1 or less) with color code points.
* \param fNoBleed Should we dodge a naked return-to-normal state.
* \param fColor256 Can we use the full 256-color palette?
* \return String with exportable ANSI color sequences.
*/
UTF8 *convert_color(const UTF8 *pString, bool fNoBleed, bool fColor256)
{
static UTF8 aBuffer[2*LBUF_SIZE];
static const UTF8 *pNormal= T(ANSI_NORMAL ANSI_WHITE);
size_t nNormal = sizeof(ANSI_NORMAL)-1;
if (fNoBleed)
{
nNormal += sizeof(ANSI_WHITE)-1;
}
ColorState csClient = (fNoBleed)?CS_FG_WHITE:CS_NORMAL;
ColorState csPrev = CS_NORMAL;
ColorState csNext = CS_NORMAL;
UTF8 *pBuffer = aBuffer;
size_t i = 0;
size_t iCopy = 0;
unsigned int iCode = COLOR_NOTCOLOR;
if ('\0' != pString[i])
{
iCode = mux_color(pString + i);
}
while ('\0' != pString[i])
{
iCopy = i;
while ( '\0' != pString[i]
&& COLOR_NOTCOLOR == iCode)
{
i += utf8_advance_nul(pString + i);
iCode = mux_color(pString + i);
}
if (iCopy < i)
{
if (csNext != csPrev)
{
UTF8 *pTransition = nullptr;
size_t nTransition;
pTransition = ColorTransitionANSI( csClient, csNext,
&nTransition, fNoBleed, fColor256);
if (nTransition)
{
if (sizeof(aBuffer) - (pBuffer - aBuffer) - nNormal - 1 < nTransition)
{
break;
}
memcpy(pBuffer, pTransition, nTransition);
pBuffer += nTransition;
}
csPrev = csNext;
}
if (sizeof(aBuffer) - (pBuffer - aBuffer) - nNormal - 1 < i - iCopy)
{
break;
}
memcpy(pBuffer, pString + iCopy, i - iCopy);
pBuffer += i - iCopy;
iCopy = i;
}
while ( '\0' != pString[i]
&& COLOR_NOTCOLOR != iCode)
{
csNext = UpdateColorState(csNext, iCode, pString + i);
i += utf8_advance_nul(pString + i);
iCode = mux_color(pString + i);
}
}
if (csPrev != CS_NORMAL)
{
memcpy(pBuffer, pNormal, nNormal);
pBuffer += nNormal;
}
*pBuffer = '\0';
return aBuffer;
}
UTF8 *strip_color(const UTF8 *pString, size_t *pnBytes, size_t *pnPoints)
{
static UTF8 aBuffer[LBUF_SIZE];
UTF8 *pBuffer = aBuffer;
if (nullptr == pString)
{
if (nullptr != pnBytes)
{
*pnBytes = 0;
}
if (nullptr != pnPoints)
{
*pnPoints = 0;
}
*pBuffer = '\0';
return aBuffer;
}
size_t nPoints = 0;
while ('\0' != *pString)
{
if (COLOR_NOTCOLOR == mux_color(pString))
{
utf8_safe_chr(pString, aBuffer, &pBuffer);
nPoints++;
}
pString += utf8_advance_nul(pString);
}
*pBuffer = '\0';
if (nullptr != pnBytes)
{
*pnBytes = pBuffer - aBuffer;
}
if (nullptr != pnPoints)
{
*pnPoints = nPoints;
}
return aBuffer;
}
typedef struct
{
int len;
const UTF8 *p;
} LITERAL_STRING_STRUCT;
#define NUM_WS_SUBS 6
#define NUM_MU_SUBS 14
static LITERAL_STRING_STRUCT MU_Substitutes[NUM_MU_SUBS] =
{
{ 1, T(" ") }, // 0
{ 1, T(" ") }, // 1
{ 2, T("%t") }, // 2
{ 2, T("%r") }, // 3
{ 0, T("") }, // 4 -- emit nothing (\r); empty, not null (#1458)
{ 2, T("%b") }, // 5
{ 2, T("%%") }, // 6
{ 2, T("%(") }, // 7
{ 2, T("%)") }, // 8
{ 2, T("%[") }, // 9
{ 2, T("%]") }, // 10
{ 2, T("%{") }, // 11
{ 2, T("%}") }, // 12
{ 2, T("\\\\") } // 13
};
const unsigned char MU_EscapeConvert[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 0, 0, 0, 0, 6, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,13,10, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11, 0,12, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
const unsigned char MU_EscapeNoConvert[256] =
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
//
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
// Convert raw character sequences into MUX substitutions (type = 1)
// or strips them (type = 0).
//
UTF8 *translate_string(const UTF8 *pString, bool bConvert)
{
static UTF8 szTranslatedString[LBUF_SIZE];
UTF8 *pTranslatedString = szTranslatedString;
if (!pString)
{
*pTranslatedString = '\0';
return szTranslatedString;
}
ColorState csCurrent = CS_NOBLEED;
ColorState csPrevious = csCurrent;
const UTF8 *MU_EscapeChar = (bConvert)? MU_EscapeConvert : MU_EscapeNoConvert;
while ('\0' != *pString)
{
unsigned int iCode = mux_color(pString);
if (COLOR_NOTCOLOR == iCode)
{
size_t nTransition = 0;
if (bConvert)
{
UTF8 *pTransition = ColorTransitionEscape(csPrevious, csCurrent, &nTransition);
safe_str(pTransition, szTranslatedString, &pTranslatedString);
csPrevious = csCurrent;
}
UTF8 ch = pString[0];
unsigned char code = MU_EscapeChar[ch];
if ( 0 < code
&& code < NUM_MU_SUBS)
{
if ( ' ' == ch
&& ' ' == pString[1])
{
code = 5;
}
safe_copy_buf(MU_Substitutes[code].p,
MU_Substitutes[code].len, szTranslatedString,
&pTranslatedString);
}
else
{
utf8_safe_chr(pString, szTranslatedString, &pTranslatedString);
}
}
else
{
csCurrent = UpdateColorState(csCurrent, iCode, pString);
}
pString += utf8_advance_nul(pString);
}
*pTranslatedString = '\0';
return szTranslatedString;
}
bool IsDecompFriendly(const UTF8 *pString)
{
bool fFriendly = true;
if (!pString)
{
return fFriendly;
}
const UTF8 *MU_EscapeChar = MU_EscapeConvert;
while ( '\0' != *pString
&& fFriendly)
{
unsigned int iCode = mux_color(pString);
if (COLOR_NOTCOLOR == iCode)
{
UTF8 ch = pString[0];
unsigned char code = MU_EscapeChar[ch];
if ( 0 < code
&& code < NUM_WS_SUBS)
{
if (' ' == ch)
{
if (' ' == pString[1])
{
// Two adjacent spaces are not @decomp-friendly.
//
fFriendly = false;
break;
}
// An isolated space is still @decomp-friendly.
//
}
else
{
// Raw tabs and newlines are not @decomp-friendly.
//
fFriendly = false;
break;
}
}
}
else
{
// Raw color codes are not @decomp-friendly.
//
fFriendly = false;
break;
}
pString += utf8_advance_nul(pString);
}
return fFriendly;
}
/* ---------------------------------------------------------------------------
* munge_space: Compress multiple spaces to one space, also remove leading and
* trailing spaces.
*/
UTF8 *munge_space(const UTF8 *string)
{
UTF8 *buffer = alloc_lbuf("munge_space");
const UTF8 *p = string;
UTF8 *q = buffer;
if (p)
{
// Remove initial spaces.
//
while (mux_isspace(*p))
p++;
while (*p)
{
while (*p && !mux_isspace(*p))
*q++ = *p++;
while (mux_isspace(*p))
{
p++;
}
if (*p)
*q++ = ' ';
}
}
// Remove terminal spaces and terminate string.
//
*q = '\0';
return buffer;
}
/* ---------------------------------------------------------------------------
* trim_spaces: Remove leading and trailing spaces and space-compress internal
* spaces.
*/
UTF8 *trim_spaces(const UTF8 *string)
{
UTF8 *buffer = alloc_lbuf("trim_spaces");
const UTF8 *p = string;
UTF8 *q = buffer;
if (p)
{
// Remove initial spaces.
//
while (mux_isspace(*p))
{
p++;
}
while (*p)
{
// Copy non-space characters.
//
while (*p && !mux_isspace(*p))
{
*q++ = *p++;
}
// Compress spaces.
//
while (mux_isspace(*p))
{
p++;
}
// Leave one space.
//
if (*p)
{
*q++ = ' ';
}
}
}
// Terminate string.
//
*q = '\0';
return buffer;
}
/*
* ---------------------------------------------------------------------------
* * grabto: Return portion of a string up to the indicated character. Also
* * returns a modified pointer to the string ready for another call.
*/
UTF8 *grabto(UTF8 **str, UTF8 targ)
{
UTF8 *savec, *cp;
if (!str || !*str || !**str)
return nullptr;
savec = cp = *str;
while (*cp && *cp != targ)
cp++;
if (*cp)
*cp++ = '\0';
*str = cp;
return savec;
}
int string_compare(const UTF8 *s1, const UTF8 *s2)
{
if (g_space_compress)
{
while (mux_isspace(*s1))
{
s1++;
}
while (mux_isspace(*s2))
{
s2++;
}
while (*s1 && *s2)
{
if (mux_isspace(*s1) && mux_isspace(*s2))
{
// Both are spaces — skip all contiguous spaces.
//
do
{
s1++;
} while (mux_isspace(*s1));
do
{
s2++;
} while (mux_isspace(*s2));
continue;
}
// ASCII fast path: compare via table without the full
// Unicode state machine.
//
if (*s1 < 0x80 && *s2 < 0x80)
{
if (mux_tolower_ascii[*s1] != mux_tolower_ascii[*s2])
{
break;
}
s1++;
s2++;
continue;
}
// Compare code points case-insensitively (Unicode-aware).
//
UTF8 la[4], lb[4];
size_t na, nb;
bool bXorA;
const string_desc *qA = mux_tolower(s1, bXorA);
if (nullptr == qA)
{
na = utf8_FirstByte[static_cast<unsigned char>(*s1)];
if (na >= UTF8_CONTINUE) na = 1;
for (size_t j = 0; j < na; j++) la[j] = s1[j];
}
else
{
na = qA->n_bytes;
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = s1[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
bool bXorB;
const string_desc *qB = mux_tolower(s2, bXorB);
if (nullptr == qB)
{
nb = utf8_FirstByte[static_cast<unsigned char>(*s2)];
if (nb >= UTF8_CONTINUE) nb = 1;
for (size_t j = 0; j < nb; j++) lb[j] = s2[j];
}
else
{
nb = qB->n_bytes;
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = s2[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
// If lowercased code points differ, we're done.
//
if (na != nb)
{
break;
}
bool bEqual = true;
for (size_t j = 0; j < na; j++)
{
if (la[j] != lb[j])
{
bEqual = false;
break;
}
}
if (!bEqual)
{
break;
}
s1 += na;
s2 += nb;
}
if ( *s1
&& *s2)
{
return 1;
}
if (mux_isspace(*s1))
{
while (mux_isspace(*s1))
{
s1++;
}
return *s1;
}
if (mux_isspace(*s2))
{
while (mux_isspace(*s2))
{
s2++;
}
return *s2;
}
if ( *s1
|| *s2)
{
return 1;
}
return 0;
}
else
{
return mux_stricmp(s1, s2);
}
}
int string_prefix(const UTF8 *string, const UTF8 *prefix)
{
int count = 0;
// ASCII fast path: compare bytes directly via tolower table.
// Most object names and commands are pure ASCII — this avoids
// the full Unicode mux_tolower state machine per character.
//
while (*string && *prefix
&& *string < 0x80 && *prefix < 0x80)
{
if (mux_tolower_ascii[*string] != mux_tolower_ascii[*prefix])
{
return 0;
}
string++;
prefix++;
count++;
}
// Unicode fallback: code-point-at-a-time case-insensitive comparison.
//
while (*string && *prefix)
{
UTF8 la[4], lb[4];
size_t na, nb;
bool bXorA;
const string_desc *qA = mux_tolower(string, bXorA);
if (nullptr == qA)
{
na = utf8_FirstByte[static_cast<unsigned char>(*string)];
if (na >= UTF8_CONTINUE) na = 1;
for (size_t j = 0; j < na; j++) la[j] = string[j];
}
else
{
na = qA->n_bytes;
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = string[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
bool bXorB;
const string_desc *qB = mux_tolower(prefix, bXorB);
if (nullptr == qB)
{
nb = utf8_FirstByte[static_cast<unsigned char>(*prefix)];
if (nb >= UTF8_CONTINUE) nb = 1;
for (size_t j = 0; j < nb; j++) lb[j] = prefix[j];
}
else
{
nb = qB->n_bytes;
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = prefix[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
if (na != nb)
{
return 0;
}
for (size_t j = 0; j < na; j++)
{
if (la[j] != lb[j])
{
return 0;
}
}
string += na;
prefix += nb;
count += static_cast<int>(na);
}
if (*prefix == '\0')
{
// Matched all of prefix.
//
return count;
}
else
{
return 0;
}
}
/*
* accepts only nonempty matches starting at the beginning of a word
*/
const UTF8 *string_match(const UTF8 *src, const UTF8 *sub)
{
if ((*sub != '\0') && (src))
{
const bool ascii_sub = (*sub < 0x80);
const UTF8 sub0_lower = ascii_sub
? mux_tolower_ascii[*sub]
: 0;
while (*src)
{
if (ascii_sub && *src < 0x80)
{
if (mux_tolower_ascii[*src] != sub0_lower)
{
while (mux_isalnum(*src))
{
src++;
}
while (*src && !mux_isalnum(*src))
{
src++;
}
continue;
}
const UTF8 *s = src;
const UTF8 *p = sub;
while (*s && *p && *s < 0x80 && *p < 0x80)
{
if (mux_tolower_ascii[*s] != mux_tolower_ascii[*p])
{
break;
}
s++;
p++;
}
if (*p == '\0')
{
return src;
}
// If the ASCII prefix matched and either side then went
// non-ASCII, fall back to the full Unicode-aware matcher.
if ((*s || *p) && !(*s < 0x80 && *p < 0x80)
&& string_prefix(src, sub))
{
return src;
}
}
else if (string_prefix(src, sub))
{
return src;
}
// else scan to beginning of next word
//
while (mux_isalnum(*src))
{
src++;
}
while (*src && !mux_isalnum(*src))
{
src++;
}
}
}
return 0;
}
/*
* ---------------------------------------------------------------------------
* * replace_string: Returns an lbuf containing string STRING with all occurances
* * of OLD replaced by NEW. OLD and NEW may be different lengths.
* * (mitch 1 feb 91)
*/
UTF8 *replace_string(const UTF8 *old, const UTF8 *new0, const UTF8 *s)
{
if (!s)
{
return nullptr;
}
size_t olen = strlen(reinterpret_cast<const char *>(old));
UTF8 *result = alloc_lbuf("replace_string");
UTF8 *r = result;
while (*s)
{
// Find next occurrence of the first character of OLD string.
//
const UTF8 *p = reinterpret_cast<const UTF8 *>(strchr(reinterpret_cast<const char *>(s), old[0]));
if ( olen
&& p)
{
// Copy up to the next occurrence of the first char of OLD.
//
size_t n = p - s;
if (n)
{
safe_copy_buf(s, n, result, &r);
s += n;
}
// If we are really at an complete OLD, append NEW to the result
// and bump the input string past the occurrence of OLD.
// Otherwise, copy the character and try matching again.
//
if (!strncmp(reinterpret_cast<const char *>(old), reinterpret_cast<const char *>(s), olen))
{
safe_str(new0, result, &r);
s += olen;
}
else
{
safe_chr(*s, result, &r);
s++;
}
}
else
{
// Finish copying source string. No matches. No further
// work to perform.
//
safe_str(s, result, &r);
break;
}
}
*r = '\0';
return result;
}
bool minmatch(const UTF8 *str, const UTF8 *target, int min)
{
// Code-point-at-a-time case-insensitive comparison (Unicode-aware).
// min tracks bytes matched (callers pass byte-based minlen).
//
while (*str && *target)
{
UTF8 la[4], lb[4];
size_t na, nb;
bool bXorA;
const string_desc *qA = mux_tolower(str, bXorA);
if (nullptr == qA)
{
na = utf8_FirstByte[static_cast<unsigned char>(*str)];
if (na >= UTF8_CONTINUE) na = 1;
for (size_t j = 0; j < na; j++) la[j] = str[j];
}
else
{
na = qA->n_bytes;
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = str[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
bool bXorB;
const string_desc *qB = mux_tolower(target, bXorB);
if (nullptr == qB)
{
nb = utf8_FirstByte[static_cast<unsigned char>(*target)];
if (nb >= UTF8_CONTINUE) nb = 1;
for (size_t j = 0; j < nb; j++) lb[j] = target[j];
}
else
{
nb = qB->n_bytes;
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = target[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
if (na != nb)
{
return false;
}
for (size_t j = 0; j < na; j++)
{
if (la[j] != lb[j])
{
return false;
}
}
str += na;
target += nb;
min -= static_cast<int>(na);
}
if (*str)
{
return false;
}
if (!*target)
{
return true;
}
return (min <= 0);
}
// --------------------------------------------------------------------------
// StringCloneLen: allocate memory and copy string
//
UTF8 *StringCloneLen(const UTF8 *str, size_t nStr)
{
UTF8 *buff = reinterpret_cast<UTF8 *>(MEMALLOC(nStr+1));
if (buff)
{
memcpy(buff, str, nStr);
buff[nStr] = '\0';
}
else
{
OutOfMemory(reinterpret_cast<const UTF8 *>(__FILE__), __LINE__);
}
return buff;
}
// --------------------------------------------------------------------------
// StringClone: allocate memory and copy string
//
UTF8 *StringClone(const UTF8 *str)
{
return StringCloneLen(str, strlen(reinterpret_cast<const char *>(str)));
}
/* ---------------------------------------------------------------------------
* safe_copy_str - Copy buffers, watching for overflows.
*/
void safe_copy_str(const UTF8 *src, UTF8 *buff, UTF8 **bufp, size_t nSizeOfBuffer)
{
if (src == nullptr) return;
UTF8 *tp = *bufp;
UTF8 *maxtp = buff + nSizeOfBuffer;
while (tp < maxtp && *src)
{
*tp++ = *src++;
}
*bufp = buff + TrimPartialSequence(tp - buff, buff);
}
void safe_copy_str_lbuf(const UTF8 *src, UTF8 *buff, UTF8 **bufp)
{
if (src == nullptr)
{
return;
}
UTF8 *tp = *bufp;
UTF8 *maxtp = buff + LBUF_SIZE - 1;
while (tp < maxtp && *src)
{
*tp++ = *src++;
}
*bufp = buff + TrimPartialSequence(tp - buff, buff);
}
size_t safe_copy_buf(const UTF8 *src, size_t nLen, UTF8 *buff, UTF8 **bufc)
{
// A null src is UB for memcpy even when nLen is zero -- the standard
// requires valid pointers regardless of the length (C17 7.24.1p2), and
// UBSan reports it as "null pointer passed as argument 2" (#1458).
//
// Guarding here rather than only at the one caller that does it: the
// sibling helpers safe_copy_str, safe_copy_str_lbuf and utf8_safe_chr
// all already return early on a null src, so tolerating it is the
// established convention among these functions and safe_copy_buf was
// the one outlier. It also covers the TrimPartialSequence call below,
// which would dereference src outright had a caller passed null with a
// non-zero length.
//
if (nullptr == src)
{
return 0;
}
size_t left = LBUF_SIZE - (*bufc - buff) - 1;
if (left < nLen)
{
nLen = TrimPartialSequence(left, src);
}
memcpy(*bufc, src, nLen);
*bufc += nLen;
return nLen;
}
size_t safe_fill(UTF8 *buff, UTF8 **bufc, UTF8 chFill, size_t nSpaces)
{
// Check for buffer limits.
//
size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1;
if (nSpaces > nBufferAvailable)
{
nSpaces = nBufferAvailable;
}
// Fill with spaces.
//
memset(*bufc, chFill, nSpaces);
*bufc += nSpaces;
return nSpaces;
}
void utf8_safe_chr(const UTF8 *src, UTF8 *buff, UTF8 **bufc)
{
size_t nLen;
size_t nLeft;
if ( nullptr == src
|| UTF8_CONTINUE <= (nLen = utf8_FirstByte[*src]))
{
return;
}
for (size_t i = 1; i < nLen; i++)
{
if ( '\0' == src[i]
|| UTF8_CONTINUE != utf8_FirstByte[src[i]])
{
return;
}
}
nLeft = LBUF_SIZE - (*bufc - buff) - 1;
if (nLeft < nLen)
{
return;
}
memcpy(*bufc, src, nLen);
*bufc += nLen;
}
UTF8 *ConvertToUTF8
(
UTF32 ch
)
{
static UTF8 buffer[6];
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
if (ch < (UTF32)0x80)
{
// ASCII
//
buffer[1] = '\0';
buffer[0] = static_cast<UTF8>(ch);
}
else if (ch < (UTF32)0x800)
{
buffer[2] = '\0';
buffer[1] = static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[0] = static_cast<char>(0xC0 | ch);
}
else if (ch < (UTF32)0x10000)
{
if ( UNI_SUR_HIGH_START <= ch
&& ch <= UNI_SUR_LOW_END)
{
buffer[0] = '\0';
return buffer;
}
buffer[3] = '\0';
buffer[2] =static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[1] = static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[0] = static_cast<char>(0xE0 | ch);
}
else if (ch <= UNI_MAX_LEGAL_UTF32)
{
buffer[4] = '\0';
buffer[3] = static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[2] = static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[1] = static_cast<char>((ch | byteMark) & byteMask);
ch >>= 6;
buffer[0] = static_cast<char>(0xF0 | ch);
}
return buffer;
}
UTF16 *ConvertToUTF16(UTF32 ch)
{
static UTF16 buffer[3];
if ( ch < UNI_SUR_HIGH_START
|| UNI_SUR_LOW_END < ch)
{
// This is the common case.
//
buffer[0] = (UTF16)ch;
buffer[1] = 0x0000;
return buffer;
}
else if (ch <= UNI_MAX_LEGAL_UTF32)
{
const int halfShift = 10;
const UTF32 halfBase = 0x0010000UL;
const UTF32 halfMask = 0x3FFUL;
ch -= halfBase;
buffer[0] = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
buffer[1] = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
buffer[2] = 0x0000;
}
else
{
buffer[0] = UNI_REPLACEMENT_CHAR;
buffer[1] = 0x0000;
}
return buffer;
}
UTF32 ConvertFromUTF8(const UTF8 *pString)
{
size_t t = utf8_FirstByte[*pString];
if (UTF8_CONTINUE <= t)
{
return UNI_EOF;
}
UTF32 ch;
if (1 == t)
{
// This is the most common case, and the value is always smaller than
// UNI_SUR_HIGH_START.
//
return pString[0];
}
else if (2 == t)
{
if ( '\0' == pString[1]
|| UTF8_CONTINUE != utf8_FirstByte[pString[1]])
{
return UNI_EOF;
}
ch = utf8_decode_raw(pString, 2);
if (!utf8_is_valid_scalar(ch, 2))
{
return UNI_EOF;
}
}
else if (3 == t)
{
if ( '\0' == pString[1]
|| '\0' == pString[2]
|| UTF8_CONTINUE != utf8_FirstByte[pString[1]]
|| UTF8_CONTINUE != utf8_FirstByte[pString[2]])
{
return UNI_EOF;
}
ch = utf8_decode_raw(pString, 3);
if (!utf8_is_valid_scalar(ch, 3))
{
return UNI_EOF;
}
}
else if (4 == t)
{
if ( '\0' == pString[1]
|| '\0' == pString[2]
|| '\0' == pString[3]
|| UTF8_CONTINUE != utf8_FirstByte[pString[1]]
|| UTF8_CONTINUE != utf8_FirstByte[pString[2]]
|| UTF8_CONTINUE != utf8_FirstByte[pString[3]])
{
return UNI_EOF;
}
ch = utf8_decode_raw(pString, 4);
if (!utf8_is_valid_scalar(ch, 4))
{
return UNI_EOF;
}
}
else
{
return UNI_EOF;
}
if (utf8_is_valid_scalar(ch, t))
{
return ch;
}
else
{
return UNI_EOF;
}
}
size_t ConvertFromUTF16(UTF16 *pString, UTF32 &ch)
{
ch = pString[0];
if ( ch < UNI_SUR_HIGH_START
|| UNI_SUR_LOW_END < ch)
{
// This is the most-common case.
//
return 1;
}
else if (ch <= UNI_SUR_HIGH_END)
{
UTF32 ch2 = pString[1];
if ( UNI_SUR_LOW_START <= ch2
&& ch2 <= UNI_SUR_LOW_END)
{
const int halfShift = 10;
const UTF32 halfBase = 0x0010000UL;
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START)
+ halfBase;
return 2;
}
}
ch = UNI_EOF;
return 0;
}
UTF16 *ConvertFromUTF8ToUTF16(const UTF8 *pString, size_t& length)
{
static UTF16 buffer[2*LBUF_SIZE];
UTF16 *p = buffer;
UTF16 *const pEnd = buffer + sizeof(buffer) / sizeof(buffer[0]);
length = 0;
while ('\0' != *pString)
{
UTF32 ch = ConvertFromUTF8(pString);
if (UNI_EOF == ch)
{
return nullptr;
}
UTF16 *q = ConvertToUTF16(ch);
while (0x0000 != *q)
{
if (p + 1 >= pEnd)
{
return nullptr;
}
*p++ = *q++;
}
size_t nAdvance = utf8_FirstByte[static_cast<unsigned char>(*pString)];
if (nAdvance < 1 || nAdvance >= UTF8_CONTINUE)
{
return nullptr;
}
pString += nAdvance;
}
if (p >= pEnd)
{
return nullptr;
}
*p = '\0';
length = p - buffer;
return buffer;
}
// We want to remove mal-formed ESC sequences completely and convert the
// well-formed ones.
//
UTF8 *ConvertToUTF8(const char *p, size_t *pn)
{
*pn = 0;
static UTF8 aBuffer[LBUF_SIZE];
UTF8 *pBuffer = aBuffer;
while ('\0' != *p)
{
if (ESC_CHAR != *p)
{
const UTF8 *q = latin1_utf8[static_cast<unsigned char>(*p)];
utf8_safe_chr(q, aBuffer, &pBuffer);
p++;
}
else
{
// We have an ANSI sequence.
//
p++;
if ('[' == *p)
{
p++;
const char *q = p;
while (ANSI_TokenTerminatorTable[static_cast<unsigned char>(*q)] == 0)
{
q++;
}
if ('\0' != q[0])
{
// The segment [p,q) should contain a list of semi-color delimited codes.
//
const char *r = p;
while (r != q)
{
while ( r != q
&& ';' != r[0])
{
r++;
}
// The segment [p,r) should contain one code.
//
size_t n = r - p;
const UTF8 *s = nullptr;
switch (n)
{
case 1:
if ('0' == *p)
{
s = aColors[COLOR_INDEX_RESET].pUTF;
}
else if ('1' == *p)
{
s = aColors[COLOR_INDEX_INTENSE].pUTF;
}
else if ('4' == *p)
{
s = aColors[COLOR_INDEX_UNDERLINE].pUTF;
}
else if ('5' == *p)
{
s = aColors[COLOR_INDEX_BLINK].pUTF;
}
else if ('7' == *p)
{
s = aColors[COLOR_INDEX_INVERSE].pUTF;
}
break;
case 2:
if ('3' == *p)
{
unsigned int iCode = COLOR_INDEX_FG + (p[1] - '0');
if ( COLOR_INDEX_FG <= iCode
&& iCode < COLOR_INDEX_FG + 7)
{
s = aColors[iCode].pUTF;
}
}
else if ('4' == *p)
{
unsigned int iCode = COLOR_INDEX_BG + (p[1] - '0');
if ( COLOR_INDEX_BG <= iCode
&& iCode <= COLOR_INDEX_BG + 7)
{
s = aColors[iCode].pUTF;
}
}
break;
}
if (nullptr != s)
{
utf8_safe_chr(s, aBuffer, &pBuffer);
}
while ( r != q
&& ';' == r[0])
{
r++;
}
p = r;
}
// Eat trailing terminator.
//
p = q + 1;
}
else
{
// Skip to end of mal-formed ANSI sequence.
//
p = q;
}
}
}
}
*pBuffer = '\0';
*pn = pBuffer - aBuffer;
return aBuffer;
}
// mux_strncpy: Copies up to specified number of chars from source.
// Note: unlike strncpy(), this null-terminates after copying.
//
void mux_strncpy(UTF8 *dest, const UTF8 *src, size_t length_to_copy)
{
size_t i = 0;
if ( nullptr != src
|| length_to_copy < 0)
{
while ( i < length_to_copy
&& '\0' != src[i])
{
dest[i] = src[i];
i++;
}
}
dest[i] = '\0';
}
bool matches_exit_from_list(const UTF8 *str, const UTF8 *pattern)
{
const UTF8 *s;
while (*pattern)
{
// Compare str against this exit name, code-point-at-a-time
// (Unicode-aware).
//
s = str;
while ( *s
&& *pattern
&& *pattern != EXIT_DELIMITER)
{
UTF8 la[4], lb[4];
size_t na, nb;
bool bXorA;
const string_desc *qA = mux_tolower(s, bXorA);
if (nullptr == qA)
{
na = utf8_FirstByte[static_cast<unsigned char>(*s)];
if (na >= UTF8_CONTINUE) na = 1;
for (size_t j = 0; j < na; j++) la[j] = s[j];
}
else
{
na = qA->n_bytes;
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = s[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
bool bXorB;
const string_desc *qB = mux_tolower(pattern, bXorB);
if (nullptr == qB)
{
nb = utf8_FirstByte[static_cast<unsigned char>(*pattern)];
if (nb >= UTF8_CONTINUE) nb = 1;
for (size_t j = 0; j < nb; j++) lb[j] = pattern[j];
}
else
{
nb = qB->n_bytes;
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = pattern[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
if (na != nb)
{
break;
}
bool bEqual = true;
for (size_t j = 0; j < na; j++)
{
if (la[j] != lb[j])
{
bEqual = false;
break;
}
}
if (!bEqual)
{
break;
}
s += na;
pattern += nb;
}
// Did we match it all?
//
if (*s == '\0')
{
// Make sure nothing afterwards
//
while (mux_isspace(*pattern))
{
pattern++;
}
// Did we get it?
//
if ( !*pattern
|| (*pattern == EXIT_DELIMITER))
{
return true;
}
}
// We didn't get it, find next string to test
//
while ( *pattern
&& *pattern++ != EXIT_DELIMITER)
{
; // Nothing.
}
while (mux_isspace(*pattern))
{
pattern++;
}
}
return false;
}
void string_token::set_source(UTF8* source_arg)
{
source = source_arg;
}
void string_token::set_control(const UTF8* control_arg)
{
memset(control, 0, sizeof(control));
// The '\0' character is always a control character.
//
control[0] = true;
// Record the user-specified control characters.
//
while (*control_arg)
{
control[static_cast<unsigned char>(*control_arg)] = 1;
control_arg++;
}
}
UTF8* string_token::parse_length(size_t* length)
{
*length = 0;
UTF8 *p = source;
if (!p)
{
return nullptr;
}
// Skip over leading control characters except for the NUL character.
//
while (control[static_cast<unsigned char>(*p)] && *p)
{
p++;
}
UTF8 *pReturn = p;
// Skip over non-control characters.
//
while (control[static_cast<unsigned char>(*p)] == 0)
{
p++;
}
// What is the length of this token?
//
*length = p - pReturn;
// Terminate the token with a NUL.
//
if (p[0])
{
// We found a non-NUL delimiter, so the next call will begin parsing
// on the character after this one.
//
source = p+1;
}
else
{
// We hit the end of the string, so the end of the string is where
// the next call will begin.
//
source = p;
}
// Did we find a token?
//
if (*length > 0)
{
return pReturn;
}
else
{
return nullptr;
}
}
UTF8* string_token::parse()
{
size_t nLen;
UTF8 *p = parse_length(&nLen);
if (p)
{
p[nLen] = '\0';
}
return p;
}
mux_field StripTabsAndTruncate
(
const UTF8 *pString,
UTF8 *pBuffer,
size_t nLength,
size_t nWidth0
)
{
mux_field fldOutput(0, 0);
if ( nullptr == pBuffer
|| nullptr == pString
|| 0 == nLength
|| 0 == nWidth0
|| '\0' == pString[0])
{
if ( nullptr != pBuffer
&& 0 < nLength)
{
pBuffer[0] = '\0';
}
return fldOutput;
}
LBUF_OFFSET nWidth = static_cast<LBUF_OFFSET>(nWidth0);
if (nLength < nWidth)
{
nWidth = static_cast<LBUF_OFFSET>(nLength);
}
mux_cursor curPos(0, 0);
mux_field fldLimit(nLength, nWidth);
mux_field fldTransition(0, 0);
mux_field fldNormal(0, 0);
const UTF8 *pTransition = nullptr, *pNormal = nullptr;
size_t nNormalBytes = 0, nTransition = 0;
ColorState csCurrent = CS_NORMAL, csNext = CS_NORMAL;
while ('\0' != pString[curPos.m_byte])
{
int iCode = mux_color(pString + curPos.m_byte);
size_t nPointBytes = utf8_FirstByte[static_cast<unsigned char>(pString[curPos.m_byte])];
if (nPointBytes >= UTF8_CONTINUE)
{
nPointBytes = UTF8_SIZE1;
}
if (nPointBytes > nLength - curPos.m_byte)
{
nPointBytes = nLength - curPos.m_byte;
}
if (0 == nPointBytes)
{
break;
}
mux_cursor curPoint(static_cast<LBUF_OFFSET>(nPointBytes), 1);
if (COLOR_NOTCOLOR != iCode)
{
csNext = UpdateColorState(csNext, iCode, pString + curPos.m_byte);
}
else if (nullptr == strchr("\r\n\t", pString[curPos.m_byte]))
{
int nPointWidth = ConsoleWidth(pString + curPos.m_byte);
mux_field fldPoint(static_cast<LBUF_OFFSET>(nPointBytes), static_cast<LBUF_OFFSET>(nPointWidth));
if (csCurrent != csNext)
{
pTransition = ColorTransitionBinary(csCurrent, csNext, &nTransition);
pNormal = ColorBinaryNormal(csNext, &nNormalBytes);
fldNormal(nNormalBytes, 0);
}
else
{
nTransition = 0;
}
fldTransition(nTransition, 0);
if (fldOutput + fldTransition + fldPoint + fldNormal <= fldLimit)
{
if (0 < nTransition)
{
memcpy(pBuffer + fldOutput.m_byte, pTransition, nTransition);
csCurrent = csNext;
}
fldOutput += fldTransition;
for (size_t j = 0; j < fldPoint.m_byte; j++)
{
pBuffer[fldOutput.m_byte + j] = pString[curPos.m_byte + j];
}
fldOutput += fldPoint;
}
else
{
break;
}
}
curPos += curPoint;
}
if (csCurrent != csNext)
{
pNormal = ColorBinaryNormal(csCurrent, &nNormalBytes);
fldNormal(nNormalBytes, 0);
}
if ( 0 < nNormalBytes
&& fldOutput + fldNormal <= fldLimit)
{
memcpy(pBuffer + fldOutput.m_byte, pNormal, nNormalBytes);
fldOutput += fldNormal;
}
pBuffer[fldOutput.m_byte] = '\0';
return fldOutput;
}
// TruncateToBuffer()
//
// pString is parsed into alternating runs of text and color. These runs are
// then encoded into the given buffer with proper truncation. Every run of
// text will be of the same color. The color is collapsed into the minimal
// expression necessary to change from the color of the last run of text to
// the color of the next run of text. The initial color state and last color
// state are both CS_NORMAL.
//
// Parsing runs of text: As long as mux_color() returns COLOR_NOTCOLOR, we are
// in a run of text.
//
// Parsing runs of color: As long as mux_color() returns something besides
// COLOR_NOTCOLOR, we are in a run of color code points and use
// UpdateColorState() to merge the color code point into the current color
// state.
//
// It is sometimes not necessary to parse the entire string. Once we truncate
// a run of text, we know that no runs of text after the truncated one will
// fit either.
//
// The initial state is { CS_NORMAL, "" }. In turn, new runs of text,
// { CS(i), TEXT(i) } are encoded. To encode { CS(i+1), TEXT(i+1) } on the
// end of { CS(i), TEXT(i) }, we use ColorTransitionBinary(CS(i), CS(i+1), ...)
// and ColorBinaryNormal(CS(i+1), ...) to determine the two transitions. If
// there isn't enough room remaining in the buffer for these transitions,
// TEXT(i+1), TEXT(i+1) is truncated until there is room. If TEXT(i+1) is
// truncated to zero, neither color transition nor any of TEXT(i+1) is used.
//
size_t TruncateToBuffer
(
const UTF8 *pString,
UTF8 *pBuffer,
size_t nBuffer
)
{
size_t nOutput = 0;
if ( nullptr == pBuffer
|| nullptr == pString
|| 0 == nBuffer
|| '\0' == pString[0])
{
if (nullptr != pBuffer)
{
pBuffer[0] = '\0';
}
return nOutput;
}
size_t nNormal;
const UTF8 *pNormal;
ColorState csLast = CS_NORMAL;
ColorState csCurrent = CS_NORMAL;
bool bText = false;
const UTF8 *p = pString;
bool bTruncated = false;
while ( '\0' != p[0]
&& !bTruncated)
{
// Parse a run of color code points.
//
int iCode;
while ( ( UTF8_SIZE3 == utf8_FirstByte[p[0]]
|| UTF8_SIZE4 == utf8_FirstByte[p[0]])
&& COLOR_NOTCOLOR != (iCode = mux_color(p)))
{
csCurrent = UpdateColorState(csCurrent, iCode, p);
size_t nAdvance = utf8_advance_nul(p);
if (0 == nAdvance)
{
break;
}
p += nAdvance;
}
// Parse a run of text. A run of text is always ended by '\0' and
// sometimes by '\xEF' since all color code points start with '\xEF'.
//
bText = false;
size_t nTextRun = 0;
const UTF8 *pTextRun = p;
for (;;)
{
const UTF8 *pEF, *pF3;
if (nullptr != (pEF = reinterpret_cast<const UTF8 *>(strchr(reinterpret_cast<const char *>(p), '\xEF'))))
{
nTextRun += pEF - p;
p = pEF;
if (COLOR_NOTCOLOR != mux_color(p))
{
break;
}
size_t nAdvance = utf8_advance_nul(p);
nTextRun += nAdvance;
p += nAdvance;
}
else if (nullptr != (pF3 = reinterpret_cast<const UTF8 *>(strchr(reinterpret_cast<const char *>(p), '\xF3'))))
{
nTextRun += pF3 - p;
p = pF3;
if (COLOR_NOTCOLOR != mux_color(p))
{
break;
}
size_t nAdvance = utf8_advance_nul(p);
nTextRun += nAdvance;
p += nAdvance;
}
else
{
size_t n = strlen(reinterpret_cast<const char *>(p));
nTextRun += n;
p += n;
break;
}
}
// We have either reached a color code point or end of the string.
// We have seen { csCurrent, (nTextRun, pTextRun) }. Before we parse
// further, we need to encode this into the destination buffer.
// There is a color transition, then a possibly truncated run of text
// followed by another color transition to CS_NORMAL. We won't lay
// anything down unless there is room for at least one character of
// the text.
//
if (0 < nTextRun)
{
// Calculate the two transitions.
//
size_t nTransition;
const UTF8 *pTransition = ColorTransitionBinary(csLast, csCurrent, &nTransition);
pNormal = ColorBinaryNormal(csCurrent, &nNormal);
size_t nMinChar = utf8_advance_nul(pTextRun);
if (0 == nMinChar)
{
nMinChar = 1;
}
if (nOutput + nTransition + nMinChar + nNormal <= nBuffer)
{
// Lay down the initial color transition.
//
if (0 < nTransition)
{
memcpy(pBuffer + nOutput, pTransition, nTransition);
nOutput += nTransition;
csLast = csCurrent;
}
if ( nBuffer < nOutput + nTextRun + nNormal
&& nOutput + nNormal <= nBuffer)
{
// We need to truncate the text.
//
nTextRun = nBuffer - (nOutput + nNormal);
while ( 0 < nTextRun
&& UTF8_CONTINUE <= utf8_FirstByte[pTextRun[nTextRun]])
{
nTextRun--;
}
bTruncated = true;
}
// Lay down text.
//
bText = true;
memcpy(pBuffer + nOutput, pTextRun, nTextRun);
nOutput += nTextRun;
// We have left room for the transition to CS_NORMAL, but it
// isn't laid down.
//
}
}
}
pNormal = ColorBinaryNormal((bText)?csCurrent:csLast, &nNormal);
if ( 0 < nNormal
&& nOutput + nNormal <= nBuffer)
{
memcpy(pBuffer + nOutput, pNormal, nNormal);
nOutput += nNormal;
}
pBuffer[nOutput] = '\0';
return nOutput;
}
mux_field PadField( UTF8 *pBuffer, size_t nMaxBytes, LBUF_OFFSET nMinWidth,
mux_field fldOutput)
{
if (nullptr == pBuffer)
{
return fldMin;
}
while ( fldOutput.m_byte < nMaxBytes
&& fldOutput.m_column < nMinWidth)
{
pBuffer[fldOutput.m_byte] = static_cast<UTF8>(' ');
fldOutput += fldAscii;
}
if (fldOutput.m_byte <= nMaxBytes)
{
pBuffer[fldOutput.m_byte] = '\0';
}
return fldOutput;
}
void ItemToList_Init(ITL *p, UTF8 *arg_buff, UTF8 **arg_bufc,
UTF8 arg_chPrefix, UTF8 arg_chSep)
{
p->bFirst = true;
p->chPrefix = arg_chPrefix;
p->chSep = arg_chSep;
p->buff = arg_buff;
p->bufc = arg_bufc;
p->nBufferAvailable = LBUF_SIZE - (*arg_bufc - arg_buff) - 1;
}
bool ItemToList_AddInteger(ITL *pContext, int i)
{
UTF8 smbuf[SBUF_SIZE];
UTF8 *p = smbuf;
if ( !pContext->bFirst
&& pContext->chSep)
{
*p++ = pContext->chSep;
}
if (pContext->chPrefix)
{
*p++ = pContext->chPrefix;
}
p += mux_ltoa(i, p);
size_t nLen = p - smbuf;
if ( pContext->nBufferAvailable < nLen
|| sizeof(smbuf) < nLen)
{
// Out of room.
//
return false;
}
if (pContext->bFirst)
{
pContext->bFirst = false;
}
memcpy(*(pContext->bufc), smbuf, nLen);
*(pContext->bufc) += nLen;
pContext->nBufferAvailable -= nLen;
return true;
}
bool ItemToList_AddInteger64(ITL *pContext, int64_t i64)
{
UTF8 smbuf[SBUF_SIZE];
UTF8 *p = smbuf;
if ( !pContext->bFirst
&& pContext->chSep)
{
*p++ = pContext->chSep;
}
if (pContext->chPrefix)
{
*p++ = pContext->chPrefix;
}
p += mux_i64toa(i64, p);
size_t nLen = p - smbuf;
if ( pContext->nBufferAvailable < nLen
|| sizeof(smbuf) < nLen)
{
// Out of room.
//
return false;
}
if (pContext->bFirst)
{
pContext->bFirst = false;
}
memcpy(*(pContext->bufc), smbuf, nLen);
*(pContext->bufc) += nLen;
pContext->nBufferAvailable -= nLen;
return true;
}
bool ItemToList_AddStringLEN(ITL *pContext, size_t nStr, const UTF8 *pStr)
{
size_t nLen = nStr;
if ( !pContext->bFirst
&& pContext->chSep)
{
nLen++;
}
if (pContext->chPrefix)
{
nLen++;
}
if (nLen > pContext->nBufferAvailable)
{
// Out of room.
//
return false;
}
UTF8 *p = *(pContext->bufc);
if (pContext->bFirst)
{
pContext->bFirst = false;
}
else if (pContext->chSep)
{
*p++ = pContext->chSep;
}
if (pContext->chPrefix)
{
*p++ = pContext->chPrefix;
}
memcpy(p, pStr, nStr);
*(pContext->bufc) += nLen;
pContext->nBufferAvailable -= nLen;
return true;
}
bool ItemToList_AddString(ITL *pContext, const UTF8 *pStr)
{
size_t nStr = strlen(reinterpret_cast<const char *>(pStr));
return ItemToList_AddStringLEN(pContext, nStr, pStr);
}
void ItemToList_Final(ITL *pContext)
{
**(pContext->bufc) = '\0';
}
// mux_stricmp - Compare two strings ignoring case.
//
int mux_stricmp(const UTF8 *a, const UTF8 *b)
{
// ASCII fast path: compare via tolower table without entering
// the Unicode state machine. Falls through to the full path
// when a non-ASCII byte is encountered.
//
while (*a && *b && *a < 0x80 && *b < 0x80)
{
unsigned char la = mux_tolower_ascii[*a];
unsigned char lb = mux_tolower_ascii[*b];
if (la != lb)
{
return (la < lb) ? -1 : 1;
}
a++;
b++;
}
for (;;)
{
if ('\0' == *a || '\0' == *b)
{
// Compare terminating bytes.
//
if (*a < *b) return -1;
if (*a > *b) return 1;
return 0;
}
// Get lowercased bytes for each code point.
//
UTF8 la[4], lb[4];
size_t na, nb;
bool bXorA;
const string_desc *qA = mux_tolower(a, bXorA);
if (nullptr == qA)
{
na = utf8_FirstByte[static_cast<unsigned char>(*a)];
if (na >= UTF8_CONTINUE) na = 1;
for (size_t j = 0; j < na; j++) la[j] = a[j];
}
else
{
na = qA->n_bytes;
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = a[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
bool bXorB;
const string_desc *qB = mux_tolower(b, bXorB);
if (nullptr == qB)
{
nb = utf8_FirstByte[static_cast<unsigned char>(*b)];
if (nb >= UTF8_CONTINUE) nb = 1;
for (size_t j = 0; j < nb; j++) lb[j] = b[j];
}
else
{
nb = qB->n_bytes;
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = b[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
// Compare the lowercased code-point bytes.
//
size_t nMin = (na < nb) ? na : nb;
for (size_t j = 0; j < nMin; j++)
{
if (la[j] < lb[j]) return -1;
if (la[j] > lb[j]) return 1;
}
if (na < nb) return -1;
if (na > nb) return 1;
a += na;
b += nb;
}
}
// mux_memicmp - Compare two buffers ignoring case (Unicode-aware).
// Bounded by byte count n from each buffer.
//
int mux_memicmp(const void *p1_arg, const void *p2_arg, size_t n)
{
const UTF8 *p1 = reinterpret_cast<const UTF8 *>(p1_arg);
const UTF8 *p2 = reinterpret_cast<const UTF8 *>(p2_arg);
const UTF8 *p1End = p1 + n;
const UTF8 *p2End = p2 + n;
while (p1 < p1End && p2 < p2End)
{
UTF8 la[4], lb[4];
size_t na, nb;
size_t remA = static_cast<size_t>(p1End - p1);
size_t srcA = utf8_FirstByte[static_cast<unsigned char>(*p1)];
if (srcA >= UTF8_CONTINUE)
{
srcA = UTF8_SIZE1;
}
bool bValidA = (srcA <= remA);
if (bValidA)
{
for (size_t i = 1; i < srcA; i++)
{
if (UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(p1[i])])
{
bValidA = false;
break;
}
}
}
if (!bValidA)
{
srcA = UTF8_SIZE1;
}
UTF8 cpA[5];
for (size_t j = 0; j < srcA; j++)
{
cpA[j] = p1[j];
}
cpA[srcA] = '\0';
bool bXorA;
const string_desc *qA = bValidA ? mux_tolower(cpA, bXorA) : nullptr;
if (nullptr == qA)
{
na = srcA;
for (size_t j = 0; j < na; j++) la[j] = cpA[j];
}
else
{
na = qA->n_bytes;
if (bXorA && na > srcA)
{
na = srcA;
}
if (na > remA)
{
na = remA;
}
if (bXorA)
{
for (size_t j = 0; j < na; j++) la[j] = cpA[j] ^ qA->p[j];
}
else
{
for (size_t j = 0; j < na; j++) la[j] = qA->p[j];
}
}
size_t remB = static_cast<size_t>(p2End - p2);
size_t srcB = utf8_FirstByte[static_cast<unsigned char>(*p2)];
if (srcB >= UTF8_CONTINUE)
{
srcB = UTF8_SIZE1;
}
bool bValidB = (srcB <= remB);
if (bValidB)
{
for (size_t i = 1; i < srcB; i++)
{
if (UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(p2[i])])
{
bValidB = false;
break;
}
}
}
if (!bValidB)
{
srcB = UTF8_SIZE1;
}
UTF8 cpB[5];
for (size_t j = 0; j < srcB; j++)
{
cpB[j] = p2[j];
}
cpB[srcB] = '\0';
bool bXorB;
const string_desc *qB = bValidB ? mux_tolower(cpB, bXorB) : nullptr;
if (nullptr == qB)
{
nb = srcB;
for (size_t j = 0; j < nb; j++) lb[j] = cpB[j];
}
else
{
nb = qB->n_bytes;
if (bXorB && nb > srcB)
{
nb = srcB;
}
if (nb > remB)
{
nb = remB;
}
if (bXorB)
{
for (size_t j = 0; j < nb; j++) lb[j] = cpB[j] ^ qB->p[j];
}
else
{
for (size_t j = 0; j < nb; j++) lb[j] = qB->p[j];
}
}
size_t nMin = (na < nb) ? na : nb;
for (size_t j = 0; j < nMin; j++)
{
if (la[j] < lb[j]) return -1;
if (la[j] > lb[j]) return 1;
}
if (na < nb) return -1;
if (na > nb) return 1;
p1 += na;
p2 += nb;
}
if (p1 < p1End) return 1;
if (p2 < p2End) return -1;
return 0;
}
// mux_strlwr - Convert string to all lower case.
//
UTF8 *mux_strlwr(const UTF8 *a, size_t &n)
{
static UTF8 Buffer[LBUF_SIZE];
n = 0;
while ('\0' != *a)
{
size_t j;
size_t src = utf8_FirstByte[static_cast<unsigned char>(*a)];
if (src >= UTF8_CONTINUE)
{
src = UTF8_SIZE1;
}
else
{
for (j = 1; j < src; j++)
{
if ( '\0' == a[j]
|| UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(a[j])])
{
src = UTF8_SIZE1;
break;
}
}
}
size_t out = src;
bool bXor;
const string_desc *qDesc = mux_tolower(a, bXor);
if (nullptr == qDesc)
{
if (LBUF_SIZE-1 < n + out)
{
break;
}
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else
{
out = qDesc->n_bytes;
if ( bXor
&& out != src)
{
out = src;
qDesc = nullptr;
bXor = false;
}
if (LBUF_SIZE-1 < n + out)
{
break;
}
if (nullptr == qDesc)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else if (bXor)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j] ^ qDesc->p[j];
}
}
else
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = qDesc->p[j];
}
}
}
n += out;
a += src;
}
Buffer[n] = '\0';
return Buffer;
}
// mux_strupr - Convert string to all upper case.
//
UTF8 *mux_strupr(const UTF8 *a, size_t &n)
{
static UTF8 Buffer[LBUF_SIZE];
n = 0;
while ('\0' != *a)
{
size_t j;
size_t src = utf8_FirstByte[static_cast<unsigned char>(*a)];
if (src >= UTF8_CONTINUE)
{
src = UTF8_SIZE1;
}
else
{
for (j = 1; j < src; j++)
{
if ( '\0' == a[j]
|| UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(a[j])])
{
src = UTF8_SIZE1;
break;
}
}
}
size_t out = src;
bool bXor;
const string_desc *qDesc = mux_toupper(a, bXor);
if (nullptr == qDesc)
{
if (LBUF_SIZE-1 < n + out)
{
break;
}
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else
{
out = qDesc->n_bytes;
if ( bXor
&& out != src)
{
out = src;
qDesc = nullptr;
bXor = false;
}
if (LBUF_SIZE-1 < n + out)
{
break;
}
if (nullptr == qDesc)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else if (bXor)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j] ^ qDesc->p[j];
}
}
else
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = qDesc->p[j];
}
}
}
n += out;
a += src;
}
Buffer[n] = '\0';
return Buffer;
}
// mux_toupper_first - Uppercase the first UTF-8 code point in-place in a
// buffer. buff points to the first byte to transform, bufc points to the
// current end-of-data pointer, nBufferTotal is the total buffer size.
//
// For XOR transforms (same byte length), overwrites in place.
// For literal transforms (may change byte length), shifts the remaining
// buffer contents via memmove and adjusts *bufc.
//
void mux_toupper_first(UTF8 *buff, UTF8 **bufc, size_t nBufferTotal)
{
if ( nullptr == buff
|| nullptr == bufc
|| nullptr == *bufc
|| nBufferTotal < 1
|| buff >= *bufc
|| '\0' == *buff)
{
return;
}
size_t nOld = utf8_FirstByte[static_cast<unsigned char>(*buff)];
if (nOld >= UTF8_CONTINUE)
{
return;
}
// Validate that we have enough bytes.
//
size_t nUsed = *bufc - buff;
if (nOld > nUsed)
{
return;
}
for (size_t j = 1; j < nOld; j++)
{
if ( j >= nUsed
|| UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(buff[j])])
{
return;
}
}
bool bXor;
const string_desc *qDesc = mux_toupper(buff, bXor);
if (nullptr == qDesc)
{
// No transform for this code point — already uppercase or not a letter.
//
return;
}
size_t nNew = qDesc->n_bytes;
if (bXor)
{
// XOR transform: same byte length, overwrite in place.
//
if ( nNew != nOld
|| nNew > nUsed)
{
return;
}
for (size_t j = 0; j < nNew; j++)
{
buff[j] ^= qDesc->p[j];
}
}
else
{
// Literal transform: byte length may differ.
//
size_t nTail = nUsed - nOld;
// Check that the result fits in the buffer.
//
size_t nBufferEnd = nBufferTotal - 1;
size_t nBuffStart = buff - (*bufc - nUsed); // offset of buff from buffer start
if (nBuffStart + nNew + nTail > nBufferEnd)
{
// Would overflow — truncate by not transforming.
//
return;
}
// Shift the tail to make room (or shrink).
//
if (nNew != nOld)
{
memmove(buff + nNew, buff + nOld, nTail + 1); // +1 for NUL
*bufc += (nNew - nOld);
}
// Write the transformed bytes.
//
for (size_t j = 0; j < nNew; j++)
{
buff[j] = qDesc->p[j];
}
}
}
// mux_foldmatch - alias for matching.
//
UTF8 *mux_foldmatch(const UTF8 *a, size_t &n, bool &fChanged)
{
static UTF8 Buffer[LBUF_SIZE];
n = 0;
fChanged = false;
while ('\0' != *a)
{
size_t j;
size_t src = utf8_FirstByte[static_cast<unsigned char>(*a)];
if (src >= UTF8_CONTINUE)
{
src = UTF8_SIZE1;
}
else
{
for (j = 1; j < src; j++)
{
if ( '\0' == a[j]
|| UTF8_CONTINUE != utf8_FirstByte[static_cast<unsigned char>(a[j])])
{
src = UTF8_SIZE1;
break;
}
}
}
size_t out = src;
bool bXor;
const string_desc *qDesc = mux_foldmatch(a, bXor);
if (nullptr == qDesc)
{
if (LBUF_SIZE-1 < n + out)
{
break;
}
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else
{
out = qDesc->n_bytes;
if ( bXor
&& out != src)
{
out = src;
qDesc = nullptr;
bXor = false;
}
if (LBUF_SIZE-1 < n + out)
{
break;
}
if (nullptr == qDesc)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j];
}
}
else if (bXor)
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = a[j] ^ qDesc->p[j];
}
}
else
{
for (j = 0; j < out; j++)
{
Buffer[n+j] = qDesc->p[j];
}
}
fChanged = true;
}
n += out;
a += src;
}
Buffer[n] = '\0';
return Buffer;
}
// Render a double in printf's %f / %e / %g shapes using David M. Gay's dtoa
// for the digits.
//
// Not snprintf: this keeps float rendering on the same correctly-rounded
// digit generator the rest of the tree already uses (mux_ftoa, fval,
// NearestPretty all go through mux_dtoa), rather than making output depend on
// the host libc. mux_ftoa itself is not usable here -- it is MUX's own float
// rendering and switches to exponent form once the decimal point passes 18,
// which %f never does.
//
// dtoa gives digits and a decimal-point position with trailing zeros
// suppressed, so the padding back out to the requested precision is ours.
// decpt == 9999 signals Inf/NaN.
//
// Returns the length written, or 0 with *pbOverflow set when the result will
// not fit nScratch. The caller treats that as truncation; before %f was
// implemented at all this path was a mux_assert(0), so truncating is strictly
// an improvement on aborting the process.
//
#define MUX_FLOAT_SCRATCH 512
static size_t mux_format_double(UTF8 *pScratch, size_t nScratch, double dval,
UTF8 chConv, int nPrec, bool *pbOverflow)
{
*pbOverflow = false;
bool bUpper = ( 'F' == chConv
|| 'E' == chConv
|| 'G' == chConv);
UTF8 chLower = static_cast<UTF8>(bUpper ? chConv - 'A' + 'a' : chConv);
int decpt = 0;
int bNeg = 0;
UTF8 *rve = nullptr;
UTF8 *pDigits = nullptr;
// %g selects between %e and %f on the exponent, so it has to see the
// significant digits before it can choose.
//
int nSig = 0;
if ('g' == chLower)
{
nSig = (0 == nPrec) ? 1 : nPrec;
pDigits = mux_dtoa(dval, 2, nSig, &decpt, &bNeg, &rve);
}
else if ('e' == chLower)
{
pDigits = mux_dtoa(dval, 2, nPrec + 1, &decpt, &bNeg, &rve);
}
else
{
pDigits = mux_dtoa(dval, 3, nPrec, &decpt, &bNeg, &rve);
}
if (nullptr == pDigits)
{
*pbOverflow = true;
return 0;
}
size_t nDigits = static_cast<size_t>(rve - pDigits);
size_t q = 0;
// Inf and NaN. printf spells these "inf"/"nan", uppercased for the
// uppercase conversions; a sign is carried on infinity only.
//
if (9999 == decpt)
{
const char *pWord = ('n' == pDigits[0] || 'N' == pDigits[0]) ? "nan" : "inf";
if ( bNeg
&& 'i' == pWord[0])
{
pScratch[q++] = '-';
}
for (int i = 0; i < 3; i++)
{
pScratch[q++] = static_cast<UTF8>(bUpper ? pWord[i] - 'a' + 'A' : pWord[i]);
}
pScratch[q] = '\0';
return q;
}
// dtoa returns nothing for zero. Treat it as a single '0' digit sitting
// just left of the point, which is what the assembly below expects.
//
UTF8 chZero = '0';
if (0 == nDigits)
{
pDigits = &chZero;
nDigits = 1;
decpt = 1;
}
// Resolve %g to whichever of %e / %f it renders as. C's rule: use %e
// when the exponent is below -4 or at least the precision.
//
bool bStripTrailing = false;
int nExp = decpt - 1;
if ('g' == chLower)
{
bStripTrailing = true;
if ( nExp < -4
|| nSig <= nExp)
{
chLower = 'e';
nPrec = nSig - 1;
}
else
{
chLower = 'f';
nPrec = nSig - 1 - nExp;
if (nPrec < 0)
{
nPrec = 0;
}
}
}
// Worst case is %f of DBL_MAX: ~309 integer digits, plus the point, plus
// the precision. Bail rather than overrun.
//
size_t nWorst = (('f' == chLower) ? (decpt > 0 ? static_cast<size_t>(decpt) : 1)
: 1)
+ static_cast<size_t>(nPrec) + 16;
if (nScratch <= nWorst)
{
*pbOverflow = true;
return 0;
}
if (bNeg)
{
pScratch[q++] = '-';
}
// %g suppresses trailing zeros, but only inside the fraction: the strip
// must never reach back into the integer digits, or "%.1g" of 0 renders
// as the empty string instead of "0". iDot records where the fraction
// begins; bDot says whether there is one at all.
//
size_t iDot = 0;
bool bDot = false;
if ('e' == chLower)
{
pScratch[q++] = pDigits[0];
if (0 < nPrec)
{
iDot = q;
bDot = true;
pScratch[q++] = '.';
for (int i = 0; i < nPrec; i++)
{
size_t k = static_cast<size_t>(i) + 1;
pScratch[q++] = (k < nDigits) ? pDigits[k] : '0';
}
}
if ( bStripTrailing
&& bDot)
{
while ( iDot + 1 < q
&& '0' == pScratch[q-1]) q--;
if (iDot + 1 == q) q = iDot;
}
pScratch[q++] = static_cast<UTF8>(bUpper ? 'E' : 'e');
int nShow = nExp;
pScratch[q++] = static_cast<UTF8>((nShow < 0) ? '-' : '+');
if (nShow < 0) nShow = -nShow;
if (nShow < 10)
{
pScratch[q++] = '0';
pScratch[q++] = static_cast<UTF8>('0' + nShow);
}
else
{
q += mux_ltoa(nShow, pScratch + q);
}
}
else
{
// Integer part.
//
if (decpt <= 0)
{
pScratch[q++] = '0';
}
else
{
for (int i = 0; i < decpt; i++)
{
size_t k = static_cast<size_t>(i);
pScratch[q++] = (k < nDigits) ? pDigits[k] : '0';
}
}
if (0 < nPrec)
{
iDot = q;
bDot = true;
pScratch[q++] = '.';
for (int i = 0; i < nPrec; i++)
{
int k = decpt + i;
pScratch[q++] = ( 0 <= k
&& static_cast<size_t>(k) < nDigits)
? pDigits[static_cast<size_t>(k)] : '0';
}
}
if ( bStripTrailing
&& bDot)
{
while ( iDot + 1 < q
&& '0' == pScratch[q-1]) q--;
if (iDot + 1 == q) q = iDot;
}
}
pScratch[q] = '\0';
return q;
}
// ---------------------------------------------------------------------------
// POSIX %N$ positional arguments for mux_vsnprintf (#1623).
//
// gettext catalogues reorder multi-conversion msgids with %1$s / %2$d. The
// sequential path below cannot resynchronise a va_list cursor, so positional
// formats are handled by: (1) scanning every conversion for its 1-based index
// and type, (2) pulling arguments 1..max from va_list in index order, (3)
// formatting with those saved values. The sequential path is unchanged when
// the format has no %N$.
//
// Mix of positional and non-positional conversions (other than %%) is rejected
// with the #1429 stop policy.
// ---------------------------------------------------------------------------
#define MUX_PRINTF_MAX_ARGS 32
enum mux_printf_akind
{
MPA_NONE = 0,
MPA_INT,
MPA_LONG,
MPA_I64,
MPA_UINT,
MPA_ULONG,
MPA_U64,
MPA_STR,
MPA_PTR,
MPA_DOUBLE,
MPA_CHAR
};
struct mux_printf_arg
{
mux_printf_akind kind;
union
{
int i;
long l;
int64_t i64;
unsigned int u;
unsigned long ul;
uint64_t u64;
UTF8 *s;
void *p;
double d;
unsigned int c;
} v;
};
// True if pFmt contains at least one %N$ conversion (N >= 1).
//
static bool mux_fmt_has_positional(const UTF8 *pFmt)
{
if (nullptr == pFmt)
{
return false;
}
for (const UTF8 *p = pFmt; '\0' != *p; p++)
{
if ('%' != *p)
{
continue;
}
p++;
if ('\0' == *p)
{
break;
}
if ('%' == *p)
{
continue;
}
// Position is the first field after '%': digits then '$'.
//
if ( *p < '1'
|| *p > '9')
{
continue;
}
while ( *p >= '0'
&& *p <= '9')
{
p++;
}
if ('$' == *p)
{
return true;
}
if ('\0' == *p)
{
break;
}
}
return false;
}
// Map a conversion letter + nLongs to an argument kind.
//
static mux_printf_akind mux_fmt_arg_kind(UTF8 ch, int nLongs)
{
switch (ch)
{
case 'd':
case 'i':
if (0 == nLongs)
{
return MPA_INT;
}
if (1 == nLongs)
{
return MPA_LONG;
}
if (2 == nLongs)
{
return MPA_I64;
}
return MPA_NONE;
case 'u':
case 'o':
case 'x':
case 'X':
if (0 == nLongs)
{
return MPA_UINT;
}
if (1 == nLongs)
{
return MPA_ULONG;
}
if (2 == nLongs)
{
return MPA_U64;
}
return MPA_NONE;
case 's':
return (0 == nLongs) ? MPA_STR : MPA_NONE;
case 'p':
return (0 == nLongs) ? MPA_PTR : MPA_NONE;
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
return MPA_DOUBLE;
case 'c':
return MPA_CHAR;
default:
return MPA_NONE;
}
}
// Scan pFmt for every conversion: record kind[pos] (1-based). *pMaxPos is
// the highest index referenced. Returns false on mix of positional and
// sequential, type conflict, or an unparseable conversion.
//
static bool mux_fmt_scan_kinds(
const UTF8 *pFmt, mux_printf_akind *kinds, int *pMaxPos)
{
for (int i = 0; i <= MUX_PRINTF_MAX_ARGS; i++)
{
kinds[i] = MPA_NONE;
}
*pMaxPos = 0;
bool bAnyPos = false;
bool bAnySeq = false;
int nNextSeq = 1;
size_t ncpFmt = 0;
if ( nullptr == pFmt
|| !utf8_strlen(pFmt, ncpFmt))
{
return true;
}
size_t iFmt = 0;
while (0 != ncpFmt)
{
if ('%' != pFmt[iFmt])
{
size_t d = utf8_FirstByte[pFmt[iFmt]];
iFmt += d;
ncpFmt--;
continue;
}
iFmt++;
ncpFmt--;
if (0 == ncpFmt)
{
return false;
}
if ('%' == pFmt[iFmt])
{
iFmt++;
ncpFmt--;
continue;
}
int nPos = 0;
int nLongs = 0;
// Optional N$
//
if ( pFmt[iFmt] >= '1'
&& pFmt[iFmt] <= '9')
{
size_t j = iFmt;
size_t n = 0;
size_t nDig = 0;
while ( nDig < ncpFmt
&& pFmt[j] >= '0'
&& pFmt[j] <= '9')
{
n = 10 * n + static_cast<size_t>(pFmt[j] - '0');
j++;
nDig++;
}
if ( nDig < ncpFmt
&& '$' == pFmt[j]
&& n > 0
&& n <= MUX_PRINTF_MAX_ARGS)
{
nPos = static_cast<int>(n);
iFmt = j + 1;
ncpFmt -= nDig + 1;
bAnyPos = true;
}
}
if (0 == nPos)
{
nPos = nNextSeq++;
bAnySeq = true;
}
if ( bAnyPos
&& bAnySeq)
{
return false;
}
// Skip flags / width / precision / length to the type letter.
//
while (0 != ncpFmt)
{
UTF8 ch = pFmt[iFmt];
if ( 'd' == ch || 'i' == ch || 's' == ch || 'u' == ch
|| 'o' == ch || 'x' == ch || 'X' == ch || 'p' == ch
|| 'f' == ch || 'F' == ch || 'e' == ch || 'E' == ch
|| 'g' == ch || 'G' == ch || 'c' == ch)
{
mux_printf_akind k = mux_fmt_arg_kind(ch, nLongs);
if (MPA_NONE == k)
{
return false;
}
if ( MPA_NONE != kinds[nPos]
&& kinds[nPos] != k)
{
return false;
}
kinds[nPos] = k;
if (nPos > *pMaxPos)
{
*pMaxPos = nPos;
}
iFmt++;
ncpFmt--;
break;
}
else if ('l' == ch)
{
nLongs++;
iFmt++;
ncpFmt--;
}
else if ('z' == ch)
{
nLongs = (sizeof(size_t) == sizeof(unsigned long)) ? 1 : 2;
iFmt++;
ncpFmt--;
}
else if ( ('0' <= ch && ch <= '9')
|| '.' == ch
|| '-' == ch
|| '+' == ch
|| ' ' == ch
|| '#' == ch
|| '*' == ch)
{
// Width, precision, flags — including '*' which we do not
// support as a value but must skip past if present.
//
iFmt++;
ncpFmt--;
}
else
{
return false;
}
}
}
return true;
}
static bool mux_fmt_fill_args(
mux_printf_akind *kinds, int nMaxPos, va_list va, mux_printf_arg *args)
{
for (int i = 1; i <= nMaxPos; i++)
{
args[i].kind = kinds[i];
switch (kinds[i])
{
case MPA_INT:
args[i].v.i = va_arg(va, int);
break;
case MPA_LONG:
args[i].v.l = va_arg(va, long);
break;
case MPA_I64:
args[i].v.i64 = va_arg(va, int64_t);
break;
case MPA_UINT:
args[i].v.u = va_arg(va, unsigned int);
break;
case MPA_ULONG:
args[i].v.ul = va_arg(va, unsigned long);
break;
case MPA_U64:
args[i].v.u64 = va_arg(va, uint64_t);
break;
case MPA_STR:
args[i].v.s = va_arg(va, UTF8 *);
break;
case MPA_PTR:
args[i].v.p = va_arg(va, void *);
break;
case MPA_DOUBLE:
args[i].v.d = va_arg(va, double);
break;
case MPA_CHAR:
args[i].v.c = va_arg(va, unsigned int);
break;
case MPA_NONE:
// Gap in the position list — leave zeroed; a later conversion
// that references it will fail closed.
//
break;
default:
return false;
}
}
return true;
}
// mux_vsnprintf - Is an sprintf-like function that will not overflow
// a buffer of specific size. The size is give by count, and count
// should be chosen to include the '\0' termination.
//
// Returns: A number from 0 to count-1 that is the string length of
// the returned (possibly truncated) buffer.
//
// Supports POSIX %N$ positional conversions (#1623) when the format uses
// them; sequential formats keep the original single-pass path.
//
size_t DCL_CDECL mux_vsnprintf(UTF8 *pBuffer, size_t nBuffer, const UTF8 *pFmt, va_list va)
{
if ( nullptr == pBuffer
|| nBuffer < 1)
{
return 0;
}
size_t nLimit = nBuffer-1;
// Positional mode: materialise args, then format with saved values.
//
mux_printf_arg posArgs[MUX_PRINTF_MAX_ARGS + 1];
bool bPositional = false;
int nMaxPos = 0;
memset(posArgs, 0, sizeof(posArgs));
if ( nullptr != pFmt
&& mux_fmt_has_positional(pFmt))
{
mux_printf_akind kinds[MUX_PRINTF_MAX_ARGS + 1];
if ( !mux_fmt_scan_kinds(pFmt, kinds, &nMaxPos)
|| nMaxPos < 1
|| nMaxPos > MUX_PRINTF_MAX_ARGS
|| !mux_fmt_fill_args(kinds, nMaxPos, va, posArgs))
{
// Unparseable or mixed positional/sequential — #1429 stop:
// emit nothing beyond an empty string rather than walk va_list
// wrong. Callers already tolerate truncation.
//
pBuffer[0] = '\0';
return 0;
}
bPositional = true;
}
// Rather than copy a character at a time, some copies are deferred and performed in a single request.
//
size_t iFmtDeferred = 0;
size_t dDeferred = 0;
size_t iBuffer = 0;
size_t ncpFmt;
size_t iFmt = 0;
int nNextSeq = 1;
if ( nullptr != pFmt
&& utf8_strlen(pFmt, ncpFmt))
{
// Octal needs 22 digits for a 64-bit value plus the terminator, one
// more than I64BUF_SIZE allows for decimal. Floating point does not
// use this buffer at all -- see the 'f'/'e'/'g' branch, which formats
// straight into the output.
//
static UTF8 Buff[I64BUF_SIZE + 8];
while (0 != ncpFmt)
{
if ('%' != pFmt[iFmt])
{
// Ordinary character.
//
size_t d = utf8_FirstByte[pFmt[iFmt]];
size_t dProposed = dDeferred + d;
if (nLimit < iBuffer + dProposed)
{
if (0 < dDeferred)
{
// Unravel the deferred copy.
//
memcpy(pBuffer + iBuffer, pFmt + iFmtDeferred, dDeferred);
iBuffer += dDeferred;
dDeferred = 0;
}
goto done;
}
else if (0 == dDeferred)
{
iFmtDeferred = iFmt;
}
dDeferred = dProposed;
iFmt += d;
ncpFmt--;
}
else
{
if (0 < dDeferred)
{
// Unravel the deferred copy.
//
memcpy(pBuffer + iBuffer, pFmt + iFmtDeferred, dDeferred);
iBuffer += dDeferred;
dDeferred = 0;
}
size_t cbBuff;
size_t cpBuff;
size_t nWidth = 0;
size_t nPrecision = 0;
bool bLeft = false;
bool bZeroPadded = false;
bool bWidth = false;
bool bSawPeriod = false;
bool bPrecision = false;
int nLongs = 0;
int nArgPos = 0;
// Where this conversion spec starts, so an unimplemented one
// can be echoed literally rather than killing the process
// (#1429).
//
size_t iFmtSpec = iFmt;
iFmt++;
ncpFmt--;
// Optional POSIX position N$ immediately after '%' (#1623).
//
if ( bPositional
&& 0 != ncpFmt
&& pFmt[iFmt] >= '1'
&& pFmt[iFmt] <= '9')
{
size_t j = iFmt;
size_t n = 0;
size_t nDig = 0;
while ( nDig < ncpFmt
&& pFmt[j] >= '0'
&& pFmt[j] <= '9')
{
n = 10 * n + static_cast<size_t>(pFmt[j] - '0');
j++;
nDig++;
}
if ( nDig < ncpFmt
&& '$' == pFmt[j]
&& n > 0
&& n <= MUX_PRINTF_MAX_ARGS)
{
nArgPos = static_cast<int>(n);
iFmt = j + 1;
ncpFmt -= nDig + 1;
}
}
while (0 != ncpFmt)
{
if ( 'd' == pFmt[iFmt]
|| 'i' == pFmt[iFmt]
|| 's' == pFmt[iFmt]
|| 'u' == pFmt[iFmt]
|| 'o' == pFmt[iFmt]
|| 'x' == pFmt[iFmt]
|| 'X' == pFmt[iFmt]
|| 'p' == pFmt[iFmt]
|| 'f' == pFmt[iFmt]
|| 'F' == pFmt[iFmt]
|| 'e' == pFmt[iFmt]
|| 'E' == pFmt[iFmt]
|| 'g' == pFmt[iFmt]
|| 'G' == pFmt[iFmt])
{
UTF8 *pBuff = Buff;
UTF8 FBuff[MUX_FLOAT_SCRATCH];
// Resolve which saved arg (positional) or va_arg
// (sequential) to consume.
//
const mux_printf_arg *pArg = nullptr;
if (bPositional)
{
if (0 == nArgPos)
{
nArgPos = nNextSeq++;
}
if ( nArgPos < 1
|| nArgPos > nMaxPos
|| MPA_NONE == posArgs[nArgPos].kind)
{
goto done;
}
pArg = &posArgs[nArgPos];
}
if ( 'd' == pFmt[iFmt]
|| 'i' == pFmt[iFmt])
{
// Obtain and validate argument.
//
if (0 == nLongs)
{
int i = (nullptr != pArg) ? pArg->v.i
: va_arg(va, int);
cbBuff = cpBuff = mux_ltoa(i, Buff);
}
else if (1 == nLongs)
{
long int i = (nullptr != pArg) ? pArg->v.l
: va_arg(va, long int);
cbBuff = cpBuff = mux_ltoa(i, Buff);
}
else if (2 == nLongs)
{
int64_t i = (nullptr != pArg) ? pArg->v.i64
: va_arg(va, int64_t);
cbBuff = cpBuff = mux_i64toa(i, Buff);
}
else
{
goto done;
}
}
else if ('s' == pFmt[iFmt])
{
// Obtain and validate argument.
//
pBuff = (nullptr != pArg) ? pArg->v.s
: va_arg(va, UTF8 *);
if ( !utf8_strlen(pBuff, cpBuff)
|| 0 != nLongs)
{
goto done;
}
cbBuff = strlen(reinterpret_cast<char *>(pBuff));
if ( bPrecision
&& nPrecision < cpBuff)
{
// Need to walk cbBuff back to correspond to changes in cpBuff.
//
while (cpBuff != nPrecision)
{
do
{
cbBuff--;
} while (UTF8_CONTINUE <= utf8_FirstByte[pBuff[cbBuff]]);
cpBuff--;
}
}
}
else if ('p' == pFmt[iFmt])
{
if ( 0 != nLongs
|| bWidth)
{
goto done;
}
// Convert pointer to unsigned integer.
//
union
{
uintptr_t ui;
void *pv;
} u;
u.pv = (nullptr != pArg) ? pArg->v.p
: va_arg(va, void *);
#if SIZEOF_UINT_PTR <= SIZEOF_UNSIGNED_LONG
cbBuff = cpBuff = mux_utox(u.ui, Buff, true);
#elif SIZEOF_UINT_PTR <= SIZEOF_UNSIGNED_LONG_LONG
cbBuff = cpBuff = mux_ui64tox(u.ui, Buff, true);
#else
#error Size of pointer is larger size of largest known integer.
#endif
bWidth = true;
nWidth = 2*sizeof(uintptr_t);
bZeroPadded = true;
}
else if ( 'f' == pFmt[iFmt]
|| 'F' == pFmt[iFmt]
|| 'e' == pFmt[iFmt]
|| 'E' == pFmt[iFmt]
|| 'g' == pFmt[iFmt]
|| 'G' == pFmt[iFmt])
{
// Floating point. Before this, %f and friends
// fell through to the mux_assert(0) below and took
// the process down -- a standard C conversion this
// function happened not to implement was a server
// abort with no warning at the call site (#1382,
// and again in @list).
//
// Digits come from mux_dtoa, the same correctly
// rounded generator mux_ftoa/fval/NearestPretty
// use, so float output does not depend on the host
// libc. nLongs is ignored: "%lf" is double in
// printf, and "%Lf" never reaches here because 'L'
// is not parsed as a length modifier.
//
double dval = (nullptr != pArg) ? pArg->v.d
: va_arg(va, double);
int nPrec = bSawPeriod ? static_cast<int>(nPrecision) : 6;
bool bOverflow = false;
cbBuff = cpBuff = mux_format_double(FBuff,
sizeof(FBuff), dval, pFmt[iFmt], nPrec,
&bOverflow);
if (bOverflow)
{
goto done;
}
pBuff = FBuff;
}
else
{
bool bHex = ( 'x' == pFmt[iFmt]
|| 'X' == pFmt[iFmt]);
bool bOct = ('o' == pFmt[iFmt]);
bool bUpper = ('X' == pFmt[iFmt]);
// Obtain and validate argument.
//
if (0 == nLongs)
{
unsigned int ui = (nullptr != pArg) ? pArg->v.u
: va_arg(va, unsigned int);
cbBuff = cpBuff = bOct?mux_utoo(ui, Buff):(bHex?mux_utox(ui, Buff, bUpper):mux_utoa(ui, Buff));
}
else if (1 == nLongs)
{
unsigned long int ui = (nullptr != pArg) ? pArg->v.ul
: va_arg(va, unsigned long int);
cbBuff = cpBuff = bOct?mux_utoo(ui, Buff):(bHex?mux_utox(ui, Buff, bUpper):mux_utoa(ui, Buff));
}
else if (2 == nLongs)
{
uint64_t ui = (nullptr != pArg) ? pArg->v.u64
: va_arg(va, uint64_t);
cbBuff = cpBuff = bOct?mux_ui64too(ui, Buff):(bHex?mux_ui64tox(ui, Buff, bUpper):mux_ui64toa(ui, Buff));
}
else
{
goto done;
}
}
// Calculate and validate needed size. Numberic and
// string fields are at least the size of their width.
// String fields may have been truncated above by
// precision.
//
// Width is compared with the number of code points.
// Padding is always done with space or zero.
//
size_t nUsed = cbBuff;
size_t nPadding = 0;
if ( bWidth
&& cpBuff < nWidth)
{
nPadding = nWidth - cpBuff;
nUsed += nPadding;
}
if (nLimit < iBuffer + nUsed)
{
goto done;
}
// Apply leading padding if necessary.
//
if ( !bLeft
&& bWidth)
{
// Any signed conversion: the minus sign has to be
// laid down before zero-padding begins, or
// "%08.2f" of -3.5 renders as "0000-3.50".
//
if ( ( 'd' == pFmt[iFmt]
|| 'i' == pFmt[iFmt]
|| 'f' == pFmt[iFmt]
|| 'F' == pFmt[iFmt]
|| 'e' == pFmt[iFmt]
|| 'E' == pFmt[iFmt]
|| 'g' == pFmt[iFmt]
|| 'G' == pFmt[iFmt])
&& '-' == pBuff[0]
&& 0 < nPadding
&& bZeroPadded)
{
// The leading minus sign must be laid down before zero-padding begins.
//
pBuffer[iBuffer] = '-';
iBuffer++;
pBuff++;
cbBuff--;
cpBuff--;
}
while (0 < nPadding)
{
pBuffer[iBuffer] = bZeroPadded?'0':' ';
iBuffer++;
nPadding--;
}
}
// Apply string.
//
memcpy(pBuffer + iBuffer, pBuff, cbBuff);
iBuffer += cbBuff;
// Apply trailing padding if necessary.
//
if ( bLeft
&& bWidth)
{
while (0 < nPadding)
{
pBuffer[iBuffer] = bZeroPadded?'0':' ';
iBuffer++;
nPadding--;
}
}
iFmt++;
ncpFmt--;
break;
}
else if ('l' == pFmt[iFmt])
{
nLongs++;
iFmt++;
ncpFmt--;
}
else if ('z' == pFmt[iFmt])
{
// size_t/ssize_t length modifier. Map onto the
// existing nLongs tiers by actual width so both LP64
// (size_t == unsigned long) and LLP64 (size_t is
// 64-bit while long is 32-bit) marshal the va_arg
// type the caller actually pushed. Without this,
// "%zu" fell through to mux_assert(0) and aborted.
//
nLongs = (sizeof(size_t) == sizeof(unsigned long)) ? 1 : 2;
iFmt++;
ncpFmt--;
}
else if ( '0' <= pFmt[iFmt]
&& pFmt[iFmt] <= '9')
{
if (!bSawPeriod)
{
if (!bWidth)
{
if ('0' == pFmt[iFmt])
{
if (bZeroPadded)
{
goto done;
}
bZeroPadded = true;
}
else
{
nWidth = pFmt[iFmt] - '0';
bWidth = true;
}
}
else
{
nWidth = 10 * nWidth + pFmt[iFmt] - '0';
}
}
else
{
if (!bPrecision)
{
nPrecision = pFmt[iFmt] - '0';
bPrecision = true;
}
else
{
nPrecision = 10 * nPrecision + pFmt[iFmt] - '0';
}
}
iFmt++;
ncpFmt--;
}
else if ('.' == pFmt[iFmt])
{
bSawPeriod = true;
iFmt++;
ncpFmt--;
}
else if ('-' == pFmt[iFmt])
{
if (bLeft)
{
goto done;
}
bLeft = true;
iFmt++;
ncpFmt--;
}
else if ('c' == pFmt[iFmt])
{
unsigned int ch;
if (bPositional)
{
if (0 == nArgPos)
{
nArgPos = nNextSeq++;
}
if ( nArgPos < 1
|| nArgPos > nMaxPos
|| MPA_CHAR != posArgs[nArgPos].kind)
{
goto done;
}
ch = posArgs[nArgPos].v.c;
}
else
{
ch = va_arg(va, unsigned int);
}
if (nLimit < iBuffer + 1)
{
goto done;
}
pBuffer[iBuffer] = static_cast<UTF8>(ch);
iBuffer++;
iFmt++;
ncpFmt--;
break;
}
else if ('%' == pFmt[iFmt])
{
// "%%"
//
if (nLimit < iBuffer + 1)
{
goto done;
}
pBuffer[iBuffer] = '%';
iBuffer++;
iFmt++;
ncpFmt--;
break;
}
else
{
// An unimplemented conversion. This was mux_assert(0),
// which is a hard abort() in the shipping build --
// mux_assert has no NDEBUG guard -- so an ordinary
// looking T("%+d") took the whole game down. #1382
// produced two wizard-triggerable aborts exactly that
// way (@list cache and astbench), and both were fixed
// at the call site rather than here (#1429).
//
// Echo the remainder of the format verbatim and STOP
// interpreting. A bounded formatter already truncates
// when it runs out of room, so callers are written
// against "imperfect output" and not against "no
// server"; emitting the text rather than dropping it
// leaves the evidence visible without a debugger.
//
// Stopping is the part that is not optional. No
// va_arg was consumed for this spec, so every LATER
// conversion in the same format string would read the
// wrong argument, and there is no way to resynchronise
// without knowing what the unknown spec would have
// taken. Continuing was measured (#1445):
//
// "%+d|%d" 11, 22 -> "%+d|11" wrong arg
// "%+d|%s" 11, "tail" -> SIGSEGV
//
// The second hands an int to the %s path as a UTF8*
// and dereferences it. That trades a clean abort for
// a wild pointer, which is not an improvement -- so
// recovery stops at the first spec it cannot parse.
//
// Echoing the whole remainder rather than just this
// spec keeps the evidence intact: the offending spec
// appears in full, with the text that followed it,
// while nothing further is interpreted.
//
size_t nRest =
strlen(reinterpret_cast<const char *>(pFmt) + iFmtSpec);
if (nLimit < iBuffer + nRest)
{
nRest = nLimit - iBuffer;
}
memcpy(pBuffer + iBuffer, pFmt + iFmtSpec, nRest);
iBuffer += nRest;
goto done;
}
}
}
}
if (0 < dDeferred)
{
// Unravel the deferred copy.
//
memcpy(pBuffer + iBuffer, pFmt + iFmtDeferred, dDeferred);
iBuffer += dDeferred;
dDeferred = 0;
}
}
done:
pBuffer[iBuffer] = '\0';
return iBuffer;
}
void DCL_CDECL mux_sprintf(UTF8 *buff, size_t count, const UTF8 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
(void)mux_vsnprintf(buff, count, fmt, ap);
va_end(ap);
}
// As mux_sprintf, but returns the length written -- 0..count-1, the value
// mux_vsnprintf already computes and mux_sprintf throws away.
//
// Callers that append in a loop need it, and until now each grew its own
// varargs wrapper because only the va_list form returned a length. There is
// one in mail_mod.cpp already; the next conversion of a raw snprintf() that
// uses its return value would have made a third, and identical private
// copies do not stay identical (see #1667's ADR on append_ljust_field, which
// is byte-for-byte duplicated across two modules today).
//
// Note this is NOT snprintf's return: snprintf answers how much it WOULD
// have written, so `n >= size` is how callers detect truncation. This
// answers how much it DID write, so truncation shows as a short result
// rather than an over-long one. Anything ported from snprintf that tests
// the return against the buffer size has to be re-read, not just renamed.
//
size_t DCL_CDECL mux_snprintf(UTF8 *buff, size_t count, const UTF8 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
size_t n = mux_vsnprintf(buff, count, fmt, ap);
va_end(ap);
return n;
}
void DCL_CDECL mux_fprintf(FILE *fp, const UTF8 *fmt, ...)
{
if (nullptr != fp)
{
UTF8 Buffer[MBUF_SIZE];
va_list ap;
va_start(ap, fmt);
size_t nBuffer = mux_vsnprintf(Buffer, sizeof(Buffer), fmt, ap);
va_end(ap);
fwrite(Buffer, 1, nBuffer, fp);
}
}
// This function acts like fgets except that any data on the end of the
// line past the buffer size is truncated instead of being returned on
// the next call.
//
size_t GetLineTrunc(UTF8 *Buffer, size_t nBuffer, FILE *fp)
{
size_t lenBuffer = 0;
if (fgets(reinterpret_cast<char *>(Buffer), static_cast<int>(nBuffer), fp))
{
lenBuffer = strlen(reinterpret_cast<char *>(Buffer));
}
if (lenBuffer <= 0)
{
memcpy(Buffer, "\n", 2);
return 1;
}
if (Buffer[lenBuffer-1] != '\n')
{
// The line was too long for the buffer. Continue reading until the
// end of the line.
//
UTF8 TruncBuffer[SBUF_SIZE];
size_t lenTruncBuffer;
do
{
if (!fgets(reinterpret_cast<char *>(TruncBuffer), sizeof(TruncBuffer), fp))
{
break;
}
lenTruncBuffer = strlen(reinterpret_cast<char *>(TruncBuffer));
}
while (TruncBuffer[lenTruncBuffer-1] != '\n');
}
return lenBuffer;
}
// Method: Boyer-Moore-Horspool
//
// This method is a simplification of the Boyer-Moore String Searching
// Algorithm, but a useful one. It does not require as much temporary
// storage, and the setup costs are not as high as the full Boyer-Moore.
//
// If we were searching megabytes of data instead of 8KB at most, then
// the full Boyer-Moore would make more sense.
//
#define BMH_LARGE 32767
void BMH_Prepare(BMH_State *bmhs, size_t nPat, const UTF8 *pPat)
{
if (nPat <= 0)
{
return;
}
size_t k;
for (k = 0; k < 256; k++)
{
bmhs->m_d[k] = nPat;
}
UTF8 chLastPat = pPat[nPat-1];
bmhs->m_skip2 = nPat;
for (k = 0; k < nPat - 1; k++)
{
bmhs->m_d[static_cast<unsigned char>(pPat[k])] = nPat - k - 1;
if (pPat[k] == chLastPat)
{
bmhs->m_skip2 = nPat - k - 1;
}
}
bmhs->m_d[static_cast<unsigned char>(chLastPat)] = BMH_LARGE;
}
bool BMH_Execute(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc)
{
if (nPat <= 0)
{
return false;
}
for (size_t i = nPat-1; i < nSrc; i += bmhs->m_skip2)
{
while ((i += bmhs->m_d[static_cast<unsigned char>(pSrc[i])]) < nSrc)
{
; // Nothing.
}
if (i < BMH_LARGE)
{
break;
}
i -= BMH_LARGE;
int j = static_cast<int>(nPat - 1);
const UTF8 *s = pSrc + (i - j);
while (--j >= 0 && s[j] == pPat[j])
{
; // Nothing.
}
if (j < 0)
{
*pnMatched = s-pSrc;
return true;
}
}
return false;
}
bool BMH_StringSearch(size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc)
{
BMH_State bmhs;
BMH_Prepare(&bmhs, nPat, pPat);
return BMH_Execute(&bmhs, pnMatched, nPat, pPat, nSrc, pSrc);
}
// BMH_PrepareI - Pre-lowercase the pattern with mux_strlwr() (Unicode-aware)
// and prepare the case-sensitive BMH state on the lowered pattern.
//
// Note: For XOR transforms (the vast majority), byte length is preserved so
// offsets map directly. For the ~24 rare literal transforms that change byte
// count, the offset in the lowered source may differ from the original.
// Callers (grepi) use the offset to extract from the original text, so the
// result is correct when byte length is preserved.
//
void BMH_PrepareI(BMH_State *bmhs, size_t nPat, const UTF8 *pPat)
{
size_t nLower;
UTF8 *pLower = mux_strlwr(pPat, nLower);
// Use a persistent buffer since BMH_Execute needs the pattern later.
//
static UTF8 LoweredPattern[LBUF_SIZE];
if (nLower >= LBUF_SIZE)
{
nLower = LBUF_SIZE - 1;
}
memcpy(LoweredPattern, pLower, nLower);
LoweredPattern[nLower] = '\0';
BMH_Prepare(bmhs, nLower, LoweredPattern);
}
bool BMH_ExecuteI(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc)
{
// Lowercase both pattern and source, then delegate to case-sensitive.
//
size_t nLowerPat;
UTF8 *pLowerPat = mux_strlwr(pPat, nLowerPat);
// mux_strlwr uses a static buffer, so copy the lowered pattern first.
//
LBuf LowPat = LBuf_Src("BMH_ExecuteI");
if (nLowerPat >= LBUF_SIZE) nLowerPat = LBUF_SIZE - 1;
memcpy(LowPat, pLowerPat, nLowerPat);
LowPat[nLowerPat] = '\0';
size_t nLowerSrc;
UTF8 *pLowerSrc = mux_strlwr(pSrc, nLowerSrc);
// Re-prepare BMH state with lowered pattern since the state from
// BMH_PrepareI may have been invalidated.
//
BMH_State bmhsLocal;
BMH_Prepare(&bmhsLocal, nLowerPat, LowPat);
return BMH_Execute(&bmhsLocal, pnMatched, nLowerPat, LowPat, nLowerSrc, pLowerSrc);
}
bool BMH_StringSearchI(size_t *pnMatched, size_t nPat, const UTF8 *pPat, size_t nSrc, const UTF8 *pSrc)
{
// Lowercase pattern and source, then use case-sensitive search.
//
size_t nLowerPat;
UTF8 *pLowerPat = mux_strlwr(pPat, nLowerPat);
LBuf LowPat = LBuf_Src("BMH_StringSearchI");
if (nLowerPat >= LBUF_SIZE) nLowerPat = LBUF_SIZE - 1;
memcpy(LowPat, pLowerPat, nLowerPat);
LowPat[nLowerPat] = '\0';
size_t nLowerSrc;
UTF8 *pLowerSrc = mux_strlwr(pSrc, nLowerSrc);
return BMH_StringSearch(pnMatched, nLowerPat, LowPat, nLowerSrc, pLowerSrc);
}
// find_pattern_delimiter - Find the first ':' in a $-command or ^-listen
// pattern that is not part of a '::' escape. A '::' pair represents a literal
// ':' in the pattern (useful for regexp non-capturing groups, etc.). Returns
// a pointer to the delimiter ':', or nullptr if none is found.
//
UTF8 *find_pattern_delimiter(UTF8 *str)
{
UTF8 *p = str;
while (*p)
{
if (':' == *p)
{
if (':' == p[1])
{
p += 2;
continue;
}
return p;
}
p++;
}
return nullptr;
}
// unescape_pattern_colons - Collapse '::' sequences to ':' in-place.
// Called on the pattern portion of a $-command or ^-listen after the
// delimiter has been found and the string split.
//
void unescape_pattern_colons(UTF8 *str)
{
UTF8 *r = str;
UTF8 *w = str;
while (*r)
{
if (':' == r[0] && ':' == r[1])
{
*w++ = ':';
r += 2;
continue;
}
*w++ = *r++;
}
*w = '\0';
}
// strip_fancy_quotes - Replace Unicode smart/curly quotes with ASCII equivalents
// in-place. The string can only shrink (3-byte UTF-8 sequences become 1 byte),
// so no additional buffer is needed.
//
// U+201C / U+201D (left/right double quotation mark) -> "
// U+2018 / U+2019 (left/right single quotation mark) -> '
//
void strip_fancy_quotes(UTF8 *str)
{
UTF8 *r = str;
UTF8 *w = str;
while (*r)
{
if ( 0xE2 == r[0]
&& 0x80 == r[1])
{
if (0x9C == r[2] || 0x9D == r[2])
{
*w++ = '"';
r += 3;
continue;
}
else if (0x98 == r[2] || 0x99 == r[2])
{
*w++ = '\'';
r += 3;
continue;
}
}
*w++ = *r++;
}
*w = '\0';
}
bool mux_fopen(FILE **pFile, const UTF8 *filename, const UTF8 *mode)
{
if (pFile)
{
*pFile = nullptr;
if ( nullptr != filename
&& nullptr != mode)
{
#if defined(WINDOWS_FILES) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400)
// 1400 is Visual C++ 2005
//
return (fopen_s(pFile, reinterpret_cast<const char *>(filename), reinterpret_cast<const char *>(mode)) == 0);
#else
*pFile = fopen(reinterpret_cast<const char *>(filename), reinterpret_cast<const char *>(mode));
if (nullptr != *pFile)
{
return true;
}
#endif // WINDOWS_FILES
}
}
return false;
}
void mux_fclose(FILE *fp)
{
if (nullptr != fp)
{
fclose(fp);
}
}
bool mux_open(int *pfh, const UTF8 *filename, int oflag)
{
if (nullptr != pfh)
{
*pfh = MUX_OPEN_INVALID_HANDLE_VALUE;
if (nullptr != filename)
{
#if defined(WINDOWS_FILES) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400)
// 1400 is Visual C++ 2005
//
return (_sopen_s(pfh, reinterpret_cast<const char *>(filename), oflag, _SH_DENYNO, _S_IREAD|_S_IWRITE) == 0);
#elif defined(WINDOWS_FILES)
*pfh = _open(reinterpret_cast<const char *>(filename), oflag, _S_IREAD|_S_IWRITE);
return (0 <= *pfh);
#else
*pfh = open(reinterpret_cast<const char *>(filename), oflag, 0600);
return (0 <= *pfh);
#endif
}
}
return false;
}
const UTF8 *mux_strerror(int errnum)
{
#if defined(WINDOWS_FILES) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400)
// 1400 is Visual C++ 2005
//
static UTF8 buffer[80];
strerror_s(reinterpret_cast<char *>(buffer), sizeof(buffer), errnum);
return buffer;
#else
return reinterpret_cast<UTF8 *>(strerror(errnum));
#endif
}
size_t LeftJustifyString(UTF8 *field, size_t nWidth, const UTF8 *value)
{
size_t n = strlen(reinterpret_cast<const char *>(value));
if (n > nWidth)
{
n = nWidth;
}
memcpy(field, value, n);
memset(field+n, ' ', nWidth-n);
return nWidth;
}
size_t RightJustifyNumber(UTF8 *field, size_t nWidth, int64_t value, UTF8 chFill)
{
UTF8 buffer[I64BUF_SIZE];
size_t nReturn = 0;
if (nWidth < sizeof(buffer))
{
size_t n = mux_i64toa(value, buffer);
if (n < sizeof(buffer))
{
nReturn = n;
if (n < nWidth)
{
memset(field, chFill, nWidth-n);
field += nWidth-n;
nReturn = nWidth;
}
memcpy(field, buffer, n);
}
}
return nReturn;
}
// ConvertCRLFtoSpace — replace CRLF sequences with spaces.
// Returns a pointer to a static buffer.
//
UTF8 *ConvertCRLFtoSpace(const UTF8 *pString)
{
static UTF8 buf[LBUF_SIZE];
UTF8 *bp = buf;
// Skip any leading CRLF.
//
while ( '\r' == *pString
|| '\n' == *pString)
{
pString++;
}
bool bFirst = true;
while (*pString)
{
if (!bFirst)
{
safe_chr(' ', buf, &bp);
}
else
{
bFirst = false;
}
while ( *pString
&& '\r' != *pString
&& '\n' != *pString)
{
safe_chr(*pString, buf, &bp);
pString++;
}
// Skip any CRLF.
//
while ( '\r' == *pString
|| '\n' == *pString)
{
pString++;
}
}
*bp = '\0';
return buf;
}