On Fri, 19 Dec 2025, Pali Rohár wrote:
On Friday 19 December 2025 14:02:43 Martin Storsjö wrote:
On Fri, 19 Dec 2025, Pali Rohár wrote:
On Tuesday 18 November 2025 16:46:43 Pali Rohár wrote:
On Monday 17 November 2025 22:06:40 Martin Storsjö wrote:
On Mon, 17 Nov 2025, Pali Rohár wrote:
On Monday 17 November 2025 17:13:56 Martin Storsjö wrote:
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.
Ah, right, there is missing "they" (nul chars). Should be "they are accepted".
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?
I used term "accept" whether wprintf will continue or immediately
returns -1. I think that this was the main confusing here.
No, the main confusion here is that some of the sentences here are
contradicting themselves. The core of the confusion is above:
"crtdll, msvcrt10 and msvcrt before Vista accept nul char in ANSI_STRING for
wprintf, but ANSI_STRING content after nul char is discarded."
Here you describe two different behaviours for ANSI_STRING. Do you mean one
behaviour for ANSI_STRING and one for UNICODE_STRING?
// Martin
Ok, I will to rephrase that sentence:
crtdll, msvcrt10 and msvcrt before Vista accept ANSI_STRING with nul
chars in wprintf call, but the first nul char and everything after it in
the ANSI_STRING content is ignored and not printed by wprintf at all.
It is more clear my above last comment about behavior?
No it is still unclear.
Going back to the original quoted comment above:
+ * - 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.
Do you mean this:
- In both modes, printing stops at nul char in ANSI_STRING
In old versions, when the nul char is detected, char is not printed
and wprintf function jumps and continue formatting the next %format
argument. So it skips the nul char and everything after the nul char in
the current ANSI_STRING %format argument. But all remaining %format
arguments are processed.
In new version, when the nul char is detected, char is not printed and
wprintf function returns -1. So it skips the nul char and everything
after nul char in the current ANSI_STRING %format argument. And it also
skips also all other remaining %format arguments.
Lets take this example:
wprintf(L"%d%hZ%d", 1, compose_ANSI_STRING("A\0B"), 2);
Old version returns <success> and prints: "1A2"
New version returns <failure> (-1) and prints: "1A"
Ok, I see - this makes it clear.
To clarify your original comment:
+ * - 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.
Admittedly, after your explanation above, this comment does read
understandably. But that doesn't help for people reading it the first
time...
Maybe it would be clearer like this:
* - msvcrt since Vista, msvcr80+ and UCRT do not accept nul chars in
ANSI_STRING for wprintf. If encountering a nul char, it stops
processing the format string 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.
// Martin
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public