MSVCRT: add handling of %ws, %S and %C to _vsn(w)printf, improve sprintf tests

Mike McCormack mike at codeweavers.com
Sat Feb 12 08:27:26 CST 2005


This implementation uses libc's printf for floats and integers, and 
handles other format strings itself.  The _vsnwprintf and _vsnprintf are 
handled by the new code so they remain consistent with each other.

Mike


ChangeLog:
* add handling of %ws, %S and %C to _vns(w)printf, improve sprintf tests
-------------- next part --------------
Index: dlls/msvcrt/msvcrt.spec
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/msvcrt.spec,v
retrieving revision 1.95
diff -u -p -r1.95 msvcrt.spec
--- dlls/msvcrt/msvcrt.spec	10 Dec 2004 15:28:25 -0000	1.95
+++ dlls/msvcrt/msvcrt.spec	12 Feb 2005 14:10:06 -0000
@@ -484,8 +484,8 @@
 @ cdecl _unloaddll(long)
 @ cdecl _unlock(long)
 @ cdecl _utime(str ptr)
-@ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf
-@ cdecl _vsnwprintf(ptr long wstr long)
+@ cdecl _vsnprintf(ptr long ptr ptr) MSVCRT_vsnprintf
+@ cdecl _vsnwprintf(ptr long wstr long) MSVCRT_vsnwprintf
 @ cdecl _waccess(wstr long)
 @ stub _wasctime #(ptr) MSVCRT__wasctime
 @ cdecl _wchdir(wstr)
@@ -693,7 +693,7 @@
 @ cdecl signal(long long) MSVCRT_signal
 @ cdecl sin(double)
 @ cdecl sinh(double)
-@ varargs sprintf(ptr str)
+@ varargs sprintf(ptr str) MSVCRT_sprintf
 @ cdecl sqrt(double)
 @ cdecl srand(long)
 @ varargs sscanf(str str) MSVCRT_sscanf
Index: dlls/msvcrt/wcs.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/wcs.c,v
retrieving revision 1.18
diff -u -p -r1.18 wcs.c
--- dlls/msvcrt/wcs.c	25 Jun 2004 01:19:15 -0000	1.18
+++ dlls/msvcrt/wcs.c	12 Feb 2005 14:10:06 -0000
@@ -21,6 +21,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <math.h>
+#include <assert.h>
 #include "msvcrt.h"
 #include "winnls.h"
 #include "wine/unicode.h"
@@ -178,184 +179,490 @@ double MSVCRT_wcstod(const MSVCRT_wchar_
   return ret;
 }
 
-static int MSVCRT_vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
+
+typedef struct pf_output_t
+{
+    int used;
+    int len;
+    BOOL unicode;
+    union {
+        LPWSTR W;
+        LPSTR  A;
+    } buf;
+} pf_output;
+
+typedef struct pf_flags_t
+{
+    char Sign, LeftAlign, Alternate, PadZero;
+    char FieldLength, Precision;
+    char IntegerLength, IntegerDouble;
+    char WideString;
+    char Format;
+} pf_flags;
+
+/*
+ * writes a string of characters to the output
+ * returns -1 if the string doesn't fit in the output buffer
+ * return the length of the string if all characters were written
+ */
+static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
 {
-    unsigned int written = 0;
-    const WCHAR *iter = format;
-    char bufa[256], fmtbufa[64], *fmta;
+    int space = out->len - out->used;
 
-    while (*iter)
+    if( len < 0 )
+        len = strlenW( str );
+    if( out->unicode )
     {
-        while (*iter && *iter != '%')
+        LPWSTR p = out->buf.W + out->used;
+
+        if( space >= len )
         {
-            if (written++ >= len)
-                return -1;
-            *str++ = *iter++;
+            memcpy( p, str, len*sizeof(WCHAR) );
+            out->used += len;
+            return len;
         }
-        if (*iter == '%')
+        if( space > 0 )
+            memcpy( p, str, space*sizeof(WCHAR) );
+        out->used += len;
+    }
+    else
+    {
+        int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
+        LPSTR p = out->buf.A + out->used;
+
+        if( space >= n )
         {
-            if (iter[1] == '%')
-            {
-                if (written++ >= len)
-                    return -1;
-                *str++ = '%'; /* "%%"->'%' */
-                iter += 2;
-                continue;
-            }
+            WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
+            out->used += n;
+            return len;
+        }
+        if( space > 0 )
+            WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
+        out->used += n;
+    }
+    return -1;
+}
 
-            fmta = fmtbufa;
-            *fmta++ = *iter++;
-            while (*iter == '0' ||
-                   *iter == '+' ||
-                   *iter == '-' ||
-                   *iter == ' ' ||
-                   *iter == '*' ||
-                   *iter == '#')
-            {
-                if (*iter == '*')
-                {
-                    char *buffiter = bufa;
-                    int fieldlen = va_arg(valist, int);
-                    sprintf(buffiter, "%d", fieldlen);
-                    while (*buffiter)
-                        *fmta++ = *buffiter++;
-                }
-                else
-                    *fmta++ = *iter;
-                iter++;
-            }
+static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
+{
+    int space = out->len - out->used;
 
-            while (isdigit(*iter))
-                *fmta++ = *iter++;
+    if( len < 0 )
+        len = strlen( str );
+    if( !out->unicode )
+    {
+        LPSTR p = out->buf.A + out->used;
 
-            if (*iter == '.')
-            {
-                *fmta++ = *iter++;
-                if (*iter == '*')
-                {
-                    char *buffiter = bufa;
-                    int fieldlen = va_arg(valist, int);
-                    sprintf(buffiter, "%d", fieldlen);
-                    while (*buffiter)
-                        *fmta++ = *buffiter++;
-                }
-                else
-                    while (isdigit(*iter))
-                        *fmta++ = *iter++;
-            }
-            if (*iter == 'h' || *iter == 'l')
-                *fmta++ = *iter++;
+        if( space >= len )
+        {
+            memcpy( p, str, len );
+            out->used += len;
+            return len;
+        }
+        if( space > 0 )
+            memcpy( p, str, space );
+        out->used += len;
+    }
+    else
+    {
+        int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
+        LPWSTR p = out->buf.W + out->used;
 
-            switch (*iter)
-            {
-            case 'S':
-            {
-                static const char *none = "(null)";
-                const char *astr = va_arg(valist, const char *);
-                const char *striter = astr ? astr : none;
-                int r, n;
-                while (*striter)
-                {
-                    if (written >= len)
-                        return -1;
-                    n = 1;
-                    if( IsDBCSLeadByte( *striter ) )
-                        n++;
-                    r = MultiByteToWideChar( CP_ACP, 0,
-                               striter, n, str, len - written );
-                    striter += n;
-                    str += r;
-                    written += r;
-                }
-                iter++;
+        if( space >= n )
+        {
+            MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
+            out->used += n;
+            return len;
+        }
+        if( space > 0 )
+            MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
+        out->used += n;
+    }
+    return -1;
+}
+
+static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
+{
+    int i, r = 0;
+
+    if( ( !left &&  flags->LeftAlign ) || 
+        (  left && !flags->LeftAlign ) ||
+        (  left &&  flags->PadZero   ) )
+    {
+        for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
+        {
+            if( flags->PadZero )
+                r = pf_output_stringA( out, "0", 1 );
+            else
+                r = pf_output_stringA( out, " ", 1 );
+        }
+    }
+
+    return r;
+}
+
+static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
+                                      int len, pf_flags *flags )
+{
+    int r = 0;
+
+    if( len < 0 )
+        len = strlenW( str );
+
+    r = pf_fill( out, len, flags, 1 );
+
+    if( r>=0 )
+        r = pf_output_stringW( out, str, len );
+
+    if( r>=0 )
+        r = pf_fill( out, len, flags, 0 );
+
+    return r;
+}
+
+static inline int pf_output_format_A( pf_output *out, LPCSTR str,
+                                      int len, pf_flags *flags )
+{
+    int r = 0;
+
+    if( len < 0 )
+        len = strlen( str );
+
+    r = pf_fill( out, len, flags, 1 );
+
+    if( r>=0 )
+        r = pf_output_stringA( out, str, len );
+
+    if( r>=0 )
+        r = pf_fill( out, len, flags, 0 );
+
+    return r;
+}
+
+static inline BOOL pf_is_double_format( char fmt )
+{
+    char float_fmts[] = "aefg";
+    if (!fmt)
+        return FALSE;
+    fmt = tolower( fmt );
+    return strchr( float_fmts, fmt ) ? TRUE : FALSE;
+}
+
+static inline BOOL pf_is_valid_format( char fmt )
+{
+    char float_fmts[] = "acdefginoux";
+    if (!fmt)
+        return FALSE;
+    fmt = tolower( fmt );
+    return strchr( float_fmts, fmt ) ? TRUE : FALSE;
+}
+
+static void pf_rebuild_format_string( char *p, pf_flags *flags )
+{
+    *p++ = '%';
+    if( flags->Sign )
+        *p++ = flags->Sign;
+    if( flags->LeftAlign )
+        *p++ = flags->LeftAlign;
+    if( flags->Alternate )
+        *p++ = flags->Alternate;
+    if( flags->PadZero )
+        *p++ = flags->PadZero;
+    if( flags->FieldLength )
+    {
+        sprintf(p, "%d", flags->FieldLength);
+        p += strlen(p);
+    }
+    if( flags->Precision )
+    {
+        sprintf(p, ".%d", flags->Precision);
+        p += strlen(p);
+    }
+    *p++ = flags->Format;
+    *p++ = 0;
+}
+
+/*********************************************************************
+ *  pf_vsnprintf  (INTERNAL)
+ *
+ *  implements both A and W vsnprintf functions
+ */
+static int pf_vsnprintf( pf_output *out, const WCHAR *format, va_list valist )
+{
+    int r;
+    LPCWSTR q, p = format;
+    pf_flags flags;
+
+    while (*p)
+    {
+        q = strchrW( p, '%' );
+
+        /* there's no % characters left, output the rest of the string */
+        if( !q )
+        {
+            r = pf_output_stringW(out, p, -1);
+            if( r<0 )
+                return r;
+            p += r;
+            continue;
+        }
+
+        /* there's characters before the %, output them */
+        if( q != p )
+        {
+            r = pf_output_stringW(out, p, q - p);
+            if( r<0 )
+                return r;
+            p = q;
+        }
+
+        /* we must be at a % now, skip over it */
+        assert( *p == '%' );
+        p++;
+
+        /* output a single % character */
+        if( *p == '%' )
+        {
+            r = pf_output_stringW(out, p, 1);
+            if( r<0 )
+                return r;
+            continue;
+        }
+
+        /* parse the flags */
+        memset( &flags, 0, sizeof flags );
+        while (*p)
+        {
+            if( *p == '+' || *p == ' ' )
+                flags.Sign = '+';
+            else if( *p == '-' )
+                flags.LeftAlign = *p;
+            else if( *p == '0' )
+                flags.PadZero = *p;
+            else if( *p == '#' )
+                flags.Alternate = *p;
+            else
                 break;
-            }
+            p++;
+        }
 
-            case 's':
+        /* deal with the field width specifier */
+        flags.FieldLength = 0;
+        if( *p == '*' )
+            flags.FieldLength = va_arg( valist, int );
+        else while( isdigit(*p) )
+        {
+            flags.FieldLength *= 10;
+            flags.FieldLength += *p++ - '0';
+        }
+
+        /* deal with precision */
+        if( *p == '.' )
+        {
+            p++;
+            if( *p == '*' )
+                flags.Precision = va_arg( valist, int );
+            else while( isdigit(*p) )
             {
-                static const WCHAR none[] = { '(','n','u','l','l',')',0 };
-                const WCHAR *wstr = va_arg(valist, const WCHAR *);
-                const WCHAR *striter = wstr ? wstr : none;
-                while (*striter)
-                {
-                    if (written++ >= len)
-                        return -1;
-                    *str++ = *striter++;
-                }
-                iter++;
-                break;
+                flags.Precision *= 10;
+                flags.Precision += *p++ - '0';
             }
+        }
 
-            case 'c':
-                if (written++ >= len)
-                    return -1;
-                *str++ = (WCHAR)va_arg(valist, int);
-                iter++;
-                break;
-
-            default:
+        /* deal with integer width modifier */
+        while( *p )
+        {
+            if( *p == 'h' || *p == 'l' || *p == 'L' )
             {
-                /* For non wc types, use system sprintf and append to wide char output */
-                /* FIXME: for unrecognised types, should ignore % when printing */
-                char *bufaiter = bufa;
-                if (*iter == 'p')
-                    sprintf(bufaiter, "%08lX", va_arg(valist, long));
+                if( flags.IntegerLength == *p )
+                    flags.IntegerDouble++;
                 else
-                {
-                    *fmta++ = *iter;
-                    *fmta = '\0';
-                    if (*iter == 'a' || *iter == 'A' ||
-                        *iter == 'e' || *iter == 'E' ||
-                        *iter == 'f' || *iter == 'F' || 
-                        *iter == 'g' || *iter == 'G')
-                        sprintf(bufaiter, fmtbufa, va_arg(valist, double));
-                    else
-                    {
-                        /* FIXME: On 32 bit systems this doesn't handle int 64's.
-                         *        on 64 bit systems this doesn't work for 32 bit types
-			 */
-                        sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
-                    }
-                }
-                while (*bufaiter)
-                {
-                    if (written++ >= len)
-                        return -1;
-                    *str++ = *bufaiter++;
-                }
-                iter++;
-                break;
-            }
+                    flags.IntegerLength = *p;
+                p++;
             }
+            else if( *p == 'w' )
+                flags.WideString = *p++;
+            else
+                break;
+        }
+
+        flags.Format = *p;
+        r = 0;
+
+        /* output a unicode string */
+        if( ( flags.Format == 's' && flags.WideString ) ||
+            ( !out->unicode && flags.Format == 'S' ) ||
+            ( out->unicode && flags.Format == 's' ) )
+        {
+            LPCWSTR str = va_arg( valist, const WCHAR * );
+
+            if( str )
+                r = pf_output_format_W( out, str, -1, &flags );
+            else
+                r = pf_output_format_A( out, "(null)", -1, &flags );
+        }
+
+        /* output a ASCII string */
+        else if( ( flags.Format == 's' && flags.IntegerLength == 'h' ) ||
+            ( out->unicode && flags.Format == 'S' ) ||
+            ( !out->unicode && flags.Format == 's' ) )
+        {
+            LPCSTR str = va_arg( valist, const CHAR * );
+
+            if( str )
+                r = pf_output_format_A( out, str, -1, &flags );
+            else
+                r = pf_output_format_A( out, "(null)", -1, &flags );
+        }
+
+        /* output a single wide character */
+        else if( ( flags.Format == 'c' && flags.IntegerLength == 'w' ) ||
+            ( out->unicode && flags.Format == 'c' ) ||
+            ( !out->unicode && flags.Format == 'C' ) )
+        {
+            WCHAR ch = va_arg( valist, int );
+
+            r = pf_output_format_W( out, &ch, 1, &flags );
+        }
+
+        /* output a single ascii character */
+        else if( ( flags.Format == 'c' && flags.IntegerLength == 'h' ) ||
+            ( out->unicode && flags.Format == 'C' ) ||
+            ( !out->unicode && flags.Format == 'c' ) )
+        {
+            CHAR ch = va_arg( valist, int );
+
+            r = pf_output_format_A( out, &ch, 1, &flags );
+        }
+
+        /* output a pointer */
+        else if( flags.Format == 'p' )
+        {
+            char pointer[10];
+
+            flags.PadZero = 0;
+            if( flags.Alternate )
+                sprintf(pointer, "0X%08lX", va_arg(valist, long));
+            else
+                sprintf(pointer, "%08lX", va_arg(valist, long));
+            r = pf_output_format_A( out, pointer, -1, &flags );
+        }
+
+        /* deal with %n */
+        else if( flags.Format == 'n' )
+        {
+            int *x = va_arg(valist, int *);
+            *x = out->used;
         }
+
+        /* deal with integers and floats using libc's printf */
+        else if( pf_is_valid_format( flags.Format ) )
+        {
+            char fmt[20], number[40], *x = number;
+
+            if( flags.FieldLength >= sizeof number )
+                x = HeapAlloc( GetProcessHeap(), 0, flags.FieldLength+1 );
+
+            pf_rebuild_format_string( fmt, &flags );
+
+            if( pf_is_double_format( flags.Format ) )
+                sprintf( number, fmt, va_arg(valist, double) );
+            else
+                sprintf( number, fmt, va_arg(valist, int) );
+
+            r = pf_output_stringA( out, number, -1 );
+            if( x != number )
+                HeapFree( GetProcessHeap(), 0, number );
+        }
+        else
+            continue;
+
+        if( r<0 )
+            return r;
+        p++;
     }
-    if (written >= len)
-        return -1;
-    *str++ = 0;
-    return (int)written;
+
+    /* check we reached the end, and null terminate the string */
+    assert( *p == 0 );
+    r = pf_output_stringW( out, p, 1 );
+    if( r<0 )
+        return r;
+
+    return out->used - 1;
 }
 
 /*********************************************************************
- *		swprintf (MSVCRT.@)
+ *		_vsnprintf (MSVCRT.@)
  */
-int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
+int MSVCRT_vsnprintf( char *str, unsigned int len,
+                const char *format, va_list valist )
+{
+    DWORD sz;
+    LPWSTR formatW = NULL;
+    pf_output out;
+    int r;
+
+    out.unicode = FALSE;
+    out.buf.A = str;
+    out.used = 0;
+    out.len = len;
+
+    if( format )
+    {
+        sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
+        formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
+        MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
+    }
+
+    r = pf_vsnprintf( &out, formatW, valist );
+
+    HeapFree( GetProcessHeap(), 0, formatW );
+
+    return r;
+}
+
+/*********************************************************************
+ *		_vsnwsprintf (MSVCRT.@)
+ */
+int MSVCRT_vsnwprintf( MSVCRT_wchar_t *str, unsigned int len,
+                              const WCHAR *format, va_list valist )
+{
+    pf_output out;
+
+    out.unicode = TRUE;
+    out.buf.W = str;
+    out.used = 0;
+    out.len = len;
+
+    return pf_vsnprintf( &out, format, valist );
+}
+
+/*********************************************************************
+ *		sprintf (MSVCRT.@)
+ */
+int MSVCRT_sprintf( char *str, const char *format, ... )
 {
     va_list ap;
     int r;
 
     va_start( ap, format );
-    r = MSVCRT_vsnprintfW( str, INT_MAX, format, ap );
+    r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
     va_end( ap );
     return r;
 }
 
 /*********************************************************************
- *		_vsnwprintf (MSVCRT.@)
+ *		swprintf (MSVCRT.@)
  */
-int _vsnwprintf(MSVCRT_wchar_t *str, unsigned int len,
-                const MSVCRT_wchar_t *format, va_list valist)
+int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
 {
-    return MSVCRT_vsnprintfW(str, len, format, valist);
+    va_list ap;
+    int r;
+
+    va_start( ap, format );
+    r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
+    va_end( ap );
+    return r;
 }
 
 /*********************************************************************
@@ -363,7 +670,7 @@ int _vsnwprintf(MSVCRT_wchar_t *str, uns
  */
 int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
 {
-    return MSVCRT_vsnprintfW( str, INT_MAX, format, args );
+    return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
 }
 
 /*********************************************************************
Index: dlls/msvcrt/tests/printf.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/tests/printf.c,v
retrieving revision 1.2
diff -u -p -r1.2 printf.c
--- dlls/msvcrt/tests/printf.c	28 Nov 2004 15:01:50 -0000	1.2
+++ dlls/msvcrt/tests/printf.c	12 Feb 2005 14:10:07 -0000
@@ -3,6 +3,7 @@
  *
  * Copyright 2002 Uwe Bonnes
  * Copyright 2004 Aneurin Price
+ * Copyright 2005 Mike McCormack
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,54 +27,213 @@
 static void test_sprintf( void )
 {
     char buffer[100];
-    const char *I64d = "%I64d";
-    const char *O4c = "%04c";
-    const char *O4s = "%04s";
-    const char *hash012p = "%#012p";
+    const char *format;
     double pnumber=789456123;
-/**    WCHAR widestring[]={'w','i','d','e','s','t','r','i','n','g',0};**/
-    sprintf(buffer,"%+#23.15e",pnumber);
-    todo_wine
-      {
-        ok(strstr(buffer,"e+008") != 0,"Sprintf different \"%s\"\n",buffer);
-      }
-    sprintf(buffer,I64d,((ULONGLONG)0xffffffff)*0xffffffff);
-    todo_wine
-      {
-        ok(strlen(buffer) == 11,"Problem with long long \"%s\"\n",buffer);
-      }
-    sprintf(buffer,"%lld",((ULONGLONG)0xffffffff)*0xffffffff);
-    todo_wine
-      {
-        ok(strlen(buffer) == 1,"Problem with \"ll\" interpretation \"%s\"\n",buffer);
-      }
-/** This one actually crashes WINE at the moment, when using builtin msvcrt.dll.
-    sprintf(buffer,"%S",widestring);
-    todo_wine
-      {
-        ok(strlen(buffer) == 10,"Problem with \"%%S\" interpretation \"%s\"\n",buffer);
-      }
- **/
-    sprintf(buffer,O4c,'1');
-    todo_wine
-      {
-        ok(!strcmp(buffer,"0001"),"Character not zero-prefixed \"%s\"\n",buffer);
-      }
-    sprintf(buffer,"%p",(void *)57);
-    todo_wine
-      {
-        ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer);
-      }
-    sprintf(buffer,hash012p,(void *)57);
-    todo_wine
-      {
-        ok(!strcmp(buffer,"  0X00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer);
-      }
-    sprintf(buffer,O4s,"foo");/**Warning again**/
-    todo_wine
-      {
-        ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer);
-      }
+    int x, r;
+    WCHAR wide[] = { 'w','i','d','e',0};
+
+    format = "%+#23.15e";
+    r = sprintf(buffer,format,pnumber);
+    todo_wine {
+    ok(!strcmp(buffer,"+7.894561230000000e+008"),"exponent format incorrect\n");
+    }
+    ok( r==23, "return count wrong\n");
+
+    todo_wine {
+    format = "%I64d";
+    r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff);
+    ok(!strcmp(buffer,"-8589934591"),"Problem with long long\n");
+    ok( r==11, "return count wrong\n");
+    }
+
+    format = "%lld";
+    r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff);
+    ok(!strcmp(buffer, "1"), "Problem with \"ll\" interpretation\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "%S";
+    r = sprintf(buffer,format,wide);
+    ok(!strcmp(buffer,"wide"),"Problem with wide string format\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%04c";
+    r = sprintf(buffer,format,'1');
+    ok(!strcmp(buffer,"0001"),"Character not zero-prefixed \"%s\"\n",buffer);
+    ok( r==4, "return count wrong\n");
+
+    format = "%p";
+    r = sprintf(buffer,format,(void *)57);
+    ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer);
+    ok( r==8, "return count wrong\n");
+
+    format = "%#012p";
+    r = sprintf(buffer,format,(void *)57);
+    ok(!strcmp(buffer,"  0X00000039"),"Pointer formatted incorrectly\n");
+    ok( r==12, "return count wrong\n");
+
+    format = "%04s";
+    r = sprintf(buffer,format,"foo");
+    ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer);
+    ok( r==4, "return count wrong\n");
+
+    format = "%#-012p";
+    r = sprintf(buffer,format,(void *)57);
+    ok(!strcmp(buffer,"0X00000039  "),"Pointer formatted incorrectly\n");
+    ok( r==12, "return count wrong\n");
+
+    format = "hello";
+    r = sprintf(buffer, format);
+    ok(!strcmp(buffer,"hello"), "failed\n");
+    ok( r==5, "return count wrong\n");
+
+    format = "%ws";
+    r = sprintf(buffer, format, wide);
+    ok(!strcmp(buffer,"wide"), "failed\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%-10ws";
+    r = sprintf(buffer, format, wide );
+    ok(!strcmp(buffer,"wide      "), "failed\n");
+    ok( r==10, "return count wrong\n");
+
+    format = "%10ws";
+    r = sprintf(buffer, format, wide );
+    ok(!strcmp(buffer,"      wide"), "failed\n");
+    ok( r==10, "return count wrong\n");
+
+    format = "%#+ -03whlls";
+    r = sprintf(buffer, format, wide );
+    ok(!strcmp(buffer,"wide"), "failed\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%w0s";
+    r = sprintf(buffer, format, wide );
+    ok(!strcmp(buffer,"0s"), "failed\n");
+    ok( r==2, "return count wrong\n");
+
+    format = "%w-s";
+    r = sprintf(buffer, format, wide );
+    ok(!strcmp(buffer,"-s"), "failed\n");
+    ok( r==2, "return count wrong\n");
+
+    format = "%b";
+    r = sprintf(buffer, format);
+    ok(!strcmp(buffer,"b"), "failed\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "%3c";
+    r = sprintf(buffer, format,'a');
+    ok(!strcmp(buffer,"  a"), "failed\n");
+    ok( r==3, "return count wrong\n");
+
+    format = "%3d";
+    r = sprintf(buffer, format,1234);
+    ok(!strcmp(buffer,"1234"), "failed\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%3h";
+    r = sprintf(buffer, format);
+    ok(!strcmp(buffer,""), "failed\n");
+    ok( r==0, "return count wrong\n");
+
+    format = "%j%k%m%q%r%t%v%y%z";
+    r = sprintf(buffer, format);
+    ok(!strcmp(buffer,"jkmqrtvyz"), "failed\n");
+    ok( r==9, "return count wrong\n");
+
+    format = "asdf%n";
+    x = 0;
+    r = sprintf(buffer, format, &x );
+    ok(x == 4, "should write to x\n");
+    ok(!strcmp(buffer,"asdf"), "failed\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%-1d";
+    r = sprintf(buffer, format,2);
+    ok(!strcmp(buffer,"2"), "failed\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "%2.4f";
+    r = sprintf(buffer, format,8.6);
+    ok(!strcmp(buffer,"8.6000"), "failed\n");
+    ok( r==6, "return count wrong\n");
+
+    todo_wine {
+    format = "%2.4e";
+    r = sprintf(buffer, format,8.6);
+    ok(!strcmp(buffer,"8.6000e+000"), "failed\n");
+    ok( r==11, "return count wrong\n");
+    }
+
+    format = "%2.4g";
+    r = sprintf(buffer, format,8.6);
+    ok(!strcmp(buffer,"8.6"), "failed\n");
+    ok( r==3, "return count wrong\n");
+
+    format = "%-i";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,"-1"), "failed\n");
+    ok( r==2, "return count wrong\n");
+
+    format = "%-i";
+    r = sprintf(buffer, format,1);
+    ok(!strcmp(buffer,"1"), "failed\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "%+i";
+    r = sprintf(buffer, format,1);
+    ok(!strcmp(buffer,"+1"), "failed\n");
+    ok( r==2, "return count wrong\n");
+
+    format = "%o";
+    r = sprintf(buffer, format,10);
+    ok(!strcmp(buffer,"12"), "failed\n");
+    ok( r==2, "return count wrong\n");
+
+    format = "%p";
+    r = sprintf(buffer, format,0);
+    ok(!strcmp(buffer,"00000000"), "failed\n");
+    ok( r==8, "return count wrong\n");
+
+    format = "%s";
+    r = sprintf(buffer, format,0);
+    ok(!strcmp(buffer,"(null)"), "failed\n");
+    ok( r==6, "return count wrong\n");
+
+    format = "%s";
+    r = sprintf(buffer, format,"%%%%");
+    ok(!strcmp(buffer,"%%%%"), "failed\n");
+    ok( r==4, "return count wrong\n");
+
+    format = "%u";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,"4294967295"), "failed\n");
+    ok( r==10, "return count wrong\n");
+
+    format = "%w";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,""), "failed\n");
+    ok( r==0, "return count wrong\n");
+
+    format = "%h";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,""), "failed\n");
+    ok( r==0, "return count wrong\n");
+
+    format = "%z";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,"z"), "failed\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "%j";
+    r = sprintf(buffer, format,-1);
+    ok(!strcmp(buffer,"j"), "failed\n");
+    ok( r==1, "return count wrong\n");
+
+    format = "x%cx";
+    r = sprintf(buffer, format, 0x100+'X');
+    ok(!strcmp(buffer,"xXx"), "failed\n");
+    ok( r==3, "return count wrong\n");
 }
 
 static void test_swprintf( void )


More information about the wine-patches mailing list