On Sat, 25 Oct 2025, Pali Rohár wrote:
Format %Z takes pointer to ANSI_STRING or UNICODE_STRING based on the
wideness of format.
In this mingw-w64 implementation (same as in UCRT) the uppercase format %Z
has the same default wideness as uppercase format %S when no h, l or w
modifier is specified.
Format %Z is supported by crtdll, msvcrt and UCRT libraries. There are some
differences between individual CRT versions regarding the wide wprintf(%lZ),
narrow printf(%Z/%lZ) and whether nul chars in ANSI_STRING are accepted by
wprintf or not. In mingw-w64 for compatibility reasons are accepted.
The last sentence, "In mingw-w64 for compatibility reasons are accepted."
seems like it is missing something, in order to make sense.
diff --git a/mingw-w64-crt/stdio/mingw_pformat.c
b/mingw-w64-crt/stdio/mingw_pformat.c
index bdc7eba2a573..ded916c9a2bc 100644
--- a/mingw-w64-crt/stdio/mingw_pformat.c
+++ b/mingw-w64-crt/stdio/mingw_pformat.c
@@ -66,6 +66,7 @@
#include <limits.h>
#include <locale.h>
#include <wchar.h>
+#include <ntdef.h>
#ifdef __ENABLE_DFP
#ifndef __STDC_WANT_DEC_FP__
@@ -2558,6 +2559,64 @@ __pformat (int flags, void *dest, int max, const APICHAR
*fmt, va_list argv)
*/
__pformat_puts( va_arg( argv, char * ), &stream );
goto format_scan;
+
+ case 'Z':
+ /*
+ * The logic for `%Z` length modifier is quite complicated.
+ *
+ * for printf:
+ * `%Z` - UNICODE_STRING for UCRT; ANSI_STRING for
crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
+ * `%hZ` - ANSI_STRING
+ * `%lZ` - UNICODE_STRING for UCRT; ANSI_STRING for
crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
+ * `%wZ` - UNICODE_STRING
+ *
+ * for wprintf:
+ * `%Z` - ANSI_STRING
+ * `%hZ` - ANSI_STRING
+ * `%lZ` - UNICODE_STRING for UCRT; ANSI_STRING for
crtdll,msvcrt10,msvcrt,msvcr80-msvcr120
+ * `%wZ` - UNICODE_STRING
+ *
+ * There are some other changes between versions regarding nul
chars.
+ * - msvcrt since Vista, msvcr80+ and UCRT do not accept nul chars
in ANSI_STRING for wprintf. They stop at nul char and returns -1.
+ * - crtdll, msvcrt10 and msvcrt before Vista accept nul char in
ANSI_STRING for wprintf, but ANSI_STRING content after nul char is discarded.
This explanation doesn't feel like it makes sense to me. If it accepts the
nul char, the wouldn't it also proceed after that? So do you say that it
includes the single nul char in the output, but nothing after it? While
the logical thing would be to either stop at the nul (not outputting it)
or include everything?
+ * - ANSI_STRING for printf, and UNICODE_STRING for both printf
and wprintf works fine in all versions.
+ *
+ * This mingw-w64 implementation uses UCRT behavior of length
modifiers.
+ * And for compatibility with older msvcrt versions, it accepts
also
+ * nul chars in ANSI_STRING for wprintf and discard content after
+ * nul char (like msvcrt).
Same thing in this explanation here.
Or should the first case be UNICODE_STRING in both of these explanations?
Accept nul in UNICODE_STRING, terminate at nul in ANSI_STRING?
// Martin
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public