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

Reply via email to