Resend: Re-implement MSVCRT *printf functions

Aneurin Price wine at shadovald.dyndns.org
Fri Nov 5 16:07:00 CST 2004


Hopefully this patch might now be considered for inclusion. Let me know 
if there's still anything wrong with it.
Also included is a patch to the recently committed tests, to remove 
wine_todo statements where appropriate, and uncomment the test that 
caused Wine to crash, since it doesn't with this patch.

Summary:
msvcrt.dll currently uses native printf functions, with some munging 
within WINE to approximate differences in how they should work in 
Windows. This caused some problems in situations not supported by glibcs 
*printf, for example, bugs 321[0] and 2075[1]. This patch re-implements 
these functions such that they are more compatible with Windows' versions.

As before, some observations:

- When using "printf("%f",number)", where number is NaN, behaviour with 
the native dll seems a bit odd. The specification[2] states that the 
output should be "digit.#NANrandom-digits", whereas in actuality it 
outputs (for me) "1.#QNAN00", also it mentions "Indefinite (same as 
quiet NaN) digit.#INDrandom-digits", which I've simply not implemented 
as I have no idea when this would happen.

- When using "wprintf("some non-unicode string"), native wprintf detects 
that the string is non-unicode and does nothing, returning -1 - however 
I couldn't think of how to do this, so it attempts to print anyway (the 
current code also has this problem).

- There may be some other things I've not noticed, or of course some 
bugs I didn't manage to shake out :) .

- The patch is quite large but I don't see any way of breaking it down 
into smaller parts.

Aneurin Price.

[0]http://bugs.winehq.org/show_bug.cgi?id=321
[1]http://bugs.winehq.org/show_bug.cgi?id=2075
[2]http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_precision_specification.asp

Changelog:
Re-implement all *printf functions in msvcrt.dll, according to 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_format_specification_fields_.2d_.printf_and_wprintf_functions.asp
and descriptions of appropriate functions.

Modified Files:
dlls/msvcrt/Makefile.in
dlls/msvcrt/file.c
dlls/msvcrt/msvcrt.spec
dlls/msvcrt/wcs.c

Added Files:
dlls/msvcrt/printf.c
dlls/msvcrt/printfhelpers.c


-------------- next part --------------
? dlls/msvcrt/printf.c
? dlls/msvcrt/printfhelpers.c
Index: dlls/msvcrt/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/Makefile.in,v
retrieving revision 1.16
diff -u -u -r1.16 Makefile.in
--- dlls/msvcrt/Makefile.in	25 Jun 2004 01:19:15 -0000	1.16
+++ dlls/msvcrt/Makefile.in	5 Nov 2004 21:24:01 -0000
@@ -27,6 +27,7 @@
 	math.c \
 	mbcs.c \
 	misc.c \
+	printf.c \
 	process.c \
 	scanf.c \
 	string.c \
Index: dlls/msvcrt/file.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/file.c,v
retrieving revision 1.73
diff -u -u -r1.73 file.c
--- dlls/msvcrt/file.c	3 Nov 2004 22:17:05 -0000	1.73
+++ dlls/msvcrt/file.c	5 Nov 2004 21:24:12 -0000
@@ -2614,113 +2614,6 @@
   return file;
 }
 
-/*********************************************************************
- *		vfprintf (MSVCRT.@)
- */
-int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
-{
-  char buf[2048], *mem = buf;
-  int written, resize = sizeof(buf), retval;
-  /* There are two conventions for vsnprintf failing:
-   * Return -1 if we truncated, or
-   * Return the number of bytes that would have been written
-   * The code below handles both cases
-   */
-  while ((written = vsnprintf(mem, resize, format, valist)) == -1 ||
-          written > resize)
-  {
-    resize = (written == -1 ? resize * 2 : written + 1);
-    if (mem != buf)
-      MSVCRT_free (mem);
-    if (!(mem = (char *)MSVCRT_malloc(resize)))
-      return MSVCRT_EOF;
-  }
-  retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
-  if (mem != buf)
-    MSVCRT_free (mem);
-  return retval;
-}
-
-/*********************************************************************
- *		vfwprintf (MSVCRT.@)
- * FIXME:
- * Is final char included in written (then resize is too big) or not
- * (then we must test for equality too)?
- */
-int MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, va_list valist)
-{
-  MSVCRT_wchar_t buf[2048], *mem = buf;
-  int written, resize = sizeof(buf) / sizeof(MSVCRT_wchar_t), retval;
-  /* See vfprintf comments */
-  while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
-          written > resize)
-  {
-    resize = (written == -1 ? resize * 2 : written + sizeof(MSVCRT_wchar_t));
-    if (mem != buf)
-      MSVCRT_free (mem);
-    if (!(mem = (MSVCRT_wchar_t *)MSVCRT_malloc(resize*sizeof(*mem))))
-      return MSVCRT_EOF;
-  }
-  retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
-  if (mem != buf)
-    MSVCRT_free (mem);
-  return retval;
-}
-
-/*********************************************************************
- *		vprintf (MSVCRT.@)
- */
-int MSVCRT_vprintf(const char *format, va_list valist)
-{
-  return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
-}
-
-/*********************************************************************
- *		vwprintf (MSVCRT.@)
- */
-int MSVCRT_vwprintf(const MSVCRT_wchar_t *format, va_list valist)
-{
-  return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
-}
-
-/*********************************************************************
- *		fprintf (MSVCRT.@)
- */
-int MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = MSVCRT_vfprintf(file, format, valist);
-    va_end(valist);
-    return res;
-}
-
-/*********************************************************************
- *		fwprintf (MSVCRT.@)
- */
-int MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = MSVCRT_vfwprintf(file, format, valist);
-    va_end(valist);
-    return res;
-}
-
-/*********************************************************************
- *		printf (MSVCRT.@)
- */
-int MSVCRT_printf(const char *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
-    va_end(valist);
-    return res;
-}
 
 /*********************************************************************
  *		ungetc (MSVCRT.@)
@@ -2753,17 +2646,4 @@
 			return MSVCRT_WEOF;
 	}
 	return mwc;
-}
-
-/*********************************************************************
- *		wprintf (MSVCRT.@)
- */
-int MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = MSVCRT_vwprintf(format, valist);
-    va_end(valist);
-    return res;
 }
Index: dlls/msvcrt/msvcrt.spec
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/msvcrt.spec,v
retrieving revision 1.93
diff -u -u -r1.93 msvcrt.spec
--- dlls/msvcrt/msvcrt.spec	14 Oct 2004 00:26:39 -0000	1.93
+++ dlls/msvcrt/msvcrt.spec	5 Nov 2004 21:24:16 -0000
@@ -433,8 +433,8 @@
 @ cdecl _setmode(long long)
 @ stub _setsystime #(ptr long)
 @ cdecl _sleep(long)
-@ varargs _snprintf(str long str) snprintf
-@ varargs _snwprintf(wstr long wstr) ntdll._snwprintf
+@ varargs _snprintf(str long str)
+@ varargs _snwprintf(wstr long wstr)
 @ varargs _sopen(str long long) MSVCRT__sopen
 @ varargs _spawnl(long str str)
 @ varargs _spawnle(long str str)
@@ -484,7 +484,7 @@
 @ cdecl _unloaddll(long)
 @ cdecl _unlock(long)
 @ cdecl _utime(str ptr)
-@ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf
+@ cdecl _vsnprintf(ptr long ptr ptr)
 @ cdecl _vsnwprintf(ptr long wstr long)
 @ cdecl _waccess(wstr long)
 @ stub _wasctime #(ptr) MSVCRT__wasctime
@@ -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
@@ -735,7 +735,7 @@
 @ cdecl vfprintf(ptr str long) MSVCRT_vfprintf
 @ cdecl vfwprintf(ptr wstr long) MSVCRT_vfwprintf
 @ cdecl vprintf(str long) MSVCRT_vprintf
-@ cdecl vsprintf(ptr str ptr)
+@ cdecl vsprintf(ptr str ptr) MSVCRT_vsprintf
 @ cdecl vswprintf(ptr wstr long) MSVCRT_vswprintf
 @ cdecl vwprintf(wstr long) MSVCRT_vwprintf
 @ cdecl wcscat(wstr wstr) ntdll.wcscat
Index: dlls/msvcrt/wcs.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/wcs.c,v
retrieving revision 1.18
diff -u -u -r1.18 wcs.c
--- dlls/msvcrt/wcs.c	25 Jun 2004 01:19:15 -0000	1.18
+++ dlls/msvcrt/wcs.c	5 Nov 2004 21:24:17 -0000
@@ -178,194 +178,6 @@
   return ret;
 }
 
-static int MSVCRT_vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
-{
-    unsigned int written = 0;
-    const WCHAR *iter = format;
-    char bufa[256], fmtbufa[64], *fmta;
-
-    while (*iter)
-    {
-        while (*iter && *iter != '%')
-        {
-            if (written++ >= len)
-                return -1;
-            *str++ = *iter++;
-        }
-        if (*iter == '%')
-        {
-            if (iter[1] == '%')
-            {
-                if (written++ >= len)
-                    return -1;
-                *str++ = '%'; /* "%%"->'%' */
-                iter += 2;
-                continue;
-            }
-
-            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++;
-            }
-
-            while (isdigit(*iter))
-                *fmta++ = *iter++;
-
-            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++;
-
-            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++;
-                break;
-            }
-
-            case 's':
-            {
-                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;
-            }
-
-            case 'c':
-                if (written++ >= len)
-                    return -1;
-                *str++ = (WCHAR)va_arg(valist, int);
-                iter++;
-                break;
-
-            default:
-            {
-                /* 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));
-                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;
-            }
-            }
-        }
-    }
-    if (written >= len)
-        return -1;
-    *str++ = 0;
-    return (int)written;
-}
-
-/*********************************************************************
- *		swprintf (MSVCRT.@)
- */
-int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
-{
-    va_list ap;
-    int r;
-
-    va_start( ap, format );
-    r = MSVCRT_vsnprintfW( str, INT_MAX, format, ap );
-    va_end( ap );
-    return r;
-}
-
-/*********************************************************************
- *		_vsnwprintf (MSVCRT.@)
- */
-int _vsnwprintf(MSVCRT_wchar_t *str, unsigned int len,
-                const MSVCRT_wchar_t *format, va_list valist)
-{
-    return MSVCRT_vsnprintfW(str, len, format, valist);
-}
-
-/*********************************************************************
- *		vswprintf (MSVCRT.@)
- */
-int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
-{
-    return MSVCRT_vsnprintfW( str, INT_MAX, format, args );
-}
-
 /*********************************************************************
  *		wcscoll (MSVCRT.@)
  */
--- /dev/null	2004-08-23 03:25:44.000000000 +0100
+++ dlls/msvcrt/printf.c	2004-11-05 21:11:48.000000000 +0000
@@ -0,0 +1,353 @@
+/*
+ * msvcrt.dll printf functions
+ *
+ * Copyright 2004 Aneurin Price
+ * Some sections derived from file.c. See that file for copyright information.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <limits.h>
+#include <wctype.h>
+#include <math.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "msvcrt.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+extern MSVCRT_FILE MSVCRT__iob[];
+extern MSVCRT_size_t MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file);
+WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
+
+#define WIDE_PRINTF 8192
+
+#include "printfhelpers.c"
+
+/*********************************************************************
+ *		_vsnprintf (MSVCRT.@)
+ */
+int _vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
+{
+    /**Since the meaning of type specifiers %S and %s (and C/c) invert
+     **depending on whether the function called is *wprintf or *printf,
+     **this doesn't simply convert to wide, call _vsnwprintf, and
+     **convert back; instead, they both call the same function with a
+     **flag to indicate the correct behaviour
+     **/
+    int done=0;
+    int prev=done;
+    int bufsize=count;
+    int skip;
+    MSVCRT_wchar_t *temp;
+    MSVCRT_wchar_t *input=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,(1+strlen(format))*sizeof(MSVCRT_wchar_t));
+    MSVCRT_wchar_t *in=input;
+    MSVCRT_wchar_t *output=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,count*sizeof(MSVCRT_wchar_t));
+    MSVCRT_wchar_t *out=output;
+    MultiByteToWideChar(CP_ACP, 0, format, -1, input, strlen(format));
+    while ((done<=count)&&(*input))
+    {
+        skip=0;
+        temp=strchrW(input,'%');
+        if (!temp || (temp-input)>bufsize)
+        {
+            skip+=processw(output, input, bufsize);
+            done+=skip;
+        }
+        else
+        {
+            processw(output, input, (temp-input));
+            skip+=(temp-input);
+            done+=skip;
+            done+=_formatw((output+skip), temp, (bufsize-skip), &argptr, &skip, done,0);
+        }
+        input+=skip;
+        output+=done-prev;
+        bufsize-=done-prev;
+        prev=done;
+    }
+    if (done>count)
+    /**No more can be written.**/
+    {
+        *(out+count)=0;
+        WideCharToMultiByte(CP_ACP, 0,out, -1, buffer, count+1, NULL, NULL);
+        HeapFree(GetProcessHeap(),0,out);
+        HeapFree(GetProcessHeap(),0,in);
+        return -1;
+    }
+    else
+    {
+        WideCharToMultiByte(CP_ACP, 0,out, -1, buffer, count+1, NULL, NULL);
+        HeapFree(GetProcessHeap(),0,out);
+        HeapFree(GetProcessHeap(),0,in);
+        return done;
+    }
+}
+
+/*********************************************************************
+ *		_vsnwprintf (MSVCRT.@)
+ */
+int _vsnwprintf(MSVCRT_wchar_t *buffer, size_t count, const MSVCRT_wchar_t *format, va_list argptr)
+{
+    int done=0;
+    int prev=done;
+    int bufsize=count;
+    int skip;
+    const MSVCRT_wchar_t *input=format;
+    MSVCRT_wchar_t *output=buffer;
+    MSVCRT_wchar_t *temp;
+    while ((done<=count)&&(*input))
+    {
+        skip=0;
+        temp=strchrW(input,'%');
+        if (!temp || (temp-input)>bufsize)
+        {
+            skip+=processw(output, input, bufsize);
+            done+=skip;
+        }
+        else
+        {
+            processw(output, input, (temp-input));
+            skip+=(temp-input);
+            done+=skip;
+            done+=_formatw((output+skip), temp, (bufsize-skip), &argptr, &skip, done,WIDE_PRINTF);
+        }
+        input+=skip;
+        output+=done-prev;
+        bufsize-=done-prev;
+        prev=done;
+    }
+    if (done>count)
+    /**No more can be written.**/
+    {
+        *(buffer+count)=0;
+        return -1;
+    }
+    else
+    {
+       *(buffer+done)=0;
+       return done;
+    }
+}
+
+
+/*********************************************************************
+ *		vfprintf (MSVCRT.@)
+ */
+int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
+{
+    char buf[2048], *mem = buf;
+    int written, resize = sizeof(buf)/sizeof(char), retval;
+    while ((written = _vsnprintf(mem, resize, format, valist)) == -1)
+    {
+        resize*=2;
+        if (mem != buf)
+            MSVCRT_free (mem);
+        if (!(mem = (char *)MSVCRT_malloc(resize*sizeof(char))))
+            return (-1);
+    }
+    retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
+    if (mem != buf)
+        MSVCRT_free (mem);
+    return retval;
+}
+
+/*********************************************************************
+ *		vfwprintf (MSVCRT.@)
+ */
+int MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, va_list valist)
+{
+    MSVCRT_wchar_t buf[2048], *mem = buf;
+    int written, resize = sizeof(buf)/sizeof(MSVCRT_wchar_t), retval;
+    while ((written = _vsnwprintf(mem, resize, format, valist)) == -1)
+    {
+        resize*=2;
+        if (mem != buf)
+            MSVCRT_free (mem);
+        if (!(mem = (MSVCRT_wchar_t *)MSVCRT_malloc(resize*sizeof(MSVCRT_wchar_t))))
+            return (-1);
+    }
+    retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
+    if (mem != buf)
+        MSVCRT_free (mem);
+    return retval;
+}
+
+/*********************************************************************
+ *		printf (MSVCRT.@)
+ */
+int MSVCRT_printf(const char *format, ...)
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		wprintf (MSVCRT.@)
+ */
+int MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vfwprintf(MSVCRT_stdout,format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		vprintf (MSVCRT.@)
+ */
+int MSVCRT_vprintf(const char *format, va_list valist)
+{
+    return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
+}
+
+/*********************************************************************
+ *		vwprintf (MSVCRT.@)
+ */
+int MSVCRT_vwprintf(const MSVCRT_wchar_t *format, va_list valist)
+{
+    return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
+}
+/*********************************************************************
+ *		fprintf (MSVCRT.@)
+ */
+int MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vfprintf(file, format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		fwprintf (MSVCRT.@)
+ */
+int MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vfwprintf(file, format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		vsprintf (MSVCRT.@)
+ */
+int MSVCRT_vsprintf( char* str, const char* format, va_list args )
+{
+    char buf[2048], *mem = buf;
+    int written, resize = sizeof(buf)/sizeof(char), retval;
+    while ((written = _vsnprintf(mem, resize, format, args)) == -1)
+    {
+        resize*=2;
+        if (mem != buf)
+            MSVCRT_free (mem);
+        if (!(mem = (char *)MSVCRT_malloc(resize*sizeof(char))))
+            return (-1);
+    }
+    strcpy(str, mem);
+    if (mem != buf)
+        MSVCRT_free (mem);
+    return written;
+}
+
+/*********************************************************************
+ *		vswprintf (MSVCRT.@)
+ */
+int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
+{
+    MSVCRT_wchar_t buf[2048], *mem = buf;
+    int written, resize = sizeof(buf)/sizeof(MSVCRT_wchar_t), retval;
+    while ((written = _vsnwprintf(mem, resize, format, args)) == -1)
+    {
+        resize*=2;
+        if (mem != buf)
+            MSVCRT_free (mem);
+        if (!(mem = (MSVCRT_wchar_t *)MSVCRT_malloc(resize*sizeof(MSVCRT_wchar_t))))
+            return (-1);
+    }
+    wcscpy(str, mem);
+    if (mem != buf)
+        MSVCRT_free (mem);
+    return written;}
+
+/*********************************************************************
+ *		sprintf (MSVCRT.@)
+ */
+int MSVCRT_sprintf(char *str, const char *format, ... )
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vsprintf(str, format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		swprintf (MSVCRT.@)
+ */
+int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = MSVCRT_vswprintf(str, format, valist);
+    va_end(valist);
+    return res;
+}
+
+/*********************************************************************
+ *		_snprintf (MSVCRT.@)
+ */
+int _snprintf(char *buffer, size_t count, const char *format, ... )
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = _vsnprintf(buffer, count, format, valist);
+    va_end(valist);
+    return res;    
+}
+
+/*********************************************************************
+ *		_snwprintf (MSVCRT.@)
+ */
+int _snwprintf(MSVCRT_wchar_t *buffer, size_t count, const MSVCRT_wchar_t *format, ... )
+{
+    va_list valist;
+    int res;
+    va_start(valist, format);
+    res = _vsnwprintf(buffer, count, format, valist);
+    va_end(valist);
+    return res;    
+}
--- /dev/null	2004-08-23 03:25:44.000000000 +0100
+++ dlls/msvcrt/printfhelpers.c	2004-11-05 21:31:23.000000000 +0000
@@ -0,0 +1,910 @@
+/*
+ * Functions used by msvcrt.dll printf functions
+ *
+ * Copyright 2004 Aneurin Price
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define LEFT_ALIGN 1
+#define SIGN_PREFIX 2
+#define ZERO_PAD 4
+#define BLANK_PAD 8
+#define ZERO_PREFIX 16
+#define LONG 32
+#define SHORT 64
+#define SIZE_T 128
+#define INT64 256
+#define INT32 512
+#define LONG_CHAR 1024
+#define SHORT_CHAR 2048
+#define PRECISION_COUNT 4096
+
+int integertostringw(__int64 in, MSVCRT_wchar_t *out, MSVCRT_wchar_t digits[], int base, int flags,int width,int precision, int length)
+{
+    MSVCRT_wchar_t *string=out;
+    MSVCRT_wchar_t *tempstring;
+    int charsdone=0;
+    int neg=0;
+    int inint=in;
+    short inh=in;
+    long inl=in;
+    __int64 num=inint;
+    ptrdiff_t inI=in;
+    __int32 inI32=in;
+    __int64 inI64=in;
+    tempstring=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+    *tempstring++=0;
+    if (flags&SHORT) /**Shorten input variable to the type specified**/
+        num=inh;
+    if (flags&LONG)
+        num=inl;
+    if (flags&SIZE_T)
+        num=inI;
+    if (flags&INT32)
+        num=inI32;
+    if (flags&INT64) /**which can't be longer than 64 bits**/
+        num=inI64;
+    if (num<0)
+    {
+        num=-num;
+        neg=1;
+        flags &=~SIGN_PREFIX;
+        flags &=~BLANK_PAD;
+    }
+    
+    if ((!num)&&(precision==-1)) /**Input zero, precision unspecified, just write 0**/
+    {
+        *tempstring++=digits[0];
+        charsdone++;
+    }
+    
+    while (num)
+    {
+        *tempstring++=digits[(num%base)]; /**Find each digit (starting at the little end)**/
+        num/=base;                        /**tempstring then points to the output string, backwards**/
+        charsdone++;                      /**Ie. it's used as a stack from which chars are popped  **/
+    }                                     /**and pushed on to the output.                          **/
+    
+    while (charsdone<precision) /**If precision is higher than already written, pad the end with 0s**/
+    {
+        *tempstring++=digits[0];
+        charsdone++;
+    }
+    
+    if ((precision!=-1)&&(width>precision)) (flags&=~ZERO_PAD); /**If there is a precision specified, and it is less**/
+                                                                /**than the specified width, don't use 0s to pad    **/
+    if (flags&LEFT_ALIGN)
+    {
+        if (neg) {*string++='-'; charsdone++;}
+        if (flags&SIGN_PREFIX) {*string++='+'; charsdone++;}
+        if (flags&BLANK_PAD) {*string++=' '; charsdone++;}
+        while (*--tempstring)
+        {
+             *string++=*tempstring;
+        }
+        while (charsdone<width)
+        {
+            *string++=' ';
+            charsdone++;
+        }
+    }
+    else
+    {
+        if (flags&ZERO_PAD) /**Pad width with 0s**/
+        {
+            if (neg) {*string++='-'; charsdone++;} /**Sign should be before 0s, so add it to string**/
+            if (flags&SIGN_PREFIX) {*string++='+'; charsdone++;}
+            if (flags&BLANK_PAD) {*string++=' '; charsdone++;}
+            while (charsdone<width)
+            {
+                *string++='0';
+                charsdone++;
+            }
+        }
+        else /**Pad width with spaces**/
+        {
+            if (neg) {*tempstring++='-'; charsdone++;} /**Sign should be after spaces, so add it to**/
+            if (flags&SIGN_PREFIX) {*tempstring++='+'; charsdone++;}/**tempstring, which will be   **/
+            if (flags&BLANK_PAD) {*tempstring++=' '; charsdone++;}  /**copied backwards to string  **/
+            while (charsdone<width)
+            {
+                *string++=' ';
+                charsdone++;
+            }
+        }
+        while (*--tempstring)
+        {
+            *string++=*tempstring;
+        }
+    }
+    
+    HeapFree(GetProcessHeap(),0,tempstring);
+    return strlenW(out);
+}
+
+int uintegertostringw(unsigned __int64 in, MSVCRT_wchar_t *out, MSVCRT_wchar_t digits[], int base, int flags,int width,int precision,int length)
+{
+MSVCRT_wchar_t *string=out;
+MSVCRT_wchar_t *tempstring;
+int charsdone=0;
+unsigned int inint=in;
+unsigned short inh=in;
+unsigned long inl=in;
+size_t inI=in;
+unsigned __int32 inI32=in;
+unsigned __int64 inI64=in;
+unsigned __int64 num=inint;
+tempstring=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+*tempstring++=0;
+if (flags&SHORT) /**Shorten input variable to the type specified**/
+    num=inh;
+if (flags&LONG)
+    num=inl;
+if (flags&SIZE_T)
+    num=inI;
+if (flags&INT32)
+    num=inI32;
+if (flags&INT64) /**which can't be longer than 64 bits**/
+    num=inI64;
+
+if ((!num)&&(precision==-1))
+{
+    *tempstring++=digits[0];
+    charsdone++;
+}
+
+while (num)
+{
+    *tempstring++=digits[(num%base)];
+    num/=base;
+    charsdone++;
+}
+
+while (charsdone<precision)
+{
+    *tempstring++=digits[0];
+    charsdone++;
+}
+
+if ((precision!=-1)&&(width>precision)) (flags&=~ZERO_PAD); /**If there is a precision specified, and it is less**/
+                                                            /**than the specified width, don't use 0s to pad    **/
+if (flags&LEFT_ALIGN)
+{
+    if ((base==16)&&(flags&ZERO_PREFIX)) {*string++=digits[0];*string++=digits[16];charsdone+=2;}
+    if ((base==8)&&(flags&ZERO_PREFIX)) {*string++=digits[0]; charsdone++;}
+    while (*--tempstring)
+    {
+         *string++=*tempstring;
+    }
+    while (charsdone<width)
+    {
+        *string++=' ';
+        charsdone++;
+    }
+}
+else
+{
+    if (flags&ZERO_PAD)
+    {
+        if ((base==16)&&(flags&ZERO_PREFIX)) {*string++=digits[0];*string++=digits[16];charsdone+=2;}
+        if ((base==8)&&(flags&ZERO_PREFIX)) {*string++=digits[0]; charsdone++;}
+        while (charsdone<width)
+        {
+            *string++='0';
+            charsdone++;
+        }
+    }
+    else
+    {
+        if ((base==16)&&(flags&ZERO_PREFIX)) {*tempstring++=digits[16];*tempstring++=digits[0];charsdone+=2;}
+        if ((base==8)&&(flags&ZERO_PREFIX)) {*tempstring++=digits[0]; charsdone++;}
+        while (charsdone<width)
+        {
+            *string++=' ';
+            charsdone++;
+        }
+    }
+    while (*--tempstring)
+    {
+         *string++=*tempstring;
+    }
+}
+
+HeapFree(GetProcessHeap(),0,tempstring);
+return strlenW(out);
+}
+
+int floattostringw(double in, MSVCRT_wchar_t *out, MSVCRT_wchar_t digits[], int flags,int width,int precision,int length)
+{
+MSVCRT_wchar_t *string=out;
+MSVCRT_wchar_t *tempstring;
+MSVCRT_wchar_t *tempstringstart;
+double temp;
+int prec;
+int charsdone=0;
+int neg=0;
+int infOrNaN=0;
+tempstring=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+tempstringstart=tempstring;
+*tempstring++=0;
+
+if (in<0)
+{
+    in=-in;
+    neg=1;
+    flags&=~SIGN_PREFIX;
+    flags&=~BLANK_PAD;
+}
+
+if (isinf(in))
+{
+    infOrNaN=1;
+    in=1.0;
+}
+
+if (isnan(in))
+{
+    infOrNaN=2;
+    in=1.0;
+}
+
+temp=in-floor(in);
+prec=precision;
+
+while (prec)
+{
+    temp*=10;
+    prec--;
+}
+temp+=0.5;
+while (floor(temp))
+{
+    *tempstring++=digits[(int)fmod(temp,10)];
+    temp/=10;
+    charsdone++;
+}
+
+if ((flags&PRECISION_COUNT)&&charsdone) /**Count trailing zeros, so the precision**/
+{                                       /**can be reduced by this amount when    **/
+    tempstring-=charsdone;              /**called to deal with %[gG] (which      **/
+    charsdone=0;                        /**does not display trailing zeroes).    **/
+    while (*tempstring++=='0') charsdone++;
+    HeapFree(GetProcessHeap(),0,tempstringstart);
+    return charsdone;
+}
+
+while (charsdone<precision) /**If the decimal point is not followed by a digit 1-9,**/
+{
+    *tempstring++=digits[0]; /**fill in leading zeroes**/
+    charsdone++;
+}
+
+if (flags&PRECISION_COUNT)                        /**If there were no non-zero characters, **/
+                                                  /**count trailing zeros, so the precision**/
+{                                                 /**can be reduced by this amount when    **/
+    HeapFree(GetProcessHeap(),0,tempstringstart); /**called to deal with %[gG] (which      **/
+    return charsdone;                             /**does not display trailing zeroes).    **/
+}
+
+if (infOrNaN==2)
+{
+    if (precision>=4) *(tempstring-4)='N';/**FIXME:Is this actually the right string? MSDN  **/
+    if (precision>=3) *(tempstring-3)='A';/**says yes, but native msvcrt.dll seems to output**/
+    if (precision>=2) *(tempstring-2)='N';/**QNAN, for some reason. Also, when precision is **/
+    if (precision>=1) *(tempstring-1)='#';/**such that it is truncated, the final character **/
+}                                         /**outputted is incremented by one. I've ignored  **/
+                                          /**all this for the moment.                       **/
+if (infOrNaN==1)
+{
+    if (precision>=4) *(tempstring-4)='F';
+    if (precision>=3) *(tempstring-3)='N';
+    if (precision>=2) *(tempstring-2)='I';
+    if (precision>=1) *(tempstring-1)='#';
+}
+
+if (precision||(flags&ZERO_PREFIX)) {*tempstring++='.'; charsdone++;}
+
+in=floor(in);
+
+if (!in)
+{
+    *tempstring++=digits[0];
+    charsdone++;
+}
+
+while (floor(in))
+{
+    *tempstring++=digits[(int)fmod(in,10)];
+    in/=10;
+    charsdone++;
+}
+
+if (flags&LEFT_ALIGN)
+{
+    if (neg) {*string++='-'; charsdone++;}
+    if (flags&SIGN_PREFIX) {*string++='+'; charsdone++;}
+    if (flags&BLANK_PAD) {*string++=' '; charsdone++;}
+    while (*--tempstring)
+    {
+         *string++=*tempstring;
+    }
+    while (charsdone<width)
+    {
+        *string++=' ';
+        charsdone++;
+    }
+}
+else
+{
+    if (flags&ZERO_PAD)
+    {
+        if (neg) {*string++='-'; charsdone++;}
+        if (flags&SIGN_PREFIX) {*string++='+'; charsdone++;}
+        if (flags&BLANK_PAD) {*string++=' '; charsdone++;}
+        while (charsdone<width)
+        {
+            *string++='0';
+            charsdone++;
+        }
+    }
+    else
+    {
+        if (neg) {*tempstring++='-'; charsdone++;}
+        if (flags&SIGN_PREFIX) {*tempstring++='+'; charsdone++;}
+        if (flags&BLANK_PAD) {*tempstring++=' '; charsdone++;}
+        while (charsdone<width)
+        {
+            *string++=' ';
+            charsdone++;
+        }
+    }
+    while (*--tempstring)
+    {
+        *string++=*tempstring;
+    }
+}
+
+HeapFree(GetProcessHeap(),0,tempstring);
+return strlenW(out);
+}
+
+int efloattostringw(double in, MSVCRT_wchar_t *out, MSVCRT_wchar_t digits[], int flags,int width,int precision,int length)
+{
+MSVCRT_wchar_t *string=out;
+int exp;
+int neg=0;
+int charsdone=0;
+int infOrNaN=0;
+double temp=in;
+
+if (in<0)
+{
+    in=-in;
+    neg=1;
+    flags&=~SIGN_PREFIX;
+    flags&=~BLANK_PAD;
+}
+
+if (isinf(in))
+{
+    infOrNaN=1;
+    in=0;
+}
+
+if (isnan(in))
+{
+    infOrNaN=2;
+    in=0;
+}
+
+if (in)
+    exp=floor(log10(in));
+else
+    exp=0;
+in/=pow(10,exp);
+if (neg)
+    in=-in;
+    
+if (infOrNaN)
+    in=temp;
+    
+if (flags&PRECISION_COUNT)
+    return floattostringw(in,string,digits,flags,width-5,precision,length-5);
+    
+if (!(flags&LEFT_ALIGN))
+    charsdone+=floattostringw(in,string,digits,flags,width-5,precision,length-5);
+else
+    charsdone+=floattostringw(in,string,digits,flags,0,precision,length-5);
+    
+string+=charsdone;
+*string++=digits[14];
+charsdone++;
+flags=0;
+flags|=SIGN_PREFIX;
+flags|=INT64;
+integertostringw((__int64)exp, string,digits,10,flags,0,3,5);
+charsdone+=4;
+string+=4;
+while (charsdone++<width)
+    *string++=' ';
+    
+return strlenW(out);
+}
+
+int gfloattostringw(double in, MSVCRT_wchar_t *out, MSVCRT_wchar_t digits[], int flags,int width,int precision,int length)
+{
+MSVCRT_wchar_t *string=out;
+int exp=floor(log10(in));
+int charsdone=0;
+if ((exp<-4)||(exp>=precision))
+{
+    precision-=1;
+    if (precision<0) precision=0;
+    if (!(flags&ZERO_PREFIX))
+    {
+        flags|=PRECISION_COUNT;
+        precision-=efloattostringw(in, out, digits, flags, width,precision,length);
+        flags&=~PRECISION_COUNT;
+    }
+    charsdone+=efloattostringw(in, out, digits, flags, width,precision,length);
+    string+=charsdone;
+}
+else
+{
+    precision-=(exp+1);
+    if (precision<0) precision=0;
+    if (!(flags&ZERO_PREFIX))
+    {
+        flags|=PRECISION_COUNT;
+        precision-=floattostringw(in, out, digits, flags, width,precision,length);
+        flags&=~PRECISION_COUNT;
+    }
+    charsdone+=floattostringw(in, out, digits, flags, width,precision,length);
+    string+=charsdone;
+}
+return strlenW(out);
+}
+
+MSVCRT_wchar_t *charprocessw(int in, int flags, int width)
+{
+char inA[]={0,0};
+MSVCRT_wchar_t *inW;
+MSVCRT_wchar_t *tempW;
+MSVCRT_wchar_t *out;
+int allocsize=2;
+int charsdone=1;
+if (width>allocsize) allocsize=width;
+tempW=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),0,(allocsize+1)*sizeof(MSVCRT_wchar_t));
+if (flags&SHORT_CHAR)
+{
+    inA[0]=(char)in;
+    MultiByteToWideChar(CP_ACP, 0, inA, -1, tempW, allocsize);
+}
+else *tempW=(MSVCRT_wchar_t)in;
+inW=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),0,(allocsize+1)*sizeof(MSVCRT_wchar_t));
+out=inW;
+if (!(flags&LEFT_ALIGN))
+{
+    if (flags&ZERO_PAD)
+        while (charsdone++<width) *inW++='0';
+    else
+        while (charsdone++<width) *inW++=' ';
+}*inW++=*tempW;
+HeapFree(GetProcessHeap(),0,tempW);
+if (flags&LEFT_ALIGN)
+{
+    while (charsdone++<width) *inW++=' ';
+}
+*inW=0;
+return out;
+}
+
+MSVCRT_wchar_t *stringprocessw(va_list *in, int flags, int width, int precision)
+{
+char *inA;
+MSVCRT_wchar_t *inW;
+MSVCRT_wchar_t *tempW;
+MSVCRT_wchar_t *out;
+MSVCRT_wchar_t nullstringW[]={'(','n','u','l','l',')',0};
+char nullstringA[]={'(','n','u','l','l',')',0};
+int allocsize=width;
+int length=0;
+int charsdone=0;
+if (flags&SHORT_CHAR)
+{
+    inA=va_arg(*in, char *);
+    if (!inA) inA=nullstringA;
+    length=strlen(inA);
+    if (length>allocsize) allocsize=length;
+    tempW=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),0,(allocsize+1)*sizeof(MSVCRT_wchar_t));
+    MultiByteToWideChar(CP_ACP, 0, inA, -1, tempW, allocsize);
+}
+else
+{
+    tempW=va_arg(*in, MSVCRT_wchar_t *);
+    if (!tempW) tempW=nullstringW;
+    length=strlenW(tempW);
+    if (length>allocsize) allocsize=length;
+}
+inW=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),0,(allocsize+1)*sizeof(MSVCRT_wchar_t));
+out=inW;
+if (precision!=-1) length=precision;
+charsdone=length;
+if (!(flags&LEFT_ALIGN))
+{
+    if (flags&ZERO_PAD)
+        while (charsdone++<width) *inW++='0';
+    else
+        while (charsdone++<width) *inW++=' ';
+}
+memcpy(inW,tempW,length*sizeof(MSVCRT_wchar_t));
+if (flags&SHORT_CHAR) HeapFree(GetProcessHeap(),0,tempW);
+inW+=length;
+if (flags&LEFT_ALIGN)
+{
+    while (charsdone++<width) *inW++=' ';
+}
+*inW=0;
+return out;
+}
+
+int processw(MSVCRT_wchar_t *output, const MSVCRT_wchar_t *input, size_t bufsize)
+{
+int ret=strlenW(input);
+if (ret >= bufsize)
+    memcpy(output, input, bufsize*sizeof(MSVCRT_wchar_t));
+else
+    memcpy(output, input, ret*sizeof(MSVCRT_wchar_t));
+return ret;
+}
+
+int _formatw(MSVCRT_wchar_t *output, const MSVCRT_wchar_t *input, size_t bufsize, va_list *args, int *skip, int done, int flags)
+{
+MSVCRT_wchar_t *stringarg=NULL;
+MSVCRT_wchar_t digitsl[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','x'};
+MSVCRT_wchar_t digitsu[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','X'};
+MSVCRT_wchar_t *digits=digitsu;
+MSVCRT_wchar_t nullstring[]={'(','n','u','l','l',')',0};
+MSVCRT_wchar_t percent[]={'%',0};
+MSVCRT_wchar_t null[]={0};
+int ret=0;
+int malloced=0;
+__int64 num=0;
+__int64 precision=-1;
+__int64 length=0;
+double dnum=0;
+unsigned int width=0;
+(*skip)++;
+input++;
+/**
+ **Flags:
+ **/
+while ((*input=='-')||(*input=='+')||(*input==' ')||(*input=='0')||(*input=='#'))
+{
+switch (*input)
+{
+    case '-':
+        flags|=LEFT_ALIGN;
+        flags&=~ZERO_PAD;
+        break;
+    case '+':
+        flags|=SIGN_PREFIX;
+        flags&=~BLANK_PAD;
+        break;
+    case '0':
+        if (!(flags&LEFT_ALIGN)) flags|=ZERO_PAD;
+        break;
+    case ' ':
+        if (!(flags&SIGN_PREFIX)) flags|=BLANK_PAD;
+        break;
+    case '#':
+        flags|=ZERO_PREFIX;
+        break;
+}
+(*skip)++;
+input++;
+}
+/**Width:
+ **
+ **/
+if (*input=='*')
+{
+    width=va_arg(*args, int);
+    input++;
+    (*skip)++;
+}
+while (iswdigit(*input))
+{
+    width*=10;
+    width+=(*input)-'0';
+    input++;
+    (*skip)++;
+}
+/**Precision:
+ **
+ **/
+if (*input=='.')
+{
+precision=0;
+input++;
+(*skip)++;
+    if (*input=='*')
+    {
+        precision=va_arg(*args, int);
+        input++;
+        (*skip)++;
+    }
+    while (iswdigit(*input))
+    {
+        precision*=10;
+        precision+=(*input)-'0';
+        input++;
+        (*skip)++;
+    }
+}
+/**Size:
+ **
+ **/
+
+switch(*input)
+{
+    case 'l':
+        (*skip)++;
+        input++;
+        flags|=LONG;
+        flags|=LONG_CHAR;
+        flags&=~SHORT_CHAR;
+        break;
+    case 'L':
+        (*skip)++;
+        input++;
+        flags|=LONG;
+        flags|=LONG_CHAR;
+        flags&=~SHORT_CHAR;
+        break;
+    case 'w':
+        (*skip)++;
+        input++;
+        flags|=LONG_CHAR;
+        flags&=~SHORT_CHAR;
+        break;
+    case 'h':
+        (*skip)++;
+        input++;
+        flags|=SHORT;
+        flags|=SHORT_CHAR;
+        flags&=~LONG_CHAR;
+        break;
+    case 'I':
+        (*skip)++;
+        input++;
+        if ((*(input)=='6')&&(*(input+1)=='4'))
+        {
+            (*skip)+=2;
+            input+=2;
+            flags|=INT64;
+            break;
+        }
+        if ((*(input)=='3')&&(*(input+1)=='2'))
+        {
+            (*skip)+=2;
+            input+=2;
+            flags|=INT32;
+            break;
+        }
+        flags|=SIZE_T;
+        break;
+    default:
+        flags|=SIZE_T;
+}
+
+while ((*input=='l')||(*input=='L')||(*input=='w')||(*input=='h')||(*input=='I')) /**Further size specifications are swallowed**/
+{/**This isn't specified, but was determined from testing. Thus "ll", for example, does not mean "long long" (use I64), but "long"**/
+    (*skip)++;
+    input++;
+    if ((*input=='6')&&(*(input+1)=='4'))
+    {
+        (*skip)+=2;
+        input+=2;
+    }
+    if ((*input=='3')&&(*(input+1)=='2'))
+    {
+        (*skip)+=2;
+        input+=2;
+    }
+}
+
+if ((*input=='i')||(*input=='d')||(*input=='u')||(*input=='o')||(*input=='x')||(*input=='X'))
+{/**Do this here simply to avoid duplicating the if statements each time**/
+if (flags&SHORT)
+    num=va_arg(*args, int);
+if (flags&LONG)
+    num=va_arg(*args, long);
+if (flags&SIZE_T)
+    num=va_arg(*args, ptrdiff_t);
+if (flags&INT32)
+    num=va_arg(*args, __int32);
+if (flags&INT64)
+    num=va_arg(*args, __int64);
+}
+switch(*input)
+{
+        case '%':
+            stringarg=percent;
+            (*skip)++;
+            break;
+        case 'n':
+            *va_arg(*args, int *)=done;
+            stringarg=null;
+            (*skip)++;
+            break;
+        case 'c':
+            (*skip)++;
+            malloced=1;
+            if (flags&SHORT_CHAR) {stringarg=charprocessw(va_arg(*args, int),flags,width); break;}
+            if (flags&LONG_CHAR) {stringarg=charprocessw(va_arg(*args, int),flags,width); break;}
+            if (flags&WIDE_PRINTF) flags|=LONG_CHAR;
+            else flags|=SHORT_CHAR;
+            stringarg=charprocessw(va_arg(*args, int),flags,width);
+            break;
+        case 'C':
+            (*skip)++;
+            malloced=1;
+            if (flags&SHORT_CHAR) {stringarg=charprocessw(va_arg(*args, int),flags,width); break;}
+            if (flags&LONG_CHAR) {stringarg=charprocessw(va_arg(*args, int),flags,width); break;}
+            if (flags&WIDE_PRINTF) flags|=SHORT_CHAR;
+            else flags|=LONG_CHAR;
+            stringarg=charprocessw(va_arg(*args, int),flags,width);
+            break;
+        case 's':
+            (*skip)++;
+            malloced=1;
+            if (flags&SHORT_CHAR) {stringarg=stringprocessw(args,flags,width,precision); break;}
+            if (flags&LONG_CHAR) {stringarg=stringprocessw(args,flags,width,precision); break;}
+            if (flags&WIDE_PRINTF) flags|=LONG_CHAR;
+            else flags|=SHORT_CHAR;
+            stringarg=stringprocessw(args,flags,width,precision);
+            break;
+        case 'S':
+            (*skip)++;
+            malloced=1;
+            if (flags&SHORT_CHAR) {stringarg=stringprocessw(args,flags,width,precision); break;}
+            if (flags&LONG_CHAR) {stringarg=stringprocessw(args,flags,width,precision); break;}
+            if (flags&WIDE_PRINTF) flags|=SHORT_CHAR;
+            else flags|=LONG_CHAR;
+            stringarg=stringprocessw(args,flags,width,precision);
+            break;
+        case 'i':
+        case 'd':
+            if (num>0) length=ceil(log10(num)); /**Need to determine the string length**/
+            if (num==0) length=1;               /**necessary to hold the output.      **/
+            if (num<0) length=ceil(log10(-num));
+            if (width>length) length=width;
+            if (precision>length) length=precision;
+            length+=2;                          /** (Plus null terminator and sign)   **/
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            integertostringw(num,stringarg,digitsl,10,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'u':
+            if (num==0) length=1;
+            else length=ceil(log10((unsigned __int64)num));
+            if (width>length) length=width;
+            if (precision>length) length=precision;
+            length++;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            uintegertostringw(num,stringarg,digitsl,10,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'o':
+            if (num==0) length=1;
+            else length=ceil(log((unsigned __int64)num)/log(8));
+            if (width>length) length=width;
+            if (precision>length) length=precision;
+            length++;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            uintegertostringw(num,stringarg,digitsl,8,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'p':
+            num=(size_t)va_arg(*args, PVOID);
+            precision=8;
+            if (num==0) length=1;
+            else length=ceil(log((unsigned __int64)num)/log(16));
+            if (width>length) length=width;
+            if (precision>length) length=precision;
+            length++;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            uintegertostringw(num,stringarg,digitsu,16,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'x':
+            digits=digitsl;
+        case 'X':
+            if (num==0) length=1;
+            else length=ceil(log((unsigned __int64)num)/log(16));
+            if (width>length) length=width;
+            if (precision>length) length=precision;
+            length++;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            uintegertostringw(num,stringarg,digits,16,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'e':
+            digits=digitsl;
+        case 'E':
+            flags|=INT64;
+            dnum=va_arg(*args, double);
+            if (precision==-1) precision=6;
+            length=precision+9;
+            if (width>length) length=width;
+            length+=2;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            efloattostringw(dnum,stringarg,digits,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'f':
+            flags|=INT64;
+            dnum=va_arg(*args, double);
+            if (precision==-1) precision=6;
+            if (dnum>0) length=precision+ceil(log10(dnum))+2;
+            if (dnum==0) length=precision+2;
+            if (dnum<0) length=precision+ceil(log10(-dnum))+2;
+            if (isinf(dnum)||isnan(dnum)) length=precision+2;
+            if (width>length) length=width;
+            length+=2;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            floattostringw(dnum,stringarg,digitsl,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        case 'g':
+            digits=digitsl;
+        case 'G':
+            flags|=INT64;
+            dnum=va_arg(*args, double);
+            if (precision==-1) precision=6;
+            if (dnum>0) length=precision+ceil(log10(dnum))+2;
+            if (dnum==0) length=precision+2;
+            if (dnum<0) length=precision+ceil(log10(-dnum))+2;
+            if (isinf(dnum)||isnan(dnum)) length=precision+2;
+            if ((precision+9)>length) length=precision+9;
+            if (width>length) length=width;
+            length+=2;
+            stringarg=(MSVCRT_wchar_t *)HeapAlloc(GetProcessHeap(),8,length*sizeof(MSVCRT_wchar_t));
+            gfloattostringw(dnum,stringarg,digits,flags,width,precision,length);
+            (*skip)++;
+            malloced=1;
+            break;
+        default:
+            stringarg=null;
+}
+if (!stringarg)
+    stringarg=nullstring;
+ret=strlenW(stringarg);
+if (ret >= bufsize)
+    ret=bufsize;
+memcpy(output, stringarg, ret*sizeof(MSVCRT_wchar_t));
+if (malloced)
+    HeapFree(GetProcessHeap(),0,stringarg);
+return ret;
+}
-------------- next part --------------
Index: dlls/msvcrt/tests/printf.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/tests/printf.c,v
retrieving revision 1.1
diff -u -u -r1.1 printf.c
--- dlls/msvcrt/tests/printf.c	4 Nov 2004 21:03:30 -0000	1.1
+++ dlls/msvcrt/tests/printf.c	5 Nov 2004 21:55:45 -0000
@@ -31,49 +31,30 @@
     const char *O4s = "%04s";
     const char *hash012p = "%#012p";
     double pnumber=789456123;
-/**    WCHAR widestring[]={'w','i','d','e','s','t','r','i','n','g',0};**/
+    const wchar_t 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);
-      }
+      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);
-      }
+      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);
-      }
- **/
+      ok(strlen(buffer) == 1,"Problem with \"ll\" interpretation \"%s\"\n",buffer);
+    
+    sprintf(buffer,"%S", (LPWSTR)widestring);
+      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);
-      }
+      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);
-      }
+      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);
-      }
+      ok(!strcmp(buffer,"  0X00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer);
+    
+    sprintf(buffer,O4s,"foo");
+      ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer);
 }
 
 static void test_swprintf( void )
@@ -86,15 +67,11 @@
     const char string[]={'s','t','r','i','n','g',0};
     const wchar_t S[]={'%','S',0};
     swprintf(buffer,TwentyThreePoint15e,pnumber);
-    todo_wine
-      {
-        ok(wcsstr(buffer,e008) != 0,"Sprintf different\n");
-      }
+      ok(wcsstr(buffer,e008) != 0,"Sprintf different\n");
+    
     swprintf(buffer,I64d,((ULONGLONG)0xffffffff)*0xffffffff);
-    todo_wine
-      {
-        ok(wcslen(buffer) == 11,"Problem with long long\n");
-      }
+      ok(wcslen(buffer) == 11,"Problem with long long\n");
+    
     swprintf(buffer,S,string);
       ok(wcslen(buffer) == 6,"Problem with \"%%S\" interpretation\n");
 }
@@ -121,8 +98,8 @@
     /* Pre-2.1 libc behaviour, not C99 compliant. */
     const struct snprintf_test tests[] = {{"short", 5, {0, 0}},
                                           {"justfit", 7, {0, 0}},
-                                          {"justfits", 8, {0, 1}},
-                                          {"muchlonger", -1, {1, 1}}};
+                                          {"justfits", 8, {0, 0}},
+                                          {"muchlonger", -1, {0, 0}}};
     char buffer[8];
     const int bufsiz = sizeof buffer;
     unsigned int i;


More information about the wine-patches mailing list