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.
---
 mingw-w64-crt/stdio/mingw_pformat.c | 59 +++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/mingw-w64-crt/stdio/mingw_pformat.c 
b/mingw-w64-crt/stdio/mingw_pformat.c
index a2ef12da2de8..5c1ec41b5b8c 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__
@@ -2530,6 +2531,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.
+             * - 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 charts in ANSI_STRING for wprintf and discard content after
+             * nul char (like msvcrt).
+             */
+            if( length == PFORMAT_LENGTH_INT )
+            {
+    #ifndef __BUILD_WIDEAPI
+              length = PFORMAT_LENGTH_LONG;
+    #else
+              length = PFORMAT_LENGTH_SHORT;
+    #endif
+            }
+
+            if( (length == PFORMAT_LENGTH_LONG)
+                 || (length == PFORMAT_LENGTH_LLONG)
+              )
+            {
+              const UNICODE_STRING *s = va_arg( argv, UNICODE_STRING * );
+              const wchar_t *buf = (s && s->Buffer) ? (const wchar_t 
*)s->Buffer : L"(null)";
+              const int len = (s && s->Buffer) ? s->Length/sizeof(wchar_t) /* 
accept content after nul char */ : ( sizeof( "(null)" ) - 1 );
+              __pformat_wputchars( buf, len, &stream );
+            }
+            else
+            {
+              const ANSI_STRING *s = va_arg( argv, ANSI_STRING * );
+              const char *buf = (s && s->Buffer) ? (const char *)s->Buffer : 
"(null)";
+    #ifndef __BUILD_WIDEAPI
+              const int len = (s && s->Buffer) ? s->Length /* accept content 
after nul char */ : ( sizeof( "(null)" ) - 1 );
+    #else
+              const int len = (s && s->Buffer) ? strnlen( (const char 
*)s->Buffer, s->Length ) /* discard content after nul char */ : ( sizeof( 
"(null)" ) - 1 );
+    #endif
+              __pformat_putchars( buf, len, &stream );
+            }
+            goto format_scan;
+
           case 'm': /* strerror (errno)  */
             __pformat_puts (strerror (saved_errno), &stream);
             goto format_scan;
-- 
2.20.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