Bug #321: msvcrt-vfprintf-4.diff

Jaco Greeff jaco at puxedo.org
Tue Oct 29 06:04:40 CST 2002


Ok, this version is the same as patch "msvcrt-vfprintf-3.diff", with
exactly the same comments and test results (verified and attached after
changelog), just with the redundant (WCHAR)L casts removed.

License:
LGPL

Changelog:
* dlls/msvcrt/file.c, dlls/msvcrt/vfprintf.c, dlls/msvcrt/Makefile.in:
Jaco Greeff <jaco at puxedo.org>
- Cater for the %C and %S formatting characters in all the vf[W]printf
functions. (Both widechar and multibyte versions)


-- 

[jaco at grumpy Projects]$ wine TestPrintf.exe
Integer formats:
          Decimal: -9234  Justified: -009234  Unsigned: 4294958062
Decimal -9234 as:
          Hex: FFFFDBEEh  C hex: 0xffffdbee  Octal: 37777755756
Digits 10 equal:
          Hex: 16  Octal: 8  Decimal: 10
Characters in field (1):
           h    h    w    w
Characters in field (2):
           h    h    w    w
Strings in field (1):
                   computer
                       comp
          Unicode                      Uni
Strings in field (2):
                   computer
                       comp
          Unicode                      Uni
Real numbers:
          251.736600 251.74 2.517366e+002 2.517366E+002

Address as:     406F2E50

Display to here:
123456789012345678901234567890
          Number displayed: 16

-------------- next part --------------
diff -aurN msvcrt-vfprintf.orig/dlls/msvcrt/Makefile.in msvcrt-vfprintf.new/dlls/msvcrt/Makefile.in
--- msvcrt-vfprintf.orig/dlls/msvcrt/Makefile.in	Tue Oct 29 12:48:03 2002
+++ msvcrt-vfprintf.new/dlls/msvcrt/Makefile.in	Tue Oct 29 07:28:31 2002
@@ -35,6 +35,7 @@
 	string.c \
 	thread.c \
 	time.c \
+	vfprintf.c \
 	wcs.c
 
 @MAKE_DLL_RULES@
diff -aurN msvcrt-vfprintf.orig/dlls/msvcrt/file.c msvcrt-vfprintf.new/dlls/msvcrt/file.c
--- msvcrt-vfprintf.orig/dlls/msvcrt/file.c	Tue Oct 29 12:40:14 2002
+++ msvcrt-vfprintf.new/dlls/msvcrt/file.c	Tue Oct 29 07:28:31 2002
@@ -2190,59 +2190,6 @@
 }
 
 /*********************************************************************
- *		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 WCHAR *format, va_list valist)
-{
-  WCHAR buf[2048], *mem = buf;
-  int written, resize = sizeof(buf) / sizeof(WCHAR), retval;
-  /* See vfprintf comments */
-  while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
-          written > resize)
-  {
-    resize = (written == -1 ? resize * 2 : written + sizeof(WCHAR));
-    if (mem != buf)
-      MSVCRT_free (mem);
-    if (!(mem = (WCHAR *)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)
diff -aurN msvcrt-vfprintf.orig/dlls/msvcrt/vfprintf.c msvcrt-vfprintf.new/dlls/msvcrt/vfprintf.c
--- msvcrt-vfprintf.orig/dlls/msvcrt/vfprintf.c	Thu Jan  1 02:00:00 1970
+++ msvcrt-vfprintf.new/dlls/msvcrt/vfprintf.c	Tue Oct 29 13:54:34 2002
@@ -0,0 +1,764 @@
+/* vfprintf, vfwprintf for MSVCRT and internal helper functions thereof
+ *
+ * Copyright 2002 Jaco Greeff
+ *
+ * Portions originally based upon code in dlls/[shlwapi|user]/wsprintf.c,
+ * Copyright 1996 Alexandre Julliard
+ *
+ * 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 "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "winbase.h"
+#include "winnls.h"
+#include "wine/unicode.h"
+#include "msvcrt/stdio.h"
+#include "msvcrt/string.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
+
+#define VFPRINTF_LEFTALIGN   0x0001  /* Align output on the left ('-' prefix) */
+#define VFPRINTF_PREFIX_HEX  0x0002  /* Prefix hex with 0x ('#' prefix) */
+#define VFPRINTF_ZEROPAD     0x0004  /* Pad with zeros ('0' prefix) */
+#define VFPRINTF_LONG        0x0008  /* Long arg ('l' prefix) */
+#define VFPRINTF_SHORT       0x0010  /* Short arg ('h' prefix) */
+#define VFPRINTF_UPPER       0x0020  /* Upper-case hex ('X' specifier) */
+#define VFPRINTF_WIDE        0x0040  /* Wide arg ('w' prefix) */
+
+typedef struct
+{
+    MSVCRT_FILE  *fIOFile;
+    INT          nBufLen;
+    INT          nTotLen;
+    INT          nThisLen;
+} VFPRINTF_FILE;
+
+typedef enum
+{
+    VFMT_UNKNOWN,
+    VFMT_CHAR,
+    VFMT_WCHAR,
+    VFMT_STRING,
+    VFMT_WSTRING,
+    VFMT_INTEGER,
+    VFMT_UNSIGNED,
+    VFMT_DOUBLE,
+    VFMT_INT_LENGTH,
+    VFMT_POINTER
+} VFPRINTF_FORMAT_TYPE;
+
+typedef struct
+{
+    CHAR                 szFmt[128];
+    UINT                 nFlags;
+    UINT                 nWidth;
+    UINT                 nPrecision;
+    VFPRINTF_FORMAT_TYPE nType;
+} VFPRINTF_FORMAT, *VFPRINTF_PFORMAT;
+
+
+/*********************************************************************
+ *      VFPRINTF_printCharA
+ *      (internal, non-exported)
+ *
+ * Prints a single ASCII char to the required file/buffer
+ */
+INT VFPRINTF_printCharA(VFPRINTF_FILE *fOut, CHAR ch)
+{
+    if (fOut->fIOFile)
+    {
+        if ((fOut->nBufLen > 1) || (fOut->nBufLen == -1))
+            MSVCRT(fwrite)(&ch, sizeof(CHAR), 1, fOut->fIOFile);
+        if (fOut->nBufLen != -1)
+            fOut->nBufLen--;
+        fOut->nTotLen++;
+    }
+    fOut->nThisLen++;
+
+    return 1;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_LPCWSTRToLPSTR
+ *      (internal, non-exported)
+ *
+ * Wrapper to allocate enough memory and convert a LPCWSTR to a normal
+ * LPSTR
+ */
+CHAR *VFPRINTF_LPCWSTRToLPSTR(LPCWSTR lpwszIn, INT nIn)
+{
+    INT nLen = WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, NULL, 0, NULL, NULL);
+    CHAR *szOut = (CHAR *)malloc((nLen+1)*sizeof(CHAR));
+    if (szOut)
+    {
+        WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, szOut, nLen+1, NULL, NULL);
+        szOut[nLen] = '\0';
+    }
+    return szOut;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printStringA
+ *      (internal, non-exported)
+ *
+ * Prints a ASCII string to the required file/buffer
+ */
+INT VFPRINTF_printStringA(VFPRINTF_FILE *fOut, LPCSTR szStr)
+{
+    INT nLen = 0;
+
+    while (szStr && *szStr)
+    {
+        nLen += VFPRINTF_printCharA(fOut, *szStr);
+        szStr++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printCharW
+ *      (internal, non-exported)
+ *
+ * Prints a single wide char to the required file/buffer
+ */
+INT VFPRINTF_printCharW(VFPRINTF_FILE *fOut, WCHAR wch)
+{
+    CHAR *szStr = VFPRINTF_LPCWSTRToLPSTR(&wch, 1);
+    INT nLen = VFPRINTF_printStringA(fOut, szStr);
+    if (szStr)
+        free(szStr);
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printStringW
+ *      (internal, non-exported)
+ *
+ * Prints a wide string to the required file/buffer
+ */
+INT VFPRINTF_printStringW(VFPRINTF_FILE *fOut, LPCWSTR wszStr)
+{
+    CHAR *szStr = VFPRINTF_LPCWSTRToLPSTR(wszStr, -1);
+    INT nLen = VFPRINTF_printStringA(fOut, szStr);
+    if (szStr)
+        free(szStr);
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printArgListA
+ *      (internal, non-exported)
+ *
+ * Prints a single argument to the required file/buffer
+ */
+INT VFPRINTF_printArgListA(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat,
+                           va_list vaList)
+{
+    INT nLen = 0;
+    INT nMax = 1024;
+    CHAR *szScratch;
+
+    if (!(szScratch = (CHAR *)malloc((nMax+1)*sizeof(CHAR))))
+        return 0;
+
+    while ((nLen = vsnprintf(szScratch, nMax, pFormat->szFmt, vaList)) == -1)
+    {
+        free(szScratch);
+        nMax = nMax*2;
+        szScratch = (CHAR *)malloc((nMax+1)*sizeof(CHAR));
+    }
+    nLen = VFPRINTF_printStringA(fOut, szScratch);
+    free(szScratch);
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFmtListA
+ *      (internal, non-exported)
+ *
+ * Prints a format string to the required file/buffer
+ */
+INT VFPRINTF_printFmtListA(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, ...)
+{
+    INT nLen;
+    va_list vaList;
+
+    va_start(vaList, pFormat);
+    nLen = VFPRINTF_printArgListA(fOut, pFormat, vaList);
+    va_end(vaList);
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFormatA
+ *      (internal, non-exported)
+ *
+ * Prints a full format string to the required file/buffer
+ */
+va_list VFPRINTF_printFormatA(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, va_list vaList)
+{
+    switch (pFormat->nType)
+    {
+        case VFMT_CHAR:
+        {
+            VFPRINTF_printArgListA(fOut, pFormat, vaList);
+            (VOID)va_arg(vaList, INT);
+            break;
+        }
+        case VFMT_WCHAR:
+        {
+            WCHAR wch = (WCHAR)va_arg(vaList, INT);
+            CHAR *szStr = VFPRINTF_LPCWSTRToLPSTR(&wch, 1);
+            VFPRINTF_printFmtListA(fOut, pFormat, szStr);
+            break;
+        }
+        case VFMT_STRING:
+        case VFMT_POINTER:
+        {
+            VFPRINTF_printArgListA(fOut, pFormat, vaList);
+            (VOID)va_arg(vaList, VOID *);
+            break;
+        }
+        case VFMT_WSTRING:
+        {
+            WCHAR *wszStr = (WCHAR *)va_arg(vaList, WCHAR *);
+            CHAR *szStr = VFPRINTF_LPCWSTRToLPSTR(wszStr, -1);
+            if (szStr)
+            {
+                VFPRINTF_printFmtListA(fOut, pFormat, szStr);
+                free(szStr);
+            }
+            break;
+        }
+        case VFMT_INT_LENGTH:
+        {
+            INT *p = va_arg(vaList, INT *);
+            *p = fOut->nThisLen;
+            break;
+        }
+        case VFMT_INTEGER:
+        {
+            VFPRINTF_printArgListA(fOut, pFormat, vaList);
+            (VOID)va_arg(vaList, INT);
+            break;
+        }
+        case VFMT_DOUBLE:
+        {
+            VFPRINTF_printArgListA(fOut, pFormat, vaList);
+            (VOID)va_arg(vaList, double);
+            break;
+        }
+        case VFMT_UNKNOWN:
+        {
+            VFPRINTF_printArgListA(fOut, pFormat, vaList);
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return vaList;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrefixA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string
+ */
+INT VFPRINTF_parseFormatPrefixA(LPCSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '-')
+    {
+        strcat(pFormat->szFmt, "-");
+        pFormat->nFlags |= VFPRINTF_LEFTALIGN;
+        szFmt++;
+        nLen++;
+    }
+    if (*szFmt == '#')
+    {
+        strcat(pFormat->szFmt, "#");
+        pFormat->nFlags |= VFPRINTF_PREFIX_HEX;
+        szFmt++;
+        nLen++;
+    }
+    if (*szFmt == '0')
+    {
+        strcat(pFormat->szFmt, "0");
+        pFormat->nFlags |= VFPRINTF_ZEROPAD;
+        szFmt++;
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrefixW
+ *      (internal, non-exported)
+ *
+ * Parses part of a wide format string
+ */
+INT VFPRINTF_parseFormatPrefixW(LPCWSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '-')
+    {
+        strcat(pFormat->szFmt, "-");
+        pFormat->nFlags |= VFPRINTF_LEFTALIGN;
+        szFmt += sizeof(WCHAR);
+        nLen++;
+    }
+    if (*szFmt == '#')
+    {
+        strcat(pFormat->szFmt, "#");
+        pFormat->nFlags |= VFPRINTF_PREFIX_HEX;
+        szFmt += sizeof(WCHAR);
+        nLen++;
+    }
+    if (*szFmt == '0')
+    {
+        strcat(pFormat->szFmt, "0");
+        pFormat->nFlags |= VFPRINTF_ZEROPAD;
+        szFmt += sizeof(WCHAR);
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatWidthA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for width specifiers
+ */
+INT VFPRINTF_parseFormatWidthA(LPCSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    while ((*szFmt >= '0') && (*szFmt <= '9'))
+    {
+        strncat(pFormat->szFmt, szFmt, 1);
+        *pNum = (*pNum)*10 + *szFmt - '0';
+        szFmt++;
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatWidthW
+ *      (internal, non-exported)
+ *
+ * Parses part of a wide format string for width specifiers
+ */
+INT VFPRINTF_parseFormatWidthW(LPCWSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    while ((*szFmt >= '0') && (*szFmt <= '9'))
+    {
+        /* Print only the digit as pointed to by the pointer. If sizeof(CHAR) != 1
+           or arch != ix86, this is not correct. Where the above is applicable, this
+           code will and does work as advertised. */
+        strncat(pFormat->szFmt, (CHAR *)szFmt, 1);
+        *pNum = (*pNum)*10 + *szFmt - '0';
+        szFmt += sizeof(WCHAR);
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrecisionA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for precision specifiers
+ */
+INT VFPRINTF_parseFormatPrecisionA(LPCSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '.')
+    {
+        strcat(pFormat->szFmt, ".");
+        nLen++;
+        nLen += VFPRINTF_parseFormatWidthA(++szFmt, pNum, pFormat);
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrecisionW
+ *      (internal, non-exported)
+ *
+ * Parses part of a wide format string for precision specifiers
+ */
+INT VFPRINTF_parseFormatPrecisionW(LPCWSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '.')
+    {
+        strcat(pFormat->szFmt, ".");
+        nLen++;
+        szFmt += sizeof(WCHAR);
+        nLen += VFPRINTF_parseFormatWidthW(szFmt, pNum, pFormat);
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatFlagsA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for flags
+ */
+INT VFPRINTF_parseFormatFlagsA(LPCSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        case 'l':
+            pFormat->nFlags |= VFPRINTF_LONG;
+            return 1;
+        case 'h':
+            pFormat->nFlags |= VFPRINTF_SHORT;
+            return 1;
+        case 'w':
+            pFormat->nFlags |= VFPRINTF_WIDE;
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatFlagsW
+ *      (internal, non-exported)
+ *
+ * Parses part of a wide format string for flags
+ */
+INT VFPRINTF_parseFormatFlagsW(LPCWSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        case 'l':
+            pFormat->nFlags |= VFPRINTF_LONG;
+            return 1;
+        case 'h':
+            pFormat->nFlags |= VFPRINTF_SHORT;
+            return 1;
+        case 'w':
+            pFormat->nFlags |= VFPRINTF_WIDE;
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatTypeA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for type specifiers
+ */
+#define ADD_FORMAT_TYPE(type, fmt) \
+    pFormat->nType = type; \
+    strcat(pFormat->szFmt, fmt); \
+    break;
+INT VFPRINTF_parseFormatTypeA(LPCSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        case 'd': ADD_FORMAT_TYPE(VFMT_INTEGER, "d");
+        case 'i': ADD_FORMAT_TYPE(VFMT_INTEGER, "i");
+        case 'o': ADD_FORMAT_TYPE(VFMT_INTEGER, "o");
+        case 'u': ADD_FORMAT_TYPE(VFMT_INTEGER, "u");
+        case 'X': ADD_FORMAT_TYPE(VFMT_INTEGER, "X");
+        case 'x': ADD_FORMAT_TYPE(VFMT_INTEGER, "x");
+        case 'E': ADD_FORMAT_TYPE(VFMT_DOUBLE, "E");
+        case 'e': ADD_FORMAT_TYPE(VFMT_DOUBLE, "e");
+        case 'f': ADD_FORMAT_TYPE(VFMT_DOUBLE, "f");
+        case 'G': ADD_FORMAT_TYPE(VFMT_DOUBLE, "G");
+        case 'g': ADD_FORMAT_TYPE(VFMT_DOUBLE, "g");
+        case 'n': ADD_FORMAT_TYPE(VFMT_INT_LENGTH, "n");
+        case 'p': ADD_FORMAT_TYPE(VFMT_POINTER, "p");
+        case 'c':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_LONG) ? VFMT_WCHAR : VFMT_CHAR;
+            strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+            break;
+        }
+        case 'C':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_CHAR : VFMT_WCHAR;
+            strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+            break;
+        }
+        case 's':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_LONG) ? VFMT_WSTRING : VFMT_STRING;
+            strcat(pFormat->szFmt, "s");
+            break;
+        }
+        case 'S':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_STRING : VFMT_WSTRING;
+            strcat(pFormat->szFmt, "s");
+            break;
+        }
+        default:
+        {
+            pFormat->nType = VFMT_UNKNOWN;
+            strncat(pFormat->szFmt, szFmt, 1);
+            break;
+        }
+    }
+
+    return 1;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatTypeW
+ *      (internal, non-exported)
+ *
+ * Parses part of a wide format string for type specifiers
+ */
+INT VFPRINTF_parseFormatTypeW(LPCWSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        case 'd': ADD_FORMAT_TYPE(VFMT_INTEGER, "d");
+        case 'i': ADD_FORMAT_TYPE(VFMT_INTEGER, "i");
+        case 'o': ADD_FORMAT_TYPE(VFMT_INTEGER, "o");
+        case 'u': ADD_FORMAT_TYPE(VFMT_INTEGER, "u");
+        case 'X': ADD_FORMAT_TYPE(VFMT_INTEGER, "X");
+        case 'x': ADD_FORMAT_TYPE(VFMT_INTEGER, "x");
+        case 'E': ADD_FORMAT_TYPE(VFMT_DOUBLE, "E");
+        case 'e': ADD_FORMAT_TYPE(VFMT_DOUBLE, "e");
+        case 'f': ADD_FORMAT_TYPE(VFMT_DOUBLE, "f");
+        case 'G': ADD_FORMAT_TYPE(VFMT_DOUBLE, "G");
+        case 'g': ADD_FORMAT_TYPE(VFMT_DOUBLE, "g");
+        case 'n': ADD_FORMAT_TYPE(VFMT_INT_LENGTH, "n");
+        case 'p': ADD_FORMAT_TYPE(VFMT_POINTER, "p");
+        case 'c':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_CHAR : VFMT_WCHAR;
+            strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+            break;
+        }
+        case 'C':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_LONG) ? VFMT_WCHAR : VFMT_CHAR;
+            strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+            break;
+        }
+
+        case 's':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_STRING : VFMT_WSTRING;
+            strcat(pFormat->szFmt, "s");
+            break;
+        }
+        case 'S':
+        {
+            pFormat->nType = (pFormat->nFlags & VFPRINTF_LONG) ? VFMT_WSTRING : VFMT_STRING;
+            strcat(pFormat->szFmt, "s");
+            break;
+
+        }
+        default:
+        {
+            CHAR *szFmtChars = VFPRINTF_LPCWSTRToLPSTR(szFmt, 1);
+            if (szFmtChars)
+            {
+                strcat(pFormat->szFmt, szFmtChars);
+                free(szFmtChars);
+            }
+            pFormat->nType = VFMT_UNKNOWN;
+            break;
+        }
+    }
+
+    return 1;
+}
+#undef ADD_FORMAT_TYPE
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatA
+ *      (internal, non-exported)
+ *
+ * Parses a format string
+ */
+#define CLEAR_FORMAT \
+    pFormat->szFmt[0] = '%'; \
+    pFormat->szFmt[1] = '\0'; \
+    pFormat->nFlags = 0; \
+    pFormat->nWidth = 0; \
+    pFormat->nPrecision = 0;
+INT VFPRINTF_parseFormatA(LPCSTR szSpec, VFPRINTF_PFORMAT pFormat)
+{
+    LPCSTR szFmt = szSpec;
+
+    CLEAR_FORMAT;
+
+    /* parse: %[-][#][0][width][.precision]type */
+    szFmt++;
+    szFmt += VFPRINTF_parseFormatPrefixA(szFmt, pFormat);
+    szFmt += VFPRINTF_parseFormatWidthA(szFmt, &(pFormat->nWidth), pFormat);
+    szFmt += VFPRINTF_parseFormatPrecisionA(szFmt, &(pFormat->nPrecision), pFormat);
+    szFmt += VFPRINTF_parseFormatFlagsA(szFmt, pFormat);
+    szFmt += VFPRINTF_parseFormatTypeA(szFmt, pFormat);
+
+    return (INT)(szFmt - szSpec);
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatW
+ *      (internal, non-exported)
+ *
+ * Parses a wide format string
+ */
+INT VFPRINTF_parseFormatW(LPCWSTR szSpec, VFPRINTF_PFORMAT pFormat)
+{
+    LPCWSTR szFmt = szSpec;
+
+    CLEAR_FORMAT;
+
+    /* parse: %[-][#][0][width][.precision]type */
+    szFmt += sizeof(WCHAR);
+    szFmt += VFPRINTF_parseFormatPrefixW(szFmt, pFormat)*sizeof(WCHAR);
+    szFmt += VFPRINTF_parseFormatWidthW(szFmt, &(pFormat->nWidth), pFormat)*sizeof(WCHAR);
+    szFmt += VFPRINTF_parseFormatPrecisionW(szFmt, &(pFormat->nPrecision), pFormat)*sizeof(WCHAR);
+    szFmt += VFPRINTF_parseFormatFlagsW(szFmt, pFormat)*sizeof(WCHAR);
+    szFmt += VFPRINTF_parseFormatTypeW(szFmt, pFormat)*sizeof(WCHAR);
+
+    return ((INT)(szFmt - szSpec))/sizeof(WCHAR);
+}
+#undef CLEAR_FORMAT
+
+
+/*********************************************************************
+ *      vfprintf (MSVCRT.@)
+ */
+int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
+{
+    VFPRINTF_FILE   fOut;
+
+    fOut.fIOFile = file;
+    fOut.nBufLen = -1;
+    fOut.nTotLen = 0;
+    fOut.nThisLen = 0;
+
+    while (*format)
+    {
+        switch (*format)
+        {
+            case '%':
+            {
+                VFPRINTF_FORMAT fSpec;
+                format += VFPRINTF_parseFormatA(format, &fSpec);
+                valist = VFPRINTF_printFormatA(&fOut, &fSpec, valist);
+                break;
+            }
+            default:
+            {
+                format += VFPRINTF_printCharA(&fOut, *format);
+                break;
+            }
+        }
+    }
+
+    return fOut.nTotLen;
+}
+
+/*********************************************************************
+ *      vfwprintf (MSVCRT.@)
+ */
+int MSVCRT_vfwprintf(MSVCRT_FILE* file, const WCHAR *format, va_list valist)
+{
+    VFPRINTF_FILE   fOut;
+
+    fOut.fIOFile = file;
+    fOut.nBufLen = -1;
+    fOut.nTotLen = 0;
+    fOut.nThisLen = 0;
+
+    while (*format)
+    {
+        switch (*format)
+        {
+            case '%':
+            {
+                VFPRINTF_FORMAT fSpec;
+                format += VFPRINTF_parseFormatW(format, &fSpec)*sizeof(WCHAR);
+                valist = VFPRINTF_printFormatA(&fOut, &fSpec, valist);
+                break;
+            }
+            default:
+            {
+                format += VFPRINTF_printCharW(&fOut, *format)*sizeof(WCHAR);
+                break;
+            }
+        }
+    }
+
+    return fOut.nTotLen;
+}
+



More information about the wine-patches mailing list