Export the temp buffer functionality in the debug functions interface
to allow sharing more code between libwine and ntdll.

diff --git a/dlls/ntdll/debugtools.c b/dlls/ntdll/debugtools.c
index 80448df..2f0be3d 100644
--- a/dlls/ntdll/debugtools.c
+++ b/dlls/ntdll/debugtools.c
@@ -42,6 +42,8 @@
 
 WINE_DECLARE_DEBUG_CHANNEL(tid);
 
+static struct __wine_debug_functions default_funcs;
+
 /* ---------------------------------------------------------------------- */
 
 /* filter for page-fault exceptions */
@@ -59,7 +61,7 @@
 }
 
 /* allocate some tmp space for a string */
-static void *gimme1(int n)
+static char *get_temp_buffer( size_t n )
 {
     struct debug_info *info = get_info();
     char *res = info->str_pos;
@@ -70,101 +72,10 @@
 }
 
 /* release extra space that we requested in gimme1() */
-static inline void release( void *ptr )
+static void release_temp_buffer( char *ptr, size_t size )
 {
     struct debug_info *info = get_info();
-    info->str_pos = ptr;
-}
-
-/* put an ASCII string into the debug buffer */
-inline static char *put_string_a( const char *src, int n )
-{
-    static const char hex[16] = "0123456789abcdef";
-    char *dst, *res;
-    size_t size;
-
-    if (n == -1) n = strlen(src);
-    if (n < 0) n = 0;
-    size = 10 + min( 300, n * 4 );
-    dst = res = gimme1( size );
-    *dst++ = '"';
-    while (n-- > 0 && dst <= res + size - 9)
-    {
-        unsigned char c = *src++;
-        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 <= 126)
-                *dst++ = c;
-            else
-            {
-                *dst++ = '\\';
-                *dst++ = 'x';
-                *dst++ = hex[(c >> 4) & 0x0f];
-                *dst++ = hex[c & 0x0f];
-            }
-        }
-    }
-    *dst++ = '"';
-    if (*src)
-    {
-        *dst++ = '.';
-        *dst++ = '.';
-        *dst++ = '.';
-    }
-    *dst++ = '\0';
-    release( dst );
-    return res;
-}
-
-/* put a Unicode string into the debug buffer */
-inline static char *put_string_w( const WCHAR *src, int n )
-{
-    char *dst, *res;
-    size_t size;
-
-    if (n == -1) n = strlenW(src);
-    if (n < 0) n = 0;
-    size = 12 + min( 300, n * 5 );
-    dst = res = gimme1( size );
-    *dst++ = 'L';
-    *dst++ = '"';
-    while (n-- > 0 && dst <= res + size - 10)
-    {
-        WCHAR c = *src++;
-        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 <= 126)
-                *dst++ = c;
-            else
-            {
-                *dst++ = '\\';
-                sprintf(dst,"%04x",c);
-                dst+=4;
-            }
-        }
-    }
-    *dst++ = '"';
-    if (*src)
-    {
-        *dst++ = '.';
-        *dst++ = '.';
-        *dst++ = '.';
-    }
-    *dst++ = '\0';
-    release( dst );
-    return res;
+    info->str_pos = ptr + size;
 }
 
 /***********************************************************************
@@ -172,25 +83,18 @@
  */
 static const char *NTDLL_dbgstr_an( const char *src, int n )
 {
-    char *res, *old_pos;
+    const char *res;
     struct debug_info *info = get_info();
-
-    if (!HIWORD(src))
-    {
-        if (!src) return "(null)";
-        res = gimme1(6);
-        sprintf(res, "#%04x", LOWORD(src) );
-        return res;
-    }
     /* save current position to restore it on exception */
-    old_pos = info->str_pos;
+    char *old_pos = info->str_pos;
+
     __TRY
     {
-        res = put_string_a( src, n );
+        res = default_funcs.dbgstr_an( src, n );
     }
     __EXCEPT(page_fault)
     {
-        release( old_pos );
+        release_temp_buffer( old_pos, 0 );
         return "(invalid)";
     }
     __ENDTRY
@@ -202,26 +106,18 @@
  */
 static const char *NTDLL_dbgstr_wn( const WCHAR *src, int n )
 {
-    char *res, *old_pos;
+    const char *res;
     struct debug_info *info = get_info();
-
-    if (!HIWORD(src))
-    {
-        if (!src) return "(null)";
-        res = gimme1(6);
-        sprintf(res, "#%04x", LOWORD(src) );
-        return res;
-    }
-
     /* save current position to restore it on exception */
-    old_pos = info->str_pos;
+    char *old_pos = info->str_pos;
+
     __TRY
     {
-        res = put_string_w( src, n );
+        res = default_funcs.dbgstr_wn( src, n );
     }
     __EXCEPT(page_fault)
     {
-        release( old_pos );
+        release_temp_buffer( old_pos, 0 );
         return "(invalid)";
     }
     __ENDTRY
@@ -229,20 +125,6 @@
 }
 
 /***********************************************************************
- *		NTDLL_dbg_vsprintf
- */
-static const char *NTDLL_dbg_vsprintf( const char *format, va_list args )
-{
-    static const int max_size = 200;
-
-    char *res = gimme1( max_size );
-    int len = vsnprintf( res, max_size, format, args );
-    if (len == -1 || len >= max_size) res[max_size-1] = 0;
-    else release( res + len + 1 );
-    return res;
-}
-
-/***********************************************************************
  *		NTDLL_dbg_vprintf
  */
 static int NTDLL_dbg_vprintf( const char *format, va_list args )
@@ -305,9 +187,10 @@
 
 static const struct __wine_debug_functions funcs =
 {
+    get_temp_buffer,
+    release_temp_buffer,
     NTDLL_dbgstr_an,
     NTDLL_dbgstr_wn,
-    NTDLL_dbg_vsprintf,
     NTDLL_dbg_vprintf,
     NTDLL_dbg_vlog
 };
@@ -319,6 +202,6 @@
 {
     extern void __wine_dbg_ntdll_init(void);
 
-    __wine_dbg_set_functions( &funcs, sizeof(funcs) );
+    __wine_dbg_set_functions( &funcs, &default_funcs, sizeof(funcs) );
     __wine_dbg_ntdll_init();  /* hack: register debug channels early */
 }
diff --git a/include/wine/debug.h b/include/wine/debug.h
index a6a2ca7..181d718 100644
--- a/include/wine/debug.h
+++ b/include/wine/debug.h
@@ -137,15 +137,17 @@
 
 struct __wine_debug_functions
 {
+    char * (*get_temp_buffer)( size_t n );
+    void   (*release_temp_buffer)( char *buffer, size_t n );
     const char * (*dbgstr_an)( const char * s, int n );
     const char * (*dbgstr_wn)( const WCHAR *s, int n );
-    const char * (*dbg_vsprintf)( const char *format, va_list args );
     int (*dbg_vprintf)( const char *format, va_list args );
     int (*dbg_vlog)( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
                      const char *function, const char *format, va_list args );
 };
 
-extern void __wine_dbg_set_functions( const struct __wine_debug_functions *funcs, size_t size );
+extern void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs,
+                                      struct __wine_debug_functions *old_funcs, size_t size );
 
 /*
  * Exported definitions and macros
diff --git a/libs/wine/debug.c b/libs/wine/debug.c
index 34ebc14..28a179a 100644
--- a/libs/wine/debug.c
+++ b/libs/wine/debug.c
@@ -198,7 +198,7 @@
     return errors;
 }
 
-/* varargs wrapper for __wine_dbg_vprintf */
+/* varargs wrapper for funcs.dbg_vprintf */
 int wine_dbg_printf( const char *format, ... )
 {
     int ret;
@@ -210,21 +210,25 @@
     return ret;
 }
 
-
-/* varargs wrapper for __wine_dbg_vsprintf */
+/* printf with temp buffer allocation */
 const char *wine_dbg_sprintf( const char *format, ... )
 {
-    const char *ret;
+    static const int max_size = 200;
+    char *ret;
+    int len;
     va_list valist;
 
     va_start(valist, format);
-    ret = funcs.dbg_vsprintf( format, valist );
+    ret = funcs.get_temp_buffer( max_size );
+    len = vsnprintf( ret, max_size, format, valist );
+    if (len == -1 || len >= max_size) ret[max_size-1] = 0;
+    else funcs.release_temp_buffer( ret, len + 1 );
     va_end(valist);
     return ret;
 }
 
 
-/* varargs wrapper for __wine_dbg_vlog */
+/* varargs wrapper for funcs.dbg_vlog */
 int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
                   const char *func, const char *format, ... )
 {
@@ -240,7 +244,7 @@
 
 /* allocate some tmp string space */
 /* FIXME: this is not 100% thread-safe */
-static char *get_tmp_space( int size )
+static char *get_temp_buffer( size_t size )
 {
     static char *list[32];
     static int pos;
@@ -253,24 +257,33 @@
 }
 
 
+/* release unused part of the buffer */
+static void release_temp_buffer( char *buffer, size_t size )
+{
+    /* don't bother doing anything */
+}
+
+
 /* default implementation of wine_dbgstr_an */
 static const char *default_dbgstr_an( const char *str, int n )
 {
+    static const char hex[16] = "0123456789abcdef";
     char *dst, *res;
+    size_t size;
 
-    if (!HIWORD(str))
+    if (!((ULONG_PTR)str >> 16))
     {
         if (!str) return "(null)";
-        res = get_tmp_space( 6 );
+        res = funcs.get_temp_buffer( 6 );
         sprintf( res, "#%04x", LOWORD(str) );
         return res;
     }
     if (n == -1) n = strlen(str);
     if (n < 0) n = 0;
-    else if (n > 200) n = 200;
-    dst = res = get_tmp_space( n * 4 + 6 );
+    size = 10 + min( 300, n * 4 );
+    dst = res = funcs.get_temp_buffer( size );
     *dst++ = '"';
-    while (n-- > 0)
+    while (n-- > 0 && dst <= res + size - 9)
     {
         unsigned char c = *str++;
         switch (c)
@@ -286,9 +299,9 @@
             else
             {
                 *dst++ = '\\';
-                *dst++ = '0' + ((c >> 6) & 7);
-                *dst++ = '0' + ((c >> 3) & 7);
-                *dst++ = '0' + ((c >> 0) & 7);
+                *dst++ = 'x';
+                *dst++ = hex[(c >> 4) & 0x0f];
+                *dst++ = hex[c & 0x0f];
             }
         }
     }
@@ -299,7 +312,8 @@
         *dst++ = '.';
         *dst++ = '.';
     }
-    *dst = 0;
+    *dst++ = 0;
+    funcs.release_temp_buffer( res, dst - res );
     return res;
 }
 
@@ -308,21 +322,22 @@
 static const char *default_dbgstr_wn( const WCHAR *str, int n )
 {
     char *dst, *res;
+    size_t size;
 
-    if (!HIWORD(str))
+    if (!((ULONG_PTR)str >> 16))
     {
         if (!str) return "(null)";
-        res = get_tmp_space( 6 );
+        res = funcs.get_temp_buffer( 6 );
         sprintf( res, "#%04x", LOWORD(str) );
         return res;
     }
     if (n == -1) n = strlenW(str);
     if (n < 0) n = 0;
-    else if (n > 200) n = 200;
-    dst = res = get_tmp_space( n * 5 + 7 );
+    size = 12 + min( 300, n * 5 );
+    dst = res = funcs.get_temp_buffer( n * 5 + 7 );
     *dst++ = 'L';
     *dst++ = '"';
-    while (n-- > 0)
+    while (n-- > 0 && dst <= res + size - 10)
     {
         WCHAR c = *str++;
         switch (c)
@@ -350,22 +365,12 @@
         *dst++ = '.';
         *dst++ = '.';
     }
-    *dst = 0;
+    *dst++ = 0;
+    funcs.release_temp_buffer( res, dst - res );
     return res;
 }
 
 
-/* default implementation of wine_dbg_vsprintf */
-static const char *default_dbg_vsprintf( const char *format, va_list args )
-{
-    static const int max_size = 200;
-
-    char *res = get_tmp_space( max_size );
-    int len = vsnprintf( res, max_size, format, args );
-    if (len == -1 || len >= max_size) res[max_size-1] = 0;
-    return res;
-}
-
 /* default implementation of wine_dbg_vprintf */
 static int default_dbg_vprintf( const char *format, va_list args )
 {
@@ -408,16 +413,19 @@
     return funcs.dbgstr_wn( s, -1 );
 }
 
-void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs, size_t size )
+void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs,
+                               struct __wine_debug_functions *old_funcs, size_t size )
 {
-    memcpy( &funcs, new_funcs, min(sizeof(funcs),size) );
+    if (old_funcs) memcpy( old_funcs, &funcs, min(sizeof(funcs),size) );
+    if (new_funcs) memcpy( &funcs, new_funcs, min(sizeof(funcs),size) );
 }
 
 static struct __wine_debug_functions funcs =
 {
+    get_temp_buffer,
+    release_temp_buffer,
     default_dbgstr_an,
     default_dbgstr_wn,
-    default_dbg_vsprintf,
     default_dbg_vprintf,
     default_dbg_vlog
 };