Hi,

This is a patch series which:

1. Fixes return value of `mbrlen` and `mbrtowc` functions with DBCS code pages.
2. Makes all CRTs use mingw-w64's replacements for C95 conversion functions.

Note that mingw-w64's replacements for C95 conversion functions work only with 
SBCS and DBCS code pages (that is, code pages for which MB_CUR_MAX <= 2). UCRT 
supports code pages for which MB_CUR_MAX > 2 (most notably, code page 65001 - 
UTF-8). In order to support such code pages, implementation for UCRT calls 
either mingw-w64's replacements (defined in misc/mbrtowc.c and misc/wcrtomb.c) 
or *real* CRT's versions (obtained from LoadLibrary/GetProcAddress) depending 
on value of MB_CUR_MAX.

This patch series has other minor changes:

- Tests for DBCS code pages now only run for msvcrt20.dll or later. Based on my 
understanding, support for multibyte code pages was first added in 
msvcrt20.dll, which would always cause tests to fail with older CRTs. Please 
correct me if I am wrong.
- Tests now run for all CRTs. Previously they were skipped for msvcr80.dll and 
later, and UCRT. UCRT-specific test cases are used to confirm that conversion 
from/to UTF-8 works as expected.

This patch series passed GitHub tests[1].

Unrelated question, would it be OK to move some files (for example, those 
implementing C95 conversion functions) from misc/ subdirectory to a new locale/ 
subdirectory? I'll send a patch if it's OK.

- Kirill Makurin

[1] https://github.com/maiddaisuki/mingw-w64/actions/runs/16882836338
From 97f2acd1c5bc72248fc94d3e6d3ef26c0824f11e Mon Sep 17 00:00:00 2001
From: Kirill Makurin <maiddais...@outlook.com>
Date: Mon, 11 Aug 2025 21:05:44 +0900
Subject: [PATCH 1/6] tests: run tests for DBCS code pages only for
 msvcrt20.dll or later

Support for multibyte characters was first added in msvcrt20.dll.
This will cause tests for C95 conversion functions always fail with
CRTs older than msvcrt20.dll.

Signed-off-by: Kirill Makurin <maiddais...@outlook.com>
---
 mingw-w64-crt/testcases/t_btowc.c     | 4 ++--
 mingw-w64-crt/testcases/t_mbrlen.c    | 6 +++++-
 mingw-w64-crt/testcases/t_mbrtowc.c   | 6 +++++-
 mingw-w64-crt/testcases/t_mbsrtowcs.c | 6 +++++-
 mingw-w64-crt/testcases/t_wcrtomb.c   | 3 ++-
 mingw-w64-crt/testcases/t_wcsrtombs.c | 3 ++-
 mingw-w64-crt/testcases/t_wctob.c     | 4 ++--
 7 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/mingw-w64-crt/testcases/t_btowc.c 
b/mingw-w64-crt/testcases/t_btowc.c
index 7adcedd08..47ad29dc6 100644
--- a/mingw-w64-crt/testcases/t_btowc.c
+++ b/mingw-w64-crt/testcases/t_btowc.c
@@ -52,7 +52,7 @@ int main (void) {
   for (int c = 0x80; c < 0x100; ++c) {
     assert (btowc (c) != WEOF);
   }
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -74,7 +74,7 @@ int main (void) {
       assert (btowc (c) == WEOF);
     }
   }
-
+#endif
 #ifdef _UCRT
   /**
    * Test UTF-8
diff --git a/mingw-w64-crt/testcases/t_mbrlen.c 
b/mingw-w64-crt/testcases/t_mbrlen.c
index 4d297e3b7..1b08ca68c 100644
--- a/mingw-w64-crt/testcases/t_mbrlen.c
+++ b/mingw-w64-crt/testcases/t_mbrlen.c
@@ -88,7 +88,7 @@ int main (void) {
       break;
     }
   }
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -143,5 +143,9 @@ int main (void) {
   assert (mbsinit (&state));
   assert (errno == EILSEQ);
 
+  // reset errno
+  _set_errno (0);
+#endif
+
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_mbrtowc.c 
b/mingw-w64-crt/testcases/t_mbrtowc.c
index 1b94207ca..7294a2291 100644
--- a/mingw-w64-crt/testcases/t_mbrtowc.c
+++ b/mingw-w64-crt/testcases/t_mbrtowc.c
@@ -100,7 +100,7 @@ int main (void) {
       break;
     }
   }
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -168,5 +168,9 @@ int main (void) {
   assert (mbsinit (&state));
   assert (errno == EILSEQ);
 
+  // reset errno
+  _set_errno (0);
+#endif
+
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_mbsrtowcs.c 
b/mingw-w64-crt/testcases/t_mbsrtowcs.c
index ba2b83805..00aac3e5d 100644
--- a/mingw-w64-crt/testcases/t_mbsrtowcs.c
+++ b/mingw-w64-crt/testcases/t_mbsrtowcs.c
@@ -192,7 +192,7 @@ int main (void) {
   assert (mbsinit (&state));
   assert (errno == 0);
   assert (buffer[8] == WEOF);
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -373,5 +373,9 @@ int main (void) {
   /* This assertion fails with CRT's version */
   assert (buffer[0] != WEOF && buffer[1] != WEOF && buffer[2] == WEOF);
 
+  // reset errno
+  _set_errno (0);
+#endif
+
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_wcrtomb.c 
b/mingw-w64-crt/testcases/t_wcrtomb.c
index f6e44f410..63a369a6c 100644
--- a/mingw-w64-crt/testcases/t_wcrtomb.c
+++ b/mingw-w64-crt/testcases/t_wcrtomb.c
@@ -148,7 +148,7 @@ int main (void) {
       break;
     }
   }
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -202,6 +202,7 @@ int main (void) {
       break;
     }
   }
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_wcsrtombs.c 
b/mingw-w64-crt/testcases/t_wcsrtombs.c
index f2c660daa..df288ea3b 100644
--- a/mingw-w64-crt/testcases/t_wcsrtombs.c
+++ b/mingw-w64-crt/testcases/t_wcsrtombs.c
@@ -350,7 +350,7 @@ int main (void) {
 
   // reset errno
   _set_errno (0);
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -565,6 +565,7 @@ int main (void) {
 
   // reset errno
   _set_errno (0);
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_wctob.c 
b/mingw-w64-crt/testcases/t_wctob.c
index 6177223a7..6fd672e02 100644
--- a/mingw-w64-crt/testcases/t_wctob.c
+++ b/mingw-w64-crt/testcases/t_wctob.c
@@ -61,7 +61,7 @@ int main (void) {
       break;
     }
   }
-
+#if __MSVCRT_VERSION__ >= 0x0200
   /**
    * Test DBCS code page
    */
@@ -96,7 +96,7 @@ int main (void) {
       break;
     }
   }
-
+#endif
 #ifdef _UCRT
   /**
    * Test UTF-8
-- 
2.50.1.windows.1

From 4a7704ac6c765f949ac02f13670aa833d5ba8f5a Mon Sep 17 00:00:00 2001
From: Kirill Makurin <maiddais...@outlook.com>
Date: Mon, 11 Aug 2025 21:46:16 +0900
Subject: [PATCH 2/6] crt: use replacements for C95 conversion functions with
 all msvcr*.dll CRTs

Update tests for C95 conversion function to be skipped only when compiling
for UCRT.

Signed-off-by: Kirill Makurin <maiddais...@outlook.com>
---
 mingw-w64-crt/Makefile.am                    |  6 ++----
 mingw-w64-crt/lib-common/msvcr120_app.def.in | 10 +++++-----
 mingw-w64-crt/lib32/msvcr100.def.in          | 10 +++++-----
 mingw-w64-crt/lib32/msvcr100d.def.in         | 10 +++++-----
 mingw-w64-crt/lib32/msvcr110.def.in          | 10 +++++-----
 mingw-w64-crt/lib32/msvcr110d.def.in         | 10 +++++-----
 mingw-w64-crt/lib32/msvcr120.def.in          | 10 +++++-----
 mingw-w64-crt/lib32/msvcr120d.def.in         | 10 +++++-----
 mingw-w64-crt/lib32/msvcr80.def.in           | 10 +++++-----
 mingw-w64-crt/lib32/msvcr80d.def.in          | 10 +++++-----
 mingw-w64-crt/lib32/msvcr90.def.in           | 10 +++++-----
 mingw-w64-crt/lib32/msvcr90d.def.in          | 10 +++++-----
 mingw-w64-crt/lib64/msvcr100.def.in          | 10 +++++-----
 mingw-w64-crt/lib64/msvcr100d.def.in         | 10 +++++-----
 mingw-w64-crt/lib64/msvcr110.def.in          | 10 +++++-----
 mingw-w64-crt/lib64/msvcr110d.def.in         | 10 +++++-----
 mingw-w64-crt/lib64/msvcr120.def.in          | 10 +++++-----
 mingw-w64-crt/lib64/msvcr120d.def.in         | 10 +++++-----
 mingw-w64-crt/lib64/msvcr80.def.in           | 10 +++++-----
 mingw-w64-crt/lib64/msvcr80d.def.in          | 10 +++++-----
 mingw-w64-crt/lib64/msvcr90.def.in           | 10 +++++-----
 mingw-w64-crt/lib64/msvcr90d.def.in          | 10 +++++-----
 mingw-w64-crt/libarm32/msvcr110.def.in       | 10 +++++-----
 mingw-w64-crt/libarm32/msvcr110d.def.in      | 10 +++++-----
 mingw-w64-crt/libarm32/msvcr120.def.in       | 10 +++++-----
 mingw-w64-crt/libarm32/msvcr120d.def.in      | 10 +++++-----
 mingw-w64-crt/testcases/t_mbrlen.c           |  2 +-
 mingw-w64-crt/testcases/t_mbrtowc.c          |  2 +-
 mingw-w64-crt/testcases/t_mbsrtowcs.c        |  2 +-
 mingw-w64-crt/testcases/t_wcrtomb.c          |  2 +-
 mingw-w64-crt/testcases/t_wcsrtombs.c        |  2 +-
 31 files changed, 132 insertions(+), 134 deletions(-)

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index a296bd804..310db52bb 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -168,9 +168,11 @@ src_libws2_32=libsrc/ws2_32.c \
 src_msvcrt_common=\
   misc/_onexit.c \
   misc/btowc.c \
+  misc/mbrtowc.c \
   misc/mbsinit.c \
   misc/onexit_table.c \
   misc/register_tls_atexit.c \
+  misc/wcrtomb.c \
   misc/wctob.c \
   stdio/_getc_nolock.c \
   stdio/_getwc_nolock.c \
@@ -346,8 +348,6 @@ src_msvcrt=\
   misc/iswblank.c \
   misc/_isblank_l.c \
   misc/_iswblank_l.c \
-  misc/mbrtowc.c \
-  misc/wcrtomb.c \
   misc/wctrans.c \
   misc/wctype.c \
   secapi/_vscprintf_p.c \
@@ -907,11 +907,9 @@ src_pre_msvcr80=\
   misc/_set_fmode.c \
   misc/imaxabs.c \
   misc/invalid_parameter_handler.c \
-  misc/mbrtowc.c \
   misc/output_format.c \
   misc/strnlen.c \
   misc/wassert.c \
-  misc/wcrtomb.c \
   misc/wcsnlen.c \
   secapi/getenv_s.c \
   stdio/_fseeki64.c \
diff --git a/mingw-w64-crt/lib-common/msvcr120_app.def.in 
b/mingw-w64-crt/lib-common/msvcr120_app.def.in
index 083b1f22e..a49398246 100644
--- a/mingw-w64-crt/lib-common/msvcr120_app.def.in
+++ b/mingw-w64-crt/lib-common/msvcr120_app.def.in
@@ -2116,9 +2116,9 @@ lroundf
 F_ARM32(lroundl) ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2283,7 +2283,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2303,7 +2303,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr100.def.in 
b/mingw-w64-crt/lib32/msvcr100.def.in
index 4016060b9..8d3747c4d 100644
--- a/mingw-w64-crt/lib32/msvcr100.def.in
+++ b/mingw-w64-crt/lib32/msvcr100.def.in
@@ -1756,9 +1756,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1860,7 +1860,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1880,7 +1880,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr100d.def.in 
b/mingw-w64-crt/lib32/msvcr100d.def.in
index 40d9e3499..63ae979b9 100644
--- a/mingw-w64-crt/lib32/msvcr100d.def.in
+++ b/mingw-w64-crt/lib32/msvcr100d.def.in
@@ -1821,9 +1821,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1923,7 +1923,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1943,7 +1943,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr110.def.in 
b/mingw-w64-crt/lib32/msvcr110.def.in
index eb8c50d46..8907bb52a 100644
--- a/mingw-w64-crt/lib32/msvcr110.def.in
+++ b/mingw-w64-crt/lib32/msvcr110.def.in
@@ -1887,9 +1887,9 @@ log10 ; If we implement log10, we can set it to DATA only.
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1989,7 +1989,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2009,7 +2009,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr110d.def.in 
b/mingw-w64-crt/lib32/msvcr110d.def.in
index cae199097..95d04700f 100644
--- a/mingw-w64-crt/lib32/msvcr110d.def.in
+++ b/mingw-w64-crt/lib32/msvcr110d.def.in
@@ -1954,9 +1954,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2056,7 +2056,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2076,7 +2076,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr120.def.in 
b/mingw-w64-crt/lib32/msvcr120.def.in
index 385567bc8..b59871a6c 100644
--- a/mingw-w64-crt/lib32/msvcr120.def.in
+++ b/mingw-w64-crt/lib32/msvcr120.def.in
@@ -2086,9 +2086,9 @@ lroundf
 ; lroundl ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2246,7 +2246,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2266,7 +2266,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr120d.def.in 
b/mingw-w64-crt/lib32/msvcr120d.def.in
index eb0257866..e52eba59d 100644
--- a/mingw-w64-crt/lib32/msvcr120d.def.in
+++ b/mingw-w64-crt/lib32/msvcr120d.def.in
@@ -2153,9 +2153,9 @@ lroundf
 ; lroundl ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2313,7 +2313,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2333,7 +2333,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr80.def.in 
b/mingw-w64-crt/lib32/msvcr80.def.in
index f3f78df13..2ad0142fa 100644
--- a/mingw-w64-crt/lib32/msvcr80.def.in
+++ b/mingw-w64-crt/lib32/msvcr80.def.in
@@ -1392,9 +1392,9 @@ log10 ; If we implement log10, we can set it to DATA only.
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1494,7 +1494,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1514,7 +1514,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr80d.def.in 
b/mingw-w64-crt/lib32/msvcr80d.def.in
index 0df1c1243..bbe25d763 100644
--- a/mingw-w64-crt/lib32/msvcr80d.def.in
+++ b/mingw-w64-crt/lib32/msvcr80d.def.in
@@ -1475,9 +1475,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1577,7 +1577,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1597,7 +1597,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr90.def.in 
b/mingw-w64-crt/lib32/msvcr90.def.in
index bfb97ff60..eaff980a4 100644
--- a/mingw-w64-crt/lib32/msvcr90.def.in
+++ b/mingw-w64-crt/lib32/msvcr90.def.in
@@ -1388,9 +1388,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1492,7 +1492,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1512,7 +1512,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib32/msvcr90d.def.in 
b/mingw-w64-crt/lib32/msvcr90d.def.in
index 69f0d8e4c..6a0318311 100644
--- a/mingw-w64-crt/lib32/msvcr90d.def.in
+++ b/mingw-w64-crt/lib32/msvcr90d.def.in
@@ -1460,9 +1460,9 @@ log10
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1564,7 +1564,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1584,7 +1584,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr100.def.in 
b/mingw-w64-crt/lib64/msvcr100.def.in
index 24698cc8d..73e8cffab 100644
--- a/mingw-w64-crt/lib64/msvcr100.def.in
+++ b/mingw-w64-crt/lib64/msvcr100.def.in
@@ -1712,9 +1712,9 @@ logf DATA
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1822,7 +1822,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1842,7 +1842,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr100d.def.in 
b/mingw-w64-crt/lib64/msvcr100d.def.in
index e3c7e1b71..5cf31b3b5 100644
--- a/mingw-w64-crt/lib64/msvcr100d.def.in
+++ b/mingw-w64-crt/lib64/msvcr100d.def.in
@@ -1777,9 +1777,9 @@ logf DATA ; overwritten
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1887,7 +1887,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1907,7 +1907,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr110.def.in 
b/mingw-w64-crt/lib64/msvcr110.def.in
index 8ef9f860f..60974774b 100644
--- a/mingw-w64-crt/lib64/msvcr110.def.in
+++ b/mingw-w64-crt/lib64/msvcr110.def.in
@@ -1836,9 +1836,9 @@ logf
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1946,7 +1946,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1966,7 +1966,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr110d.def.in 
b/mingw-w64-crt/lib64/msvcr110d.def.in
index ad13f3aad..57542181b 100644
--- a/mingw-w64-crt/lib64/msvcr110d.def.in
+++ b/mingw-w64-crt/lib64/msvcr110d.def.in
@@ -1901,9 +1901,9 @@ logf
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2011,7 +2011,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2031,7 +2031,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr120.def.in 
b/mingw-w64-crt/lib64/msvcr120.def.in
index 0401dbf20..085867a04 100644
--- a/mingw-w64-crt/lib64/msvcr120.def.in
+++ b/mingw-w64-crt/lib64/msvcr120.def.in
@@ -2034,9 +2034,9 @@ lroundf
 ; lroundl ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2202,7 +2202,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2222,7 +2222,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr120d.def.in 
b/mingw-w64-crt/lib64/msvcr120d.def.in
index bf914c744..859e24e31 100644
--- a/mingw-w64-crt/lib64/msvcr120d.def.in
+++ b/mingw-w64-crt/lib64/msvcr120d.def.in
@@ -2099,9 +2099,9 @@ lroundf
 ; lroundl ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen
+; mbrtowc
+; mbsrtowcs
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2267,7 +2267,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2287,7 +2287,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr80.def.in 
b/mingw-w64-crt/lib64/msvcr80.def.in
index aaefaa677..268c815b0 100644
--- a/mingw-w64-crt/lib64/msvcr80.def.in
+++ b/mingw-w64-crt/lib64/msvcr80.def.in
@@ -1332,9 +1332,9 @@ logf DATA
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1442,7 +1442,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1462,7 +1462,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr80d.def.in 
b/mingw-w64-crt/lib64/msvcr80d.def.in
index 5888e92f9..bb45fce6b 100644
--- a/mingw-w64-crt/lib64/msvcr80d.def.in
+++ b/mingw-w64-crt/lib64/msvcr80d.def.in
@@ -1409,9 +1409,9 @@ logf DATA ; overwritten
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1519,7 +1519,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1539,7 +1539,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr90.def.in 
b/mingw-w64-crt/lib64/msvcr90.def.in
index c3524fff2..597b84807 100644
--- a/mingw-w64-crt/lib64/msvcr90.def.in
+++ b/mingw-w64-crt/lib64/msvcr90.def.in
@@ -1330,9 +1330,9 @@ logf DATA
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1440,7 +1440,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1460,7 +1460,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/lib64/msvcr90d.def.in 
b/mingw-w64-crt/lib64/msvcr90d.def.in
index e88cffa39..d69a016db 100644
--- a/mingw-w64-crt/lib64/msvcr90d.def.in
+++ b/mingw-w64-crt/lib64/msvcr90d.def.in
@@ -1396,9 +1396,9 @@ logf DATA
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1506,7 +1506,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1526,7 +1526,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/libarm32/msvcr110.def.in 
b/mingw-w64-crt/libarm32/msvcr110.def.in
index bba35f0be..ba22acd90 100644
--- a/mingw-w64-crt/libarm32/msvcr110.def.in
+++ b/mingw-w64-crt/libarm32/msvcr110.def.in
@@ -1823,9 +1823,9 @@ logf
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1933,7 +1933,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -1953,7 +1953,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/libarm32/msvcr110d.def.in 
b/mingw-w64-crt/libarm32/msvcr110d.def.in
index 4ef8581d8..055e30a48 100644
--- a/mingw-w64-crt/libarm32/msvcr110d.def.in
+++ b/mingw-w64-crt/libarm32/msvcr110d.def.in
@@ -1888,9 +1888,9 @@ logf
 longjmp
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc  ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -1998,7 +1998,7 @@ vsprintf_s
 vswprintf_s
 vwprintf
 vwprintf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2018,7 +2018,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/libarm32/msvcr120.def.in 
b/mingw-w64-crt/libarm32/msvcr120.def.in
index 32c423fa8..a1377592b 100644
--- a/mingw-w64-crt/libarm32/msvcr120.def.in
+++ b/mingw-w64-crt/libarm32/msvcr120.def.in
@@ -2002,9 +2002,9 @@ lroundf
 lroundl
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2170,7 +2170,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2190,7 +2190,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/libarm32/msvcr120d.def.in 
b/mingw-w64-crt/libarm32/msvcr120d.def.in
index 84faadae1..0907d1556 100644
--- a/mingw-w64-crt/libarm32/msvcr120d.def.in
+++ b/mingw-w64-crt/libarm32/msvcr120d.def.in
@@ -2067,9 +2067,9 @@ lroundf
 lroundl
 malloc
 mblen
-mbrlen
-mbrtowc
-mbsrtowcs
+; mbrlen ; use replacement
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2235,7 +2235,7 @@ vwprintf
 vwprintf_s
 vwscanf
 vwscanf_s
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2255,7 +2255,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/testcases/t_mbrlen.c 
b/mingw-w64-crt/testcases/t_mbrlen.c
index 1b08ca68c..222977aed 100644
--- a/mingw-w64-crt/testcases/t_mbrlen.c
+++ b/mingw-w64-crt/testcases/t_mbrlen.c
@@ -23,7 +23,7 @@ char Multibyte[] = {(char) 0x81, (char) 0x81};
 char InvalidMultibyte[] = {(char) 0x81, 0};
 
 int main (void) {
-#if __MSVCRT_VERSION__ >= 0x0800
+#ifdef _UCRT
   return 77;
 #endif
   mbstate_t state = {0};
diff --git a/mingw-w64-crt/testcases/t_mbrtowc.c 
b/mingw-w64-crt/testcases/t_mbrtowc.c
index 7294a2291..ba5234402 100644
--- a/mingw-w64-crt/testcases/t_mbrtowc.c
+++ b/mingw-w64-crt/testcases/t_mbrtowc.c
@@ -23,7 +23,7 @@ char Multibyte[] = {(char) 0x81, (char) 0x81};
 char InvalidMultibyte[] = {(char) 0x81, 0};
 
 int main (void) {
-#if __MSVCRT_VERSION__ >= 0x0800
+#ifdef _UCRT
   return 77;
 #endif
   mbstate_t state = {0};
diff --git a/mingw-w64-crt/testcases/t_mbsrtowcs.c 
b/mingw-w64-crt/testcases/t_mbsrtowcs.c
index 00aac3e5d..00ac00e35 100644
--- a/mingw-w64-crt/testcases/t_mbsrtowcs.c
+++ b/mingw-w64-crt/testcases/t_mbsrtowcs.c
@@ -21,7 +21,7 @@ unsigned char MixedText[] = {0x93, 0xFA, 'n', 'i', 0x96, 
0x7B, 'h', 'o', 'n', 0x
 unsigned char BadText[] = {0x93, 0xFA, 0x96, 0x7B, 0x8C, 0x0};
 
 int main (void) {
-#if __MSVCRT_VERSION__ >= 0x0800
+#ifdef _UCRT
   return 77;
 #endif
   mbstate_t state = {0};
diff --git a/mingw-w64-crt/testcases/t_wcrtomb.c 
b/mingw-w64-crt/testcases/t_wcrtomb.c
index 63a369a6c..d02cbdce0 100644
--- a/mingw-w64-crt/testcases/t_wcrtomb.c
+++ b/mingw-w64-crt/testcases/t_wcrtomb.c
@@ -21,7 +21,7 @@ static void set_conversion_state (mbstate_t *state, int 
bytes) {
 }
 
 int main (void) {
-#if __MSVCRT_VERSION__ >= 0x0800
+#ifdef _UCRT
   return 77;
 #endif
   mbstate_t state = {0};
diff --git a/mingw-w64-crt/testcases/t_wcsrtombs.c 
b/mingw-w64-crt/testcases/t_wcsrtombs.c
index df288ea3b..9979e9c38 100644
--- a/mingw-w64-crt/testcases/t_wcsrtombs.c
+++ b/mingw-w64-crt/testcases/t_wcsrtombs.c
@@ -17,7 +17,7 @@ wchar_t MixedText[] = L"日NI本HON語GO";
 wchar_t BadText[] = {L'テ', L'く', WEOF, L'ト'};
 
 int main (void) {
-#if __MSVCRT_VERSION__ >= 0x0800
+#ifdef _UCRT
   return 77;
 #endif
   const wchar_t *original_text = NULL;
-- 
2.50.1.windows.1

From a35c473c351a02409848cb6235ef7ee58e48b5af Mon Sep 17 00:00:00 2001
From: Kirill Makurin <maiddais...@outlook.com>
Date: Mon, 11 Aug 2025 22:49:37 +0900
Subject: [PATCH 3/6] crt: use replacements for C95 conversion functions with
 UCRT

mingw-w64 implementation of C95 conversion functions (misc/mbrtowc.c
and misc/wcrtomb.c) can only handle SBCS and DBCS code pages.

In order to support character sets for which MB_CUR_MAX > 2,
implementation for UCRT will eihter call our implementation
(when MB_CUR_MAX <= 2) or CRT's versions (when MB_CUR_MAX > 2).

Signed-off-by: Kirill Makurin <maiddais...@outlook.com>
---
 mingw-w64-crt/Makefile.am                     |   2 +
 .../api-ms-win-crt-convert-l1-1-0.def.in      |   8 +-
 .../api-ms-win-crt-string-l1-1-0.def          |   2 +-
 .../lib-common/ucrtbase-common.def.in         |  10 +-
 mingw-w64-crt/misc/mb_wc_common.h             |  50 ++++++-
 mingw-w64-crt/misc/mbrtowc.c                  |  54 +++++--
 mingw-w64-crt/misc/ucrt_mbrtowc.c             | 134 ++++++++++++++++++
 mingw-w64-crt/misc/ucrt_wcrtomb.c             |  93 ++++++++++++
 mingw-w64-crt/misc/wcrtomb.c                  |  37 +++--
 9 files changed, 355 insertions(+), 35 deletions(-)
 create mode 100644 mingw-w64-crt/misc/ucrt_mbrtowc.c
 create mode 100644 mingw-w64-crt/misc/ucrt_wcrtomb.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 310db52bb..f62941965 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -424,6 +424,8 @@ src_ucrtbase=\
   misc/output_format.c \
   misc/ucrt-access.c \
   misc/ucrt_btowc.c \
+  misc/ucrt_mbrtowc.c \
+  misc/ucrt_wcrtomb.c \
   misc/ucrt_wctob.c \
   stdio/ucrt___local_stdio_printf_options.c \
   stdio/ucrt___local_stdio_scanf_options.c \
diff --git a/mingw-w64-crt/lib-common/api-ms-win-crt-convert-l1-1-0.def.in 
b/mingw-w64-crt/lib-common/api-ms-win-crt-convert-l1-1-0.def.in
index fd49dc01d..c4cbe8548 100644
--- a/mingw-w64-crt/lib-common/api-ms-win-crt-convert-l1-1-0.def.in
+++ b/mingw-w64-crt/lib-common/api-ms-win-crt-convert-l1-1-0.def.in
@@ -98,8 +98,8 @@ c16rtomb
 c32rtomb
 mbrtoc16
 mbrtoc32
-mbrtowc
-mbsrtowcs
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -113,9 +113,9 @@ strtoll
 strtoul
 strtoull
 strtoumax
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcstod
 wcstof
diff --git a/mingw-w64-crt/lib-common/api-ms-win-crt-string-l1-1-0.def 
b/mingw-w64-crt/lib-common/api-ms-win-crt-string-l1-1-0.def
index ebf681501..32c32afe5 100644
--- a/mingw-w64-crt/lib-common/api-ms-win-crt-string-l1-1-0.def
+++ b/mingw-w64-crt/lib-common/api-ms-win-crt-string-l1-1-0.def
@@ -158,7 +158,7 @@ iswupper
 iswxdigit
 isxdigit
 mblen
-mbrlen
+; mbrlen ; use replacement
 memcpy_s
 memmove_s
 memset
diff --git a/mingw-w64-crt/lib-common/ucrtbase-common.def.in 
b/mingw-w64-crt/lib-common/ucrtbase-common.def.in
index dd4f0815b..6fc8ac046 100644
--- a/mingw-w64-crt/lib-common/ucrtbase-common.def.in
+++ b/mingw-w64-crt/lib-common/ucrtbase-common.def.in
@@ -2473,11 +2473,11 @@ lroundf
 F_LD64(lroundl) ; Can't use long double functions from the CRT on x86
 malloc
 mblen
-mbrlen
+; mbrlen ; use replacement
 mbrtoc16
 mbrtoc32
-mbrtowc
-mbsrtowcs
+; mbrtowc ; use replacement
+; mbsrtowcs ; use replacement
 mbsrtowcs_s
 mbstowcs
 mbstowcs_s
@@ -2618,7 +2618,7 @@ F_LD64(truncl) ; Can't use long double functions from the 
CRT on x86
 unexpected
 ungetc
 ungetwc
-wcrtomb
+; wcrtomb ; use replacement
 wcrtomb_s
 wcscat
 wcscat_s
@@ -2638,7 +2638,7 @@ wcsncpy_s
 wcsnlen
 wcspbrk
 wcsrchr
-wcsrtombs
+; wcsrtombs ; use replacement
 wcsrtombs_s
 wcsspn
 wcsstr
diff --git a/mingw-w64-crt/misc/mb_wc_common.h 
b/mingw-w64-crt/misc/mb_wc_common.h
index c640fb776..d04770c60 100644
--- a/mingw-w64-crt/misc/mb_wc_common.h
+++ b/mingw-w64-crt/misc/mb_wc_common.h
@@ -4,6 +4,54 @@
  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
  */
 
-#include <_mingw.h>
+#include <wchar.h>
+#include <string.h>
 
 unsigned int __cdecl ___lc_codepage_func(void);
+
+/**
+ * Internal interpretation of `mbstate_t`.
+ */
+typedef struct {
+  char bytes[4];
+} __mingw_conversion_state;
+
+/**
+ * Set `state` to initial conversion state.
+ */
+static __inline__ void conversion_state_init (mbstate_t *state) {
+  memset (state, 0, sizeof (mbstate_t));
+}
+
+/**
+ * Return `1` if `state`'s conversion state is valid, and `0` otherwise.
+ */
+static __inline__ int conversion_state_is_valid (mbstate_t *state) {
+#ifdef _UCRT
+  return state->_Wchar == 0 || (state->_Wchar > 0x7F && state->_Wchar < 0x100);
+#else
+  return *state == 0 || (*state > 0x7F && *state < 0x100);
+#endif
+}
+
+/**
+ * Copy conversion state from `state` to `s`.
+ */
+static __inline__ void conversion_state_get_bytes (__mingw_conversion_state 
*s, mbstate_t *state) {
+#ifdef _UCRT
+  memcpy (s->bytes, &state->_Wchar, 4);
+#else
+  memcpy (s->bytes, state, 4);
+#endif
+}
+
+/**
+ * Copy conversion state from `s` to `state`.
+ */
+static __inline__ void conversion_state_set_bytes (mbstate_t *state, 
__mingw_conversion_state *s) {
+#ifdef _UCRT
+  memcpy (&state->_Wchar, s->bytes, 4);
+#else
+  memcpy (state, s->bytes, 4);
+#endif
+}
diff --git a/mingw-w64-crt/misc/mbrtowc.c b/mingw-w64-crt/misc/mbrtowc.c
index f53286e91..90b205270 100644
--- a/mingw-w64-crt/misc/mbrtowc.c
+++ b/mingw-w64-crt/misc/mbrtowc.c
@@ -3,15 +3,26 @@
  * This file is part of the mingw-w64 runtime package.
  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
  */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-#include "mb_wc_common.h"
-#include <wchar.h>
-#include <stdlib.h>
+
 #include <errno.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+#include "mb_wc_common.h"
+
+#ifdef _UCRT
+#define mbrlen    __mingw_mbrlen
+#define mbrtowc   __mingw_mbrtowc
+#define mbsrtowcs __mingw_mbsrtowcs
+
+static size_t mbrlen (const char *__restrict__, size_t, mbstate_t 
*__restrict__);
+static size_t mbrtowc (wchar_t *__restrict__, const char *__restrict__, 
size_t, mbstate_t *__restrict__);
+static size_t mbsrtowcs (wchar_t *, const char **__restrict__, size_t, 
mbstate_t *__restrict__);
+#endif
+
 /**
  * Private `mbstate_t` to use if caller did not supply one.
  */
@@ -29,12 +40,12 @@ static size_t mbrtowc_cp (
 ) {
   /* Set `state` to initial state */
   if (mbs == NULL) {
-    *state = 0;
+    conversion_state_init (state);
     return 0;
   }
 
   /* Detect invalid conversion state */
-  if ((unsigned) *state > 0xFF) {
+  if (!conversion_state_is_valid (state)) {
     goto einval;
   }
 
@@ -44,10 +55,8 @@ static size_t mbrtowc_cp (
   }
 
   /* Treat `state` as an array of bytes */
-  union {
-    mbstate_t state;
-    char bytes[4];
-  } conversion_state = {.state = *state};
+  __mingw_conversion_state conversion_state = {0};
+  conversion_state_get_bytes (&conversion_state, state);
 
   /* For SBCS code pages `state` must always be in initial state */
   if (mb_cur_max == 1 && conversion_state.bytes[0]) {
@@ -73,7 +82,7 @@ static size_t mbrtowc_cp (
 
     /* We need to examine mbs[1] */
     if (count < 2) {
-      *state = conversion_state.state;
+      conversion_state_set_bytes (state, &conversion_state);
       return (size_t) -2;
     }
 
@@ -87,7 +96,7 @@ static size_t mbrtowc_cp (
   if (conversion_state.bytes[0] == '\0') {
     if (wc != NULL) {
       *wc = L'\0';
-      *state = 0;
+      conversion_state_init (state);
     }
     return 0;
   }
@@ -110,7 +119,7 @@ static size_t mbrtowc_cp (
 
   if (wc != NULL) {
     *wc = wcOut;
-    *state = 0;
+    conversion_state_init (state);
   }
 
   return length;
@@ -124,6 +133,9 @@ einval:
   return (size_t) -1;
 }
 
+#ifdef _UCRT
+static
+#endif
 size_t mbrlen (
   const char *__restrict__ mbs,
   size_t count,
@@ -137,6 +149,9 @@ size_t mbrlen (
   return mbrtowc (&wc, mbs, count, state);
 }
 
+#ifdef _UCRT
+static
+#endif
 size_t mbrtowc (
   wchar_t *__restrict__ wc,
   const char *__restrict__ mbs,
@@ -156,6 +171,9 @@ size_t mbrtowc (
   return mbrtowc_cp (wc, mbs, count, state, cp, mb_cur_max);
 }
 
+#ifdef _UCRT
+static
+#endif
 size_t mbsrtowcs (
   wchar_t *wcs,
   const char **__restrict__ mbs,
@@ -236,3 +254,9 @@ size_t mbsrtowcs (
 
   return wcConverted;
 }
+
+#ifdef _UCRT
+#undef mbrlen
+#undef mbrtowc
+#undef mbsrtowcs
+#endif
diff --git a/mingw-w64-crt/misc/ucrt_mbrtowc.c 
b/mingw-w64-crt/misc/ucrt_mbrtowc.c
new file mode 100644
index 000000000..a580aa9aa
--- /dev/null
+++ b/mingw-w64-crt/misc/ucrt_mbrtowc.c
@@ -0,0 +1,134 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#undef __MSVCRT_VERSION__
+#define _UCRT
+
+#include "mbrtowc.c"
+
+static size_t __cdecl mbrlen_init (const char *__restrict__, size_t, mbstate_t 
*__restrict__);
+static size_t __cdecl mbrtowc_init (wchar_t *__restrict__, const char 
*__restrict__, size_t, mbstate_t *__restrict__);
+static size_t __cdecl mbsrtowcs_init (wchar_t *__restrict__, const char 
**__restrict__, size_t, mbstate_t *__restrict__);
+
+typedef size_t (__cdecl *volatile __mbrlen_t) (const char *__restrict__, 
size_t, mbstate_t *__restrict__);
+typedef size_t (__cdecl *volatile __mbrtowc_t) (wchar_t *__restrict__, const 
char *__restrict__, size_t, mbstate_t *__restrict__);
+typedef size_t (__cdecl *volatile __mbsrtowcs_t) (wchar_t *__restrict__, const 
char **__restrict__, size_t, mbstate_t *__restrict__);
+
+static __mbrlen_t __mbrlen = mbrlen_init;
+static __mbrtowc_t __mbrtowc = mbrtowc_init;
+static __mbsrtowcs_t __mbsrtowcs = mbsrtowcs_init;
+
+static size_t mbrlen_init (
+  const char *__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  HANDLE ucrt = LoadLibraryW (L"ucrtbase.dll");
+
+  if (ucrt == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain handle to 
ucrtbase.dll\n");
+    abort ();
+  }
+
+  __mbrlen_t real_mbrlen = (__mbrlen_t) GetProcAddress (ucrt, "mbrlen");
+
+  if (real_mbrlen == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain address of mbrlen 
function\n");
+    abort ();
+  }
+
+  InterlockedExchangePointer ((PVOID volatile *) &__mbrlen, (PVOID) 
real_mbrlen);
+  FreeLibrary (ucrt);
+
+  return __mbrlen (mbs, count, state);
+}
+
+static size_t mbrtowc_init (
+  wchar_t *__restrict__ wc,
+  const char *__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  HANDLE ucrt = LoadLibraryW (L"ucrtbase.dll");
+
+  if (ucrt == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain handle to 
ucrtbase.dll\n");
+    abort ();
+  }
+
+  __mbrtowc_t real_mbrtowc = (__mbrtowc_t) GetProcAddress (ucrt, "mbrtowc");
+
+  if (real_mbrtowc == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain address of mbrtowc 
function\n");
+    abort ();
+  }
+
+  InterlockedExchangePointer ((PVOID volatile *) &__mbrtowc, (PVOID) 
real_mbrtowc);
+  FreeLibrary (ucrt);
+
+  return __mbrtowc (wc, mbs, count, state);
+}
+
+static size_t mbsrtowcs_init (
+  wchar_t *__restrict__ wcs,
+  const char **__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  HANDLE ucrt = LoadLibraryW (L"ucrtbase.dll");
+
+  if (ucrt == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain handle to 
ucrtbase.dll\n");
+    abort ();
+  }
+
+  __mbsrtowcs_t real_mbsrtowcs = (__mbsrtowcs_t) GetProcAddress (ucrt, 
"mbsrtowcs");
+
+  if (real_mbsrtowcs == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain address of mbsrtowcs 
function\n");
+    abort ();
+  }
+
+  InterlockedExchangePointer ((PVOID volatile *) &__mbsrtowcs, (PVOID) 
real_mbsrtowcs);
+  FreeLibrary (ucrt);
+
+  return __mbsrtowcs (wcs, mbs, count, state);
+}
+
+size_t __cdecl mbrlen (
+  const char *__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  if (MB_CUR_MAX > 2) {
+    return __mbrlen (mbs, count, state);
+  }
+  return __mingw_mbrlen (mbs, count, state);
+}
+
+size_t __cdecl mbrtowc (
+  wchar_t *__restrict__ wc,
+  const char *__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  if (MB_CUR_MAX > 2) {
+    return __mbrtowc (wc, mbs, count, state);
+  }
+  return __mingw_mbrtowc (wc, mbs, count, state);
+}
+
+size_t __cdecl mbsrtowcs (
+  wchar_t *__restrict__ wc,
+  const char **__restrict__ mbs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  if (MB_CUR_MAX > 2) {
+    return __mbsrtowcs (wc, mbs, count, state);
+  }
+  return __mingw_mbsrtowcs (wc, mbs, count, state);
+}
diff --git a/mingw-w64-crt/misc/ucrt_wcrtomb.c 
b/mingw-w64-crt/misc/ucrt_wcrtomb.c
new file mode 100644
index 000000000..f18fb2193
--- /dev/null
+++ b/mingw-w64-crt/misc/ucrt_wcrtomb.c
@@ -0,0 +1,93 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#undef __MSVCRT_VERSION__
+#define _UCRT
+
+#include "wcrtomb.c"
+
+static size_t __cdecl wcrtomb_init (char *__restrict__, wchar_t, mbstate_t 
*__restrict__);
+static size_t __cdecl wcsrtombs_init (char *__restrict__, const wchar_t 
**__restrict__, size_t, mbstate_t *__restrict__);
+
+typedef size_t (__cdecl *volatile __wcrtomb_t) (char *__restrict__, wchar_t, 
mbstate_t *__restrict__);
+typedef size_t (__cdecl *volatile __wcsrtombs_t) (char *__restrict__, const 
wchar_t **__restrict__, size_t, mbstate_t *__restrict__);
+
+static __wcrtomb_t __wcrtomb = wcrtomb_init;
+static __wcsrtombs_t __wcsrtombs = wcsrtombs_init;
+
+static size_t wcrtomb_init (
+  char *__restrict__ mbc,
+  wchar_t wc,
+  mbstate_t *__restrict__ state
+) {
+  HANDLE ucrt = LoadLibraryW (L"ucrtbase.dll");
+
+  if (ucrt == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain handle to 
ucrtbase.dll\n");
+    abort ();
+  }
+
+  __wcrtomb_t real_wcrtomb = (__wcrtomb_t) GetProcAddress (ucrt, "wcrtomb");
+
+  if (real_wcrtomb == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain address of wcrtomb 
function\n");
+    abort ();
+  }
+
+  InterlockedExchangePointer ((PVOID volatile *) &__wcrtomb, (PVOID) 
real_wcrtomb);
+  FreeLibrary (ucrt);
+
+  return __wcrtomb (mbc, wc, state);
+}
+
+static size_t wcsrtombs_init (
+  char *__restrict__ mbs,
+  const wchar_t **__restrict__ wcs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  HANDLE ucrt = LoadLibraryW (L"ucrtbase.dll");
+
+  if (ucrt == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain handle to 
ucrtbase.dll\n");
+    abort ();
+  }
+
+  __wcsrtombs_t real_wcsrtombs = (__wcsrtombs_t) GetProcAddress (ucrt, 
"wcsrtombs");
+
+  if (real_wcsrtombs == NULL) {
+    fwprintf (stderr, L"Runtime error: failed to obtain address of wcsrtombs 
function\n");
+    abort ();
+  }
+
+  InterlockedExchangePointer ((PVOID volatile *) &__wcsrtombs, (PVOID) 
real_wcsrtombs);
+  FreeLibrary (ucrt);
+
+  return __wcsrtombs (mbs, wcs, count, state);
+}
+
+size_t __cdecl wcrtomb (
+  char *__restrict__ mbc,
+  wchar_t wc,
+  mbstate_t *__restrict__ state
+) {
+  if (MB_CUR_MAX > 2) {
+    return __wcrtomb (mbc, wc, state);
+  }
+  return __mingw_wcrtomb (mbc, wc, state);
+}
+
+size_t __cdecl wcsrtombs (
+  char *__restrict__ mbs,
+  const wchar_t **__restrict__ wcs,
+  size_t count,
+  mbstate_t *__restrict__ state
+) {
+  if (MB_CUR_MAX > 2) {
+    return __wcsrtombs (mbs, wcs, count, state);
+  }
+  return __mingw_wcsrtombs (mbs, wcs, count, state);
+}
diff --git a/mingw-w64-crt/misc/wcrtomb.c b/mingw-w64-crt/misc/wcrtomb.c
index 9f869e8f6..99ff2e0f7 100644
--- a/mingw-w64-crt/misc/wcrtomb.c
+++ b/mingw-w64-crt/misc/wcrtomb.c
@@ -3,16 +3,24 @@
  * This file is part of the mingw-w64 runtime package.
  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
  */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-#include "mb_wc_common.h"
-#include <wchar.h>
-#include <stdlib.h>
+
 #include <errno.h>
-#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+#include "mb_wc_common.h"
+
+#ifdef _UCRT
+#define wcrtomb   __mingw_wcrtomb
+#define wcsrtombs __mingw_wcsrtombs
+
+static size_t wcrtomb (char *__restrict__, wchar_t, mbstate_t *__restrict__);
+static size_t wcsrtombs (char *__restrict__, const wchar_t **__restrict__, 
size_t, mbstate_t *__restrict__);
+#endif
+
 static size_t wcrtomb_cp (
   char *__restrict__ mbc,
   wchar_t wc,
@@ -23,13 +31,13 @@ static size_t wcrtomb_cp (
   /* Set `state` to initial state */
   if (mbc == NULL) {
     if (state != NULL) {
-      *state = 0;
+      conversion_state_init (state);
     }
     return 1;
   }
 
   /* Detect invalid conversion state */
-  if (state != NULL && *state) {
+  if (!mbsinit (state)) {
     _set_errno (EINVAL);
     return (size_t) -1;
   }
@@ -73,6 +81,9 @@ eilseq:
   return (size_t) -1;
 }
 
+#ifdef _UCRT
+static
+#endif
 size_t wcrtomb (
   char *__restrict__ mbc,
   wchar_t wc,
@@ -86,6 +97,9 @@ size_t wcrtomb (
   return wcrtomb_cp (mbc, wc, state, cp, mb_cur_max);
 }
 
+#ifdef _UCRT
+static
+#endif
 size_t wcsrtombs (
   char *__restrict__ mbs,
   const wchar_t **__restrict__ wcs,
@@ -154,3 +168,8 @@ size_t wcsrtombs (
 
   return mbcConverted;
 }
+
+#ifdef _UCRT
+#undef wcrtomb
+#undef wcsrtombs
+#endif
-- 
2.50.1.windows.1

From 08cd999e10bfe9b953c0f71daad1374074498b9f Mon Sep 17 00:00:00 2001
From: Kirill Makurin <maiddais...@outlook.com>
Date: Mon, 11 Aug 2025 22:59:48 +0900
Subject: [PATCH 4/6] tests: add UCRT-specific test cases for C95 conversion
 functions

New UCRT-specific test cases are used to verify that conversion
from/to UTF-8 works as expected.

Signed-off-by: Kirill Makurin <maiddais...@outlook.com>
---
 mingw-w64-crt/testcases/t_mbrlen.c    |  66 ++++-
 mingw-w64-crt/testcases/t_mbrtowc.c   |  89 ++++++-
 mingw-w64-crt/testcases/t_mbsrtowcs.c | 176 ++++++++++++-
 mingw-w64-crt/testcases/t_wcrtomb.c   |  56 ++++-
 mingw-w64-crt/testcases/t_wcsrtombs.c | 340 +++++++++++++++++++++++++-
 5 files changed, 715 insertions(+), 12 deletions(-)

diff --git a/mingw-w64-crt/testcases/t_mbrlen.c 
b/mingw-w64-crt/testcases/t_mbrlen.c
index 222977aed..bc1d70193 100644
--- a/mingw-w64-crt/testcases/t_mbrlen.c
+++ b/mingw-w64-crt/testcases/t_mbrlen.c
@@ -22,10 +22,19 @@ char NonAscii[] = {(char) 0x80};
 char Multibyte[] = {(char) 0x81, (char) 0x81};
 char InvalidMultibyte[] = {(char) 0x81, 0};
 
-int main (void) {
 #ifdef _UCRT
-  return 77;
+/**
+ * Valid UTF-8 character which can be represented by a single wchar_t.
+ */
+char UTF8[] = "語";
+
+/**
+ * Valid UTF-8 character which cannot be represented by a single wchar_t.
+ */
+char UTF8SurrogatePair[] = "🧡";
 #endif
+
+int main (void) {
   mbstate_t state = {0};
 
   /**
@@ -146,6 +155,59 @@ int main (void) {
   // reset errno
   _set_errno (0);
 #endif
+#ifdef _UCRT
+  /**
+   * Test UTF-8
+   */
+  if (setlocale (LC_ALL, "en_US.UTF-8") != NULL) {
+    assert (MB_CUR_MAX == 4);
+
+    /**
+     * Make sure ASCII characters are handled correctly
+     */
+    for (char c = 0;; ++c) {
+      assert (mbrlen (&c, 1, &state) == !!c);
+      assert (mbsinit (&state));
+      assert (errno == 0);
+
+      if (c == 0x7F) {
+        break;
+      }
+    }
+
+    /**
+     * Get length of multibyte character
+     */
+
+    assert (mbrlen ((char *) UTF8, MB_CUR_MAX, &state) == 3);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Get length of incomplete multibyte character
+     */
+
+    assert (mbrlen ((char *) UTF8, 1, &state) == (size_t) -2);
+    assert (!mbsinit (&state));
+    assert (errno == 0);
+
+    assert (mbrlen ((char *) UTF8 + 1, 1, &state) == (size_t) -2);
+    assert (!mbsinit (&state));
+    assert (errno == 0);
+
+    assert (mbrlen ((char *) UTF8 + 2, 1, &state) == 1);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Get length of multibyte character which cannot fit into single wchar_t
+     */
+
+    assert (mbrlen ((char *) UTF8SurrogatePair, MB_CUR_MAX, &state) == 4);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+  }
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_mbrtowc.c 
b/mingw-w64-crt/testcases/t_mbrtowc.c
index ba5234402..524dcc644 100644
--- a/mingw-w64-crt/testcases/t_mbrtowc.c
+++ b/mingw-w64-crt/testcases/t_mbrtowc.c
@@ -22,10 +22,19 @@ char NonAscii[] = {(char) 0x80};
 char Multibyte[] = {(char) 0x81, (char) 0x81};
 char InvalidMultibyte[] = {(char) 0x81, 0};
 
-int main (void) {
 #ifdef _UCRT
-  return 77;
+/**
+ * Valid UTF-8 character which can be represented by a single wchar_t.
+ */
+char UTF8[] = "語";
+
+/**
+ * Valid UTF-8 character which cannot be represented by a single wchar_t.
+ */
+char UTF8SurrogatePair[] = "🧡";
 #endif
+
+int main (void) {
   mbstate_t state = {0};
   wchar_t   wc = WEOF;
 
@@ -171,6 +180,82 @@ int main (void) {
   // reset errno
   _set_errno (0);
 #endif
+#ifdef _UCRT
+  /**
+   * Test UTF-8
+   */
+  if (setlocale (LC_ALL, "en_US.UTF-8")) {
+    assert (MB_CUR_MAX == 4);
+
+    /**
+     * Make sure ASCII characters are handled correctly
+     */
+    for (char c = 0;; ++c) {
+      assert (mbrtowc (&wc, &c, 1, &state) == !!c);
+      assert (wc == c);
+      assert (mbsinit (&state));
+      assert (errno == 0);
+
+      if (c == 0x7F) {
+        break;
+      }
+    }
+
+    /**
+     * Convert multibyte character
+     */
+    wc = WEOF;
+
+    assert (mbrtowc (&wc, (char *) UTF8, MB_CUR_MAX, &state) == 3);
+    assert (wc == L'語');
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Get length of incomplete multibyte character
+     */
+    wc = WEOF;
+
+    assert (mbrtowc (&wc, (char *) UTF8, 1, &state) == (size_t) -2);
+    // assert (wc == WEOF);
+    assert (!mbsinit (&state));
+    assert (errno == 0);
+
+    assert (mbrtowc (&wc, (char *) UTF8 + 1, 1, &state) == (size_t) -2);
+    // assert (wc == WEOF);
+    assert (!mbsinit (&state));
+    assert (errno == 0);
+
+    assert (mbrtowc (&wc, (char *) UTF8 + 2, 1, &state) == 1);
+    assert (wc == L'語');
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Try convert multibyte character which cannot fit into single wchar_t
+     */
+    wc = WEOF;
+
+    assert (mbrtowc (&wc, (char *) UTF8SurrogatePair, MB_CUR_MAX, &state) == 
4);
+    assert (wc == 0xFFFD);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Try convert invalid multibyte character
+     */
+    UTF8[1] = '\0';
+    wc = WEOF;
+
+    assert (mbrtowc (&wc, (char *) UTF8, MB_CUR_MAX, &state) == (size_t) -1);
+    // assert (wc == WEOF);
+    assert (mbsinit (&state));
+    assert (errno == EILSEQ);
+
+    // reset errno
+    _set_errno (0);
+  }
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_mbsrtowcs.c 
b/mingw-w64-crt/testcases/t_mbsrtowcs.c
index 00ac00e35..ab331e4d4 100644
--- a/mingw-w64-crt/testcases/t_mbsrtowcs.c
+++ b/mingw-w64-crt/testcases/t_mbsrtowcs.c
@@ -20,10 +20,19 @@ unsigned char MixedText[] = {0x93, 0xFA, 'n', 'i', 0x96, 
0x7B, 'h', 'o', 'n', 0x
 /* DBCS text with truncated multibyte character */
 unsigned char BadText[] = {0x93, 0xFA, 0x96, 0x7B, 0x8C, 0x0};
 
-int main (void) {
 #ifdef _UCRT
-  return 77;
+/**
+ * UTF-8 Text
+ */
+char UTF8[] = "日本語テクスト";
+
+/**
+ * UTF-8 Text which will produce UTF-16 surrogate pairs in output
+ */
+char UTF8SurrogatePair[] = "🧡🩷";
 #endif
+
+int main (void) {
   mbstate_t state = {0};
   wchar_t   buffer[BUFSIZ];
 
@@ -376,6 +385,169 @@ int main (void) {
   // reset errno
   _set_errno (0);
 #endif
+#ifdef _UCRT
+  if (setlocale (LC_ALL, "en_US.UTF-8") != NULL) {
+    assert (MB_CUR_MAX == 4);
+
+    /**
+     * Test ASCII input
+     */
+    original_text = AsciiText;
+    text_length = sizeof AsciiText - 1;
+
+    /**
+     * Convert AsciiString
+     *
+     * - return value must be `text_length`
+     * - value of `text` must be NULL
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     * - converted string must be terminated with '\0'
+     */
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == text_length);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[text_length] == L'\0');
+
+    /**
+     * Test UTF-8 input
+     */
+    original_text = UTF8;
+
+    /**
+     * Get length of converted UTF8
+     *
+     * - return value must be 7
+     * - value of `text` must not change
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     */
+    text = original_text;
+
+    assert (mbsrtowcs (NULL, &text, 0, &state) == 7);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert UTF8
+     *
+     * - return value must be 7
+     * - value of `text` must not change
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     * - converted string must be terminated with '\0'
+     */
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == 7);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[7] == L'\0');
+
+    /**
+     * Convert 3 multibyte characters in UTF8
+     *
+     * - return value must be 3
+     * - value of `text` must be `original_text + 9`
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     * - converted string must not be terminated with '\0'
+     */
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, 3, &state) == 3);
+    assert (text == original_text + 9);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[2] != WEOF && buffer[2] != L'\0' && buffer[3] == WEOF);
+
+    /**
+     * Try convert invalid UTF-8 string
+     *
+     * - return value must be (size_t)-1
+     * - value of `text` must be `original_text + 3`
+     * - `state` must be in the initial state
+     * - value of `errno` must be EILSEQ
+     * - converted string must not be terminated with '\0'
+     */
+    UTF8[4] = '\0';
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == (size_t) -1);
+    assert (text == original_text + 3);
+    assert (mbsinit (&state));
+    assert (errno == EILSEQ);
+    assert (buffer[0] != WEOF && buffer[0] != L'\0' && buffer[1] == WEOF);
+
+    // reset errno
+    _set_errno (0);
+
+    /**
+     * Test UTF-8 input which produces surrogate pairs in output
+     */
+    original_text = UTF8SurrogatePair;
+
+    /**
+     * Get length of converted UTF8SurrogatePair
+     *
+     * - return value must be 4
+     * - value of `text` must not change
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     */
+    text = original_text;
+
+    assert (mbsrtowcs (NULL, &text, 0, &state) == 4);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert UTF8SurrogatePair
+     *
+     * - return value must be 4
+     * - value of `text` must not change
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     * - converted string must be terminated with '\0'
+     */
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == 4);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[4] == L'\0');
+
+    /**
+     * Convert 1 multibyte character in UTF8SurrogatePair
+     *
+     * - return value must be 2
+     * - value of `text` must be `original_text + 4`
+     * - `state` must be in the initial state
+     * - value of `errno` must not change
+     * - converted string must not be terminated with '\0'
+     */
+    wmemset (buffer, WEOF, BUFSIZ);
+    text = original_text;
+
+    assert (mbsrtowcs (buffer, &text, 3, &state) == 2);
+    assert (text == original_text + 4);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[2] == WEOF);
+  }
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_wcrtomb.c 
b/mingw-w64-crt/testcases/t_wcrtomb.c
index d02cbdce0..40dcddb16 100644
--- a/mingw-w64-crt/testcases/t_wcrtomb.c
+++ b/mingw-w64-crt/testcases/t_wcrtomb.c
@@ -21,9 +21,6 @@ static void set_conversion_state (mbstate_t *state, int 
bytes) {
 }
 
 int main (void) {
-#ifdef _UCRT
-  return 77;
-#endif
   mbstate_t state = {0};
 
   /**
@@ -203,6 +200,59 @@ int main (void) {
     }
   }
 #endif
+#ifdef _UCRT
+  /**
+   * Test UTF-8
+   */
+  if (setlocale (LC_ALL, "en_US.UTF-8") != NULL) {
+    assert (MB_CUR_MAX == 4);
+
+    /**
+     * All values in range [0,127] are valid characters
+     */
+    for (wchar_t wc = 0; wc < 0x80; ++wc) {
+      char c = EOF;
+
+      assert (wcrtomb (&c, wc, &state) == 1);
+      assert ((unsigned char) c == wc);
+      assert (errno == 0);
+      assert (mbsinit (&state));
+    }
+
+    /**
+     * Try convert multibyte characters
+     */
+    for (size_t i = 0; i < _countof (DBCS); ++i) {
+      char buffer[MB_LEN_MAX] = {0};
+
+      assert (wcrtomb (buffer, DBCS[i], &state) == 3);
+      assert (buffer[0] != 0 && buffer[1] != 0 && buffer[2] != 0);
+      assert (errno == 0);
+      assert (mbsinit (&state));
+    }
+
+    /**
+     * Try to convert low and high surrogates
+     */
+    for (wchar_t wc = 0;; ++wc) {
+      if (IS_LOW_SURROGATE (wc) || IS_HIGH_SURROGATE (wc)) {
+        char buffer[MB_LEN_MAX] = {EOF};
+
+        assert (wcrtomb (buffer, wc, &state) == (size_t) -1);
+        assert (buffer[0] == EOF);
+        assert (errno = EILSEQ);
+        assert (mbsinit (&state));
+
+        // reset errno
+        _set_errno (0);
+      }
+
+      if (wc == WEOF) {
+        break;
+      }
+    }
+  }
+#endif
 
   return 0;
 }
diff --git a/mingw-w64-crt/testcases/t_wcsrtombs.c 
b/mingw-w64-crt/testcases/t_wcsrtombs.c
index 9979e9c38..2a74ed766 100644
--- a/mingw-w64-crt/testcases/t_wcsrtombs.c
+++ b/mingw-w64-crt/testcases/t_wcsrtombs.c
@@ -14,12 +14,16 @@ wchar_t AsciiText[] = L"Simple English text.";
 wchar_t SBCSText[] = L"Sömè fÛnnÿ têxt";
 wchar_t DBCSText[] = L"日本語テクスト";
 wchar_t MixedText[] = L"日NI本HON語GO";
-wchar_t BadText[] = {L'テ', L'く', WEOF, L'ト'};
+wchar_t BadText[] = {L'テ', L'く', 0xDC00, L'ト'};
 
-int main (void) {
 #ifdef _UCRT
-  return 77;
+/**
+ * Text which contains UTF-16 surrogate pairs
+ */
+wchar_t UTF8SurrogatePairs[] = L"🧡🩷";
 #endif
+
+int main (void) {
   const wchar_t *original_text = NULL;
   const wchar_t *text = NULL;
   size_t         text_length = 0;
@@ -566,6 +570,336 @@ int main (void) {
   // reset errno
   _set_errno (0);
 #endif
+#ifdef _UCRT
+  if (setlocale (LC_ALL, "en_US.UTF-8") != NULL) {
+    assert (MB_CUR_MAX == 4);
+
+    /**
+     * Test ASCII input
+     */
+    original_text = AsciiText;
+    text_length = _countof (AsciiText) - 1;
+
+    /**
+     * Get length of converted AsciiText
+     *
+     * - return value must be `text_length`
+     * - value of `test` must not change
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     */
+    text = AsciiText;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == text_length);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert AsciiText
+     *
+     * - return value must be `text_length`
+     * - value of `test` must be NULL
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = AsciiText;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[text_length] == '\0');
+
+    /**
+     * Convert 10 wide characters in AsciiText
+     *
+     * - return value must be 10
+     * - value of `test` must be `original_text + 10`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must not be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = AsciiText;
+
+    assert (wcsrtombs (buffer, &text, 10, &state) == 10);
+    assert (text == original_text + 10);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[10] == EOF);
+
+    /**
+     * Test SBCS input
+     */
+    original_text = SBCSText;
+    text_length = _countof (SBCSText) - 1;
+
+    /**
+     * Get length of converted SBCSText
+     *
+     * - return value must be `text_length + 5`
+     * - value of `text` must not change
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     */
+    text = SBCSText;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == text_length + 5);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert SBCSText
+     *
+     * - return value must be `text_length + 5`
+     * - value of `text` must be NULL
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = SBCSText;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length + 5);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[text_length + 5] == '\0');
+
+    /**
+     * Convert 9 wide characters in SBCSText
+     *
+     * - return value must be 14
+     * - value of `text` must be `original_text + 9`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must not be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = SBCSText;
+
+    assert (wcsrtombs (buffer, &text, 13, &state) == 12);
+    assert (text == original_text + 9);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[12] == EOF);
+
+    /**
+     * Test DBCS input
+     */
+    original_text = DBCSText;
+    text_length = _countof (DBCSText) - 1;
+
+    /**
+     * Get length of converted DBCSText
+     *
+     * - return value must be 21
+     * - value of `text` must not change
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     */
+    text = original_text;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == 21);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert DBCSText
+     *
+     * - return value must be 21
+     * - value of `text` must be NULL
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == 21);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[21] == '\0');
+
+    /**
+     * Convert 5 wide characters in DBCSText
+     *
+     * - return value must be 15
+     * - value of `text` must be `original_text + 5`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must not be terminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, 17, &state) == 15);
+    assert (text == original_text + 5);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[15] == EOF && buffer[16] == EOF);
+
+    /**
+     * Test mixed input
+     */
+    original_text = MixedText;
+    text_length = _countof (MixedText) - 1;
+
+    /**
+     * Get length of converted MixedText
+     *
+     * - return value must be 16
+     * - value of `test` must not change
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     */
+    text = original_text;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == 16);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert MixedText
+     *
+     * - return value must be 16
+     * - value of `test` must be NULL
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must be teminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == 16);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[16] == '\0');
+
+    /**
+     * Convert 7 wide characters in MixedText
+     *
+     * - return value must be 11
+     * - value of `test` must be `original_text + 7`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must not be teminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, 13, &state) == 11);
+    assert (text == original_text + 7);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[11] == EOF && buffer[12] == EOF);
+
+    /**
+     * Test bad input
+     */
+    original_text = BadText;
+    text_length = _countof (BadText) - 1;
+
+    /**
+     * Try get length of converted BadText
+     *
+     * - return value must be (size_t)-1
+     * - value of `text` must not change
+     * - value of `errno` must be EILSEQ
+     * - `state` must be in initial state
+     */
+    text = original_text;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == (size_t) -1);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == EILSEQ);
+
+    /**
+     * Try convert BadText
+     *
+     * - return value must be (size_t)-1
+     * - value of `text` must be `original_text + 2`
+     * - value of `errno` must be EILSEQ
+     * - `state` must be in initial state
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == (size_t) -1);
+    assert (text == original_text + 2);
+    assert (mbsinit (&state));
+    assert (errno == EILSEQ);
+    assert (buffer[5] != EOF && buffer[6] == EOF);
+
+    // reset errno
+    _set_errno (0);
+
+    /**
+     * Test input which contains surrogate pairs
+     */
+    original_text = UTF8SurrogatePairs;
+
+    /**
+     * Get length of converted UTF8SurrogatePairs
+     *
+     * - return value must be 8
+     * - value of `test` must not change
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     */
+    text = original_text;
+
+    assert (wcsrtombs (NULL, &text, 0, &state) == 8);
+    assert (text == original_text);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+
+    /**
+     * Convert UTF8SurrogatePairs
+     *
+     * - return value must be 8
+     * - value of `test` must be `NULL`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must be teminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == 8);
+    assert (text == NULL);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[8] == L'\0');
+
+    /**
+     * Convert single multibyte character in UTF8SurrogatePairs
+     *
+     * - return value must be 4
+     * - value of `test` must be `original_text + 2`
+     * - value of `errno` must not change
+     * - `state` must be in initial state
+     * - converted string must not be teminated with '\0'
+     */
+    memset (buffer, EOF, BUFSIZ);
+    text = original_text;
+
+    assert (wcsrtombs (buffer, &text, 7, &state) == 4);
+    assert (text == original_text + 2);
+    assert (mbsinit (&state));
+    assert (errno == 0);
+    assert (buffer[4] == EOF);
+  }
+#endif
 
   return 0;
 }
-- 
2.50.1.windows.1

From 7922db53364632e05d023b1d2000fc084510cce1 Mon Sep 17 00:00:00 2001
From: Kirill Makurin <maiddais...@outlook.com>
Date: Mon, 11 Aug 2025 23:09:40 +0900
Subject: [PATCH 5/6] crt: fix return value of mbrlen and mbrtowc functions
 with DBCS code pages

CRT's mbrlen and mbrtowc functions return incorrect value if previous call
to either of them has returned (size_t)-2 when converting using DBCS code page.

Previously, mingw-w64's implementation of those functions was implementing
the same buggy behavior for compatibility with CRT.

Now, mingw-w64's implementation is always used when convering from/to
SBCS and DBCS code pages. This allows us to provide implementation which
returns correct value for all CRTs.

Signed-off-by: Kirill Makurin <maiddais...@outlook.com>
---
 mingw-w64-crt/misc/mbrtowc.c        | 7 ++++++-
 mingw-w64-crt/testcases/t_mbrlen.c  | 5 +----
 mingw-w64-crt/testcases/t_mbrtowc.c | 5 +----
 3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/mingw-w64-crt/misc/mbrtowc.c b/mingw-w64-crt/misc/mbrtowc.c
index 90b205270..8064c09ca 100644
--- a/mingw-w64-crt/misc/mbrtowc.c
+++ b/mingw-w64-crt/misc/mbrtowc.c
@@ -73,9 +73,12 @@ static size_t mbrtowc_cp (
 
   /* Length of potential multibyte character */
   int length = 1;
+  /* Number of bytes consumed from `mbs` */
+  int bytes_consumed = 0;
 
   if (conversion_state.bytes[0]) {
     conversion_state.bytes[1] = mbs[0];
+    bytes_consumed = 1;
     length = 2;
   } else if (mb_cur_max == 2 && IsDBCSLeadByteEx (cp, (BYTE) mbs[0])) {
     conversion_state.bytes[0] = mbs[0];
@@ -87,9 +90,11 @@ static size_t mbrtowc_cp (
     }
 
     conversion_state.bytes[1] = mbs[1];
+    bytes_consumed = 2;
     length = 2;
   } else {
     conversion_state.bytes[0] = mbs[0];
+    bytes_consumed = 1;
   }
 
   /* Store terminating '\0' */
@@ -122,7 +127,7 @@ static size_t mbrtowc_cp (
     conversion_state_init (state);
   }
 
-  return length;
+  return bytes_consumed;
 
 eilseq:
   _set_errno (EILSEQ);
diff --git a/mingw-w64-crt/testcases/t_mbrlen.c 
b/mingw-w64-crt/testcases/t_mbrlen.c
index bc1d70193..880b745b8 100644
--- a/mingw-w64-crt/testcases/t_mbrlen.c
+++ b/mingw-w64-crt/testcases/t_mbrlen.c
@@ -127,12 +127,9 @@ int main (void) {
 
   /**
    * Complete multibyte character
-   *
-   * NOTE: return value does not conform to ISO C and POSIX.
-   * This behavior is implemented for consistency with CRT.
    */
 
-  assert (mbrlen ((char *) Multibyte + 1, 1, &state) == 2);
+  assert (mbrlen ((char *) Multibyte + 1, 1, &state) == 1);
   assert (mbsinit (&state));
   assert (errno == 0);
 
diff --git a/mingw-w64-crt/testcases/t_mbrtowc.c 
b/mingw-w64-crt/testcases/t_mbrtowc.c
index 524dcc644..afa5b10ea 100644
--- a/mingw-w64-crt/testcases/t_mbrtowc.c
+++ b/mingw-w64-crt/testcases/t_mbrtowc.c
@@ -145,13 +145,10 @@ int main (void) {
 
   /**
    * Complete multibyte character
-   *
-   * NOTE: return value does not conform to ISO C and POSIX.
-   * This behavior is implemented for consistency with CRT.
    */
   wc = WEOF;
 
-  assert (mbrtowc (&wc, (char *) Multibyte + 1, 1, &state) == 2);
+  assert (mbrtowc (&wc, (char *) Multibyte + 1, 1, &state) == 1);
   assert (wc != WEOF);
   assert (mbsinit (&state));
   assert (errno == 0);
-- 
2.50.1.windows.1

_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to