[PATCH 4/6] ntdll: Implement debugstr_a/w(n) format extensions.

Rémi Bernon rbernon at codeweavers.com
Sat Nov 21 14:19:11 CST 2020


This makes it possible to write TRACE("%p(astr)", "string") and get the
equivalent of TRACE("%s", debugstr_a("string")), respectively with
"%p(wstr)" and debugstr_w(...).

The width format specifier (including '*') can be used to control the
length (GCC format checker doesn't like precision specifier on %p).

Note that the format extension is just here to illustrate, we could
think of any other syntax. The main issue is to pass GCC format checker,
and as done in the Linux kernel %p suffixes seems to be the best fit.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/ntdll/unix/debug.c | 96 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/unix/debug.c b/dlls/ntdll/unix/debug.c
index 2b2d63b7adf..6c4b86196c8 100644
--- a/dlls/ntdll/unix/debug.c
+++ b/dlls/ntdll/unix/debug.c
@@ -289,6 +289,90 @@ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_
     return append_output( info, buffer, strlen( buffer ));
 }
 
+static size_t sprintf_dbgstr_an( char *buffer, size_t length, const char *str, int n )
+{
+    static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+    char *dst = buffer;
+
+    if (!str) { if (length >= 7) strcpy(buffer, "(null)"); return 6; }
+    if (!((ULONG_PTR)str >> 16)) return snprintf( buffer, length, "#%04x", LOWORD(str) );
+    if (n == -1) for (n = 0; str[n]; n++) ;
+    *dst++ = '"';
+    while (n-- > 0 && dst <= buffer + length - 9)
+    {
+        unsigned char c = *str++;
+        switch (c)
+        {
+        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
+        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
+        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
+        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
+        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
+        default:
+            if (c < ' ' || c >= 127)
+            {
+                *dst++ = '\\';
+                *dst++ = 'x';
+                *dst++ = hex[(c >> 4) & 0x0f];
+                *dst++ = hex[c & 0x0f];
+            }
+            else *dst++ = c;
+        }
+    }
+    *dst++ = '"';
+    if (n > 0)
+    {
+        *dst++ = '.';
+        *dst++ = '.';
+        *dst++ = '.';
+    }
+    *dst = 0;
+    return dst - buffer;
+}
+
+static size_t sprintf_dbgstr_wn( char *buffer, size_t length, const WCHAR *str, int n )
+{
+    static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+    char *dst = buffer;
+
+    if (!str) { if (length >= 7) strcpy(buffer, "(null)"); return 6; }
+    if (!((ULONG_PTR)str >> 16)) return snprintf( buffer, length, "#%04x", LOWORD(str) );
+    if (n == -1) for (n = 0; str[n]; n++) ;
+    *dst++ = 'L';
+    *dst++ = '"';
+    while (n-- > 0 && dst <= buffer + length - 10)
+    {
+        WCHAR c = *str++;
+        switch (c)
+        {
+        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
+        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
+        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
+        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
+        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
+        default:
+            if (c < ' ' || c >= 127)
+            {
+                *dst++ = '\\';
+                *dst++ = hex[(c >> 12) & 0x0f];
+                *dst++ = hex[(c >> 8) & 0x0f];
+                *dst++ = hex[(c >> 4) & 0x0f];
+                *dst++ = hex[c & 0x0f];
+            }
+            else *dst++ = (char)c;
+        }
+    }
+    *dst++ = '"';
+    if (n > 0)
+    {
+        *dst++ = '.';
+        *dst++ = '.';
+        *dst++ = '.';
+    }
+    *dst = 0;
+    return dst - buffer;
+}
+
 static int __cdecl wine_dbg_vsnprintf( char *buffer, size_t length, const char *format, __ms_va_list args )
 {
     char fmtbuf[1024];
@@ -439,7 +523,17 @@ static int __cdecl wine_dbg_vsnprintf( char *buffer, size_t length, const char *
             }
             break;
         case 'p':
-            snprintf_dispatch( buf, end - buf, fmt, va_arg( args, void * ) );
+            if (!strncmp( spec, "p(astr)", 7 )) /* debugstr_a / debugstr_an */
+            {
+                append_checked( buf, end - buf, sprintf_dbgstr_an( buf, end - buf, va_arg( args, const char * ), w ) );
+                snprintf_checked( buf, end - buf, spec + 7 );
+            }
+            else if (!strncmp( spec, "p(wstr)", 7 )) /* debugstr_w / debugstr_wn */
+            {
+                append_checked( buf, end - buf, sprintf_dbgstr_wn( buf, end - buf, va_arg( args, const WCHAR * ), w ) );
+                snprintf_checked( buf, end - buf, spec + 7 );
+            }
+            else snprintf_dispatch( buf, end - buf, fmt, va_arg( args, void * ) );
             break;
         case 'A':
         case 'a':
-- 
2.29.2




More information about the wine-devel mailing list