Windows: encode and decode text as UTF-8 instead of trusting the locale

setlocale(LC_ALL, "") maps to the ANSI code page on Windows -- 936 (GBK)
on a Chinese system -- so wcrtomb() produces GBK where the protocol wants
UTF-8, and mbrtowc() reads UTF-8 as GBK. Typed Chinese therefore reached
the model as mojibake, and once the buffer held correct UTF-8 the input
line rendered as mojibake instead. Windows' C runtime has no ".UTF-8"
locale to switch to, so the conversion has to be explicit.

os_compat.[ch]
  * add os_utf8_encode() and os_utf8_decode(), locale-independent, with
    range and overlong-form checks
src/tui.c
  * input_put_wc(), the command-palette filter and the ask_user buffer use
    os_utf8_encode() instead of wcrtomb()
src/textsel.c
  * cst_utf8_decode() uses os_utf8_decode() instead of mbrtowc()
This commit is contained in:
XYZ
2026-10-06 17:56:55 +08:00
parent 3db33eddac
commit 929f7125b8
4 changed files with 121 additions and 30 deletions
+18 -24
View File
@@ -2966,12 +2966,10 @@ static void input_clear(tui_t *t) { input_set(t, ""); }
static void input_put_wc(tui_t *t, wchar_t wc) {
char mb[8];
mbstate_t st;
memset(&st, 0, sizeof(st));
size_t n = wcrtomb(mb, wc, &st);
if (n == (size_t)-1 || n == 0)
int n = os_utf8_encode((unsigned long)wc, mb);
if (n <= 0)
return;
input_insert(t, mb, n);
input_insert(t, mb, (size_t)n);
}
static void input_put_byte(tui_t *t, char ch) { input_insert(t, &ch, 1); }
@@ -3600,16 +3598,14 @@ static int picker_run(tui_t *t, const char *title, char items[][128], int n,
continue;
}
if (iswprint(wch)) {
char mb[8];
mbstate_t st;
memset(&st, 0, sizeof(st));
size_t k = wcrtomb(mb, (wchar_t)wch, &st);
if (k != (size_t)-1 && qlen + k < sizeof(query)) {
memcpy(query + qlen, mb, k);
qlen += k;
query[qlen] = 0;
sel = top = 0;
}
char mb[8];
int k = os_utf8_encode((unsigned long)(wchar_t)wch, mb);
if (k > 0 && qlen + (size_t)k < sizeof(query)) {
memcpy(query + qlen, mb, (size_t)k);
qlen += (size_t)k;
query[qlen] = 0;
sel = top = 0;
}
}
}
@@ -6143,15 +6139,13 @@ static void run_ask_modal(tui_t *t) {
break;
}
if (iswprint(wch)) {
char mb[8];
mbstate_t st;
memset(&st, 0, sizeof(st));
size_t k = wcrtomb(mb, (wchar_t)wch, &st);
size_t n = strlen(t->ask_buf);
if (k != (size_t)-1 && n + k + 1 < sizeof(t->ask_buf)) {
memcpy(t->ask_buf + n, mb, k);
t->ask_buf[n + k] = 0;
}
char mb[8];
int k = os_utf8_encode((unsigned long)(wchar_t)wch, mb);
size_t n = strlen(t->ask_buf);
if (k > 0 && n + (size_t)k + 1 < sizeof(t->ask_buf)) {
memcpy(t->ask_buf + n, mb, (size_t)k);
t->ask_buf[n + k] = 0;
}
}
}
curs_set(1);