msvcrt-B01: vfprintf/vfwprintf

Jaco Greeff jaco at puxedo.org
Tue Nov 5 05:21:01 CST 2002


Updated to make sure that the A?? patches applies cleanly to current CVS.

License:
LGPL

Changelog:
* dlls/msvcrt/Makefile.in, dlls/msvcrt/vfprintf.c: Jaco Greeff 
<jaco at puxedo.org>
- Full implementation of the vfprintf & vfwprintf functions allowing 
full support for Microsoft format extentions %C and %S
-------------- next part --------------
diff -aurN msvcrt-B00/dlls/msvcrt/Makefile.in msvcrt-B01/dlls/msvcrt/Makefile.in
--- msvcrt-B00/dlls/msvcrt/Makefile.in	Thu Oct 31 01:49:03 2002
+++ msvcrt-B01/dlls/msvcrt/Makefile.in	Tue Nov  5 11:46:50 2002
@@ -35,6 +35,7 @@
 	string.c \
 	thread.c \
 	time.c \
+	vfprintf.c \
 	wcs.c
 
 SUBDIRS = tests
diff -aurN msvcrt-B00/dlls/msvcrt/file.c msvcrt-B01/dlls/msvcrt/file.c
--- msvcrt-B00/dlls/msvcrt/file.c	Fri Oct 25 05:12:01 2002
+++ msvcrt-B01/dlls/msvcrt/file.c	Tue Nov  5 11:46:50 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-B00/dlls/msvcrt/vfprintf.c msvcrt-B01/dlls/msvcrt/vfprintf.c
--- msvcrt-B00/dlls/msvcrt/vfprintf.c	Thu Jan  1 02:00:00 1970
+++ msvcrt-B01/dlls/msvcrt/vfprintf.c	Tue Nov  5 11:46:54 2002
@@ -0,0 +1,983 @@
+/* vfprintf, vfwprintf for MSVCRT and internal helper functions thereof
+ *
+ * Copyright 2002 Jaco Greeff
+ *
+ * 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>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "winbase.h"
+#include "winnls.h"
+#include "wine/unicode.h"
+#include "msvcrt/stdio.h"
+#include "msvcrt/stdlib.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
+ */
+static inline 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_printCharW
+ *      (internal, non-exported)
+ *
+ * Prints a single Unicode char to the required file/buffer
+ */
+static inline INT VFPRINTF_printCharW(VFPRINTF_FILE *fOut, WCHAR wch)
+{
+    if (fOut->fIOFile)
+    {
+        if ((fOut->nBufLen > 1) || (fOut->nBufLen == -1))
+            MSVCRT(fwrite)(&wch, sizeof(WCHAR), 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
+ */
+static inline CHAR *VFPRINTF_LPCWSTRToLPSTR(LPCWSTR lpwszIn, INT nIn)
+{
+    INT nLen;
+    CHAR *szOut;
+
+    nLen = WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, NULL, 0, NULL, NULL);
+    if ((szOut = (CHAR *)MSVCRT_malloc((nLen+1)*sizeof(CHAR))))
+    {
+        WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, szOut, nLen+1, NULL, NULL);
+        szOut[nLen] = '\0';
+    }
+
+    return szOut;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_LPCSTRToLPWSTR
+ *      (internal, non-exported)
+ *
+ * Wrapper to allocate enough memory and convert a LPCSTR to a normal
+ * LPWSTR
+ */
+static inline WCHAR *VFPRINTF_LPCSTRToLPWSTR(LPCSTR lpszIn, INT nIn)
+{
+    INT nLen;
+    WCHAR *szOut;
+
+    nLen = MultiByteToWideChar(CP_ACP, 0, lpszIn, nIn, NULL, 0);
+    if ((szOut = (WCHAR *)MSVCRT_malloc((nLen+1)*sizeof(WCHAR))))
+    {
+        MultiByteToWideChar(CP_ACP, 0, lpszIn, nIn, szOut, nLen+1);
+        szOut[nLen] = 0;
+    }
+
+    return szOut;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printStringA
+ *      (internal, non-exported)
+ *
+ * Prints a ASCII string to the required file/buffer
+ */
+static inline INT VFPRINTF_printStringA(VFPRINTF_FILE *fOut, LPCSTR szStr)
+{
+    INT nLen = 0;
+
+    while (szStr && *szStr)
+    {
+        VFPRINTF_printCharA(fOut, *szStr);
+        nLen++;
+        szStr++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printStringW
+ *      (internal, non-exported)
+ *
+ * Prints a Unicode string to the required file/buffer
+ */
+static inline INT VFPRINTF_printStringW(VFPRINTF_FILE *fOut, LPCWSTR szStr)
+{
+    INT nLen = 0;
+
+    while (szStr && *szStr)
+    {
+        VFPRINTF_printCharW(fOut, *szStr);
+        nLen++;
+        szStr++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_nprintStringW
+ *      (internal, non-exported)
+ *
+ * Prints a Unicode string (num characters) to the required file/buffer
+ */
+static INT VFPRINTF_nprintStringW(VFPRINTF_FILE *fOut, LPCWSTR szStr, INT nWidth)
+{
+    INT nLen = 0;
+
+    while (nWidth && szStr && *szStr)
+    {
+        VFPRINTF_printCharW(fOut, *szStr);
+        nLen++;
+        szStr++;
+        nWidth--;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFormatArgA
+ *      (internal, non-exported)
+ *
+ * Prints a single argument using the ASCII format string to
+ * the required file/buffer
+ */
+static INT VFPRINTF_vprintFormatArgA(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, ...)
+{
+    INT nLen = 2048;
+    CHAR szScratch[2048+1];
+    CHAR *szBuffer = szScratch;
+    INT nWritten = 0;
+    va_list vaList;
+
+    va_start(vaList, pFormat);
+    while (((nWritten = vsnprintf(szBuffer, nLen, pFormat->szFmt, vaList)) == -1) ||
+           (nWritten >= nLen))
+    {
+        if (szBuffer != szScratch)
+            MSVCRT_free(szBuffer);
+        nLen = (nWritten == -1) ? nLen*2 : nWritten+1;
+        szBuffer = (CHAR *)MSVCRT_malloc(nLen*sizeof(*szBuffer));
+    }
+    nWritten = VFPRINTF_printStringA(fOut, szBuffer);
+    if (szBuffer != szScratch)
+        MSVCRT_free(szBuffer);
+    va_end(vaList);
+
+    return nWritten;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFormatArgW
+ *      (internal, non-exported)
+ *
+ * Prints a single argument using the Unicode format string to
+ * the required file/buffer
+ */
+static INT VFPRINTF_vprintFormatArgW(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, ...)
+{
+    INT nLen = 2048;
+    CHAR szScratch[2048+1];
+    CHAR *szBuffer = szScratch;
+    WCHAR *wszBuffer;
+    INT nWritten = 0;
+    va_list vaList;
+
+    va_start(vaList, pFormat);
+    while (((nWritten = vsnprintf(szBuffer, nLen, pFormat->szFmt, vaList)) == -1) ||
+           (nWritten >= nLen))
+    {
+        if (szBuffer != szScratch)
+            MSVCRT_free(szBuffer);
+        nLen = (nWritten == -1) ? nLen*2 : nWritten+1;
+        szBuffer = (CHAR *)MSVCRT_malloc(nLen*sizeof(*szBuffer));
+    }
+    if ((wszBuffer = VFPRINTF_LPCSTRToLPWSTR(szBuffer, nWritten)))
+    {
+        nWritten = VFPRINTF_printStringW(fOut, wszBuffer);
+        MSVCRT_free(wszBuffer);
+    }
+    else
+        nWritten = 0;
+    if (szBuffer != szScratch)
+        MSVCRT_free(szBuffer);
+    va_end(vaList);
+
+    return nWritten;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFormatA
+ *      (internal, non-exported)
+ *
+ * Prints a full ASCII format string to the required file/buffer
+ */
+static va_list VFPRINTF_printFormatA(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, va_list vaList)
+{
+    switch (pFormat->nType)
+    {
+        case VFMT_POINTER:
+            VFPRINTF_vprintFormatArgA(fOut, pFormat, (VOID *)va_arg(vaList, VOID *));
+            break;
+        case VFMT_INT_LENGTH:
+        {
+            INT *p = va_arg(vaList, INT *);
+            *p = fOut->nThisLen;
+            break;
+        }
+        case VFMT_INTEGER:
+            VFPRINTF_vprintFormatArgA(fOut, pFormat, va_arg(vaList, INT));
+            break;
+        case VFMT_DOUBLE:
+            VFPRINTF_vprintFormatArgA(fOut, pFormat, va_arg(vaList, double));
+            break;
+        case VFMT_CHAR:
+            VFPRINTF_vprintFormatArgA(fOut, pFormat, (CHAR)va_arg(vaList, INT));
+            break;
+        case VFMT_STRING:
+            VFPRINTF_vprintFormatArgA(fOut, pFormat, (CHAR *)va_arg(vaList, CHAR *));
+            break;
+        case VFMT_WCHAR:
+        {
+            WCHAR wch = (WCHAR)va_arg(vaList, INT);
+            CHAR *szArg = VFPRINTF_LPCWSTRToLPSTR(&wch, 1);
+            if (szArg)
+            {
+                VFPRINTF_vprintFormatArgA(fOut, pFormat, szArg);
+                MSVCRT_free(szArg);
+            }
+            break;
+        }
+        case VFMT_WSTRING:
+        {
+            CHAR *szArg = VFPRINTF_LPCWSTRToLPSTR((WCHAR *)va_arg(vaList, WCHAR *), -1);
+            if (szArg)
+            {
+                VFPRINTF_vprintFormatArgA(fOut, pFormat, szArg);
+                MSVCRT_free(szArg);
+            }
+            break;
+        }
+        default:
+            break;
+    }
+
+    return vaList;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printNoLeftAlignW
+ *      (internal, non-exported)
+ *
+ * Prints characters to a Unicode string that is not left-aligned
+ */
+static inline void VFPRINTF_printNoLeftAlignW(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat)
+{
+    int i;
+
+    if (!(pFormat->nFlags & VFPRINTF_LEFTALIGN))
+        for (i = pFormat->nPrecision; i < pFormat->nWidth; i++)
+            VFPRINTF_printCharW(fOut, ' ');
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printLeftAlignW
+ *      (internal, non-exported)
+ *
+ * Prints characters to left-align a Unicode string
+ */
+static inline void VFPRINTF_printLeftAlignW(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat)
+{
+    int i;
+
+    if (pFormat->nFlags & VFPRINTF_LEFTALIGN)
+        for (i = pFormat->nPrecision; i < pFormat->nWidth; i++)
+            VFPRINTF_printCharW(fOut, ' ');
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_printFormatW
+ *      (internal, non-exported)
+ *
+ * Prints a full Unicode format string to the required file/buffer
+ */
+static va_list VFPRINTF_printFormatW(VFPRINTF_FILE *fOut, VFPRINTF_PFORMAT pFormat, va_list vaList)
+{
+    switch (pFormat->nType)
+    {
+        case VFMT_POINTER:
+            VFPRINTF_vprintFormatArgW(fOut, pFormat, (VOID *)va_arg(vaList, VOID *));
+            break;
+        case VFMT_INT_LENGTH:
+        {
+            INT *p = va_arg(vaList, INT *);
+            *p = fOut->nThisLen;
+            break;
+        }
+        case VFMT_INTEGER:
+            VFPRINTF_vprintFormatArgW(fOut, pFormat, va_arg(vaList, INT));
+            break;
+        case VFMT_DOUBLE:
+            VFPRINTF_vprintFormatArgW(fOut, pFormat, va_arg(vaList, double));
+            break;
+        case VFMT_CHAR:
+            VFPRINTF_vprintFormatArgW(fOut, pFormat, (CHAR)va_arg(vaList, INT));
+            break;
+        case VFMT_STRING:
+            VFPRINTF_vprintFormatArgW(fOut, pFormat, (CHAR *)va_arg(vaList, CHAR *));
+            break;
+        case VFMT_WCHAR:
+            pFormat->nPrecision = 1;
+            VFPRINTF_printNoLeftAlignW(fOut, pFormat);
+            VFPRINTF_printCharW(fOut, (WCHAR)va_arg(vaList, INT));
+            VFPRINTF_printLeftAlignW(fOut, pFormat);
+            break;
+        case VFMT_WSTRING:
+        {
+            INT i;
+            INT nWidth = 0;
+            WCHAR *wszStr = (WCHAR *)va_arg(vaList, WCHAR *);
+
+            for (i = 0; !pFormat->nPrecision || (i < pFormat->nPrecision); i++)
+                if (!*(wszStr + i))
+                    break;
+            nWidth = (pFormat->nPrecision = i);
+            VFPRINTF_printNoLeftAlignW(fOut, pFormat);
+            VFPRINTF_nprintStringW(fOut, wszStr, nWidth);
+            VFPRINTF_printLeftAlignW(fOut, pFormat);
+            break;
+        }
+        default:
+            break;
+    }
+
+    return vaList;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrefixA
+ *      (internal, non-exported)
+ *
+ * Parses part of a ASCII format string
+ */
+static inline 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 Unicode format string
+ */
+static inline INT VFPRINTF_parseFormatPrefixW(LPCWSTR 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_parseFormatWidthA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for width specifiers
+ */
+static inline INT VFPRINTF_parseFormatWidthA(LPCSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    while ((*szFmt >= '0') && (*szFmt <= '9'))
+    {
+        CHAR cDigit = (CHAR)(*szFmt);
+        strncat(pFormat->szFmt, &cDigit, 1);
+        *pNum = (*pNum)*10 + cDigit - '0';
+        szFmt++;
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatWidthA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for width specifiers
+ */
+static inline INT VFPRINTF_parseFormatWidthW(LPCWSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    while ((*szFmt >= '0') && (*szFmt <= '9'))
+    {
+        CHAR cDigit = (CHAR)(*szFmt);
+        strncat(pFormat->szFmt, &cDigit, 1);
+        *pNum = (*pNum)*10 + cDigit - '0';
+        szFmt++;
+        nLen++;
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrecisionA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for precision specifiers
+ */
+static inline INT VFPRINTF_parseFormatPrecisionA(LPCSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '.')
+    {
+        strcat(pFormat->szFmt, ".");
+        nLen++;
+        szFmt++;
+        nLen += VFPRINTF_parseFormatWidthA(szFmt, pNum, pFormat);
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatPrecisionW
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for precision specifiers
+ */
+static inline INT VFPRINTF_parseFormatPrecisionW(LPCWSTR szFmt, UINT *pNum, VFPRINTF_PFORMAT pFormat)
+{
+    INT nLen = 0;
+
+    if (*szFmt == '.')
+    {
+        strcat(pFormat->szFmt, ".");
+        nLen++;
+        szFmt++;
+        nLen += VFPRINTF_parseFormatWidthW(szFmt, pNum, pFormat);
+    }
+
+    return nLen;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatFlagsA
+ *      (internal, non-exported)
+ *
+ * Parses part of a format string for flags
+ */
+static inline 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 format string for flags
+ */
+static inline 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 an ASCII format string for type specifiers
+ */
+inline INT VFPRINTF_parseFormatTypeA(LPCSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        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;
+        case 'd':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "d");
+            break;
+        case 'i':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "i");
+            break;
+        case 'o':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "o");
+            break;
+        case 'u':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "u");
+            break;
+        case 'X':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "X");
+            break;
+        case 'x':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "x");
+            break;
+        case 'E':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "E");
+            break;
+        case 'e':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "e");
+            break;
+        case 'f':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "f");
+            break;
+        case 'G':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "G");
+            break;
+        case 'g':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "g");
+            break;
+        case 'n':
+            pFormat->nType = VFMT_INT_LENGTH;
+            strcat(pFormat->szFmt, "n");
+            break;
+        case 'p':
+            pFormat->nType = VFMT_POINTER;
+            strcat(pFormat->szFmt, "p");
+            break;
+        case 'I':
+            if ((szFmt[1] == '6') && (szFmt[2] == '4'))
+            {
+                pFormat->nType = VFMT_INTEGER;
+                strcat(pFormat->szFmt, "i");
+                FIXME("I64 format type prefix is not fully supported\n");
+                break;
+            }
+        default:
+            pFormat->nType = VFMT_UNKNOWN;
+            TRACE("Unhandled format specifier %%[...]%c\n", *szFmt);
+            break;
+    }
+
+    return 1;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatTypeW
+ *      (internal, non-exported)
+ *
+ * Parses part of a Unicode format string for type specifiers
+ */
+inline INT VFPRINTF_parseFormatTypeW(LPCWSTR szFmt, VFPRINTF_PFORMAT pFormat)
+{
+    switch (*szFmt)
+    {
+        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;
+        case 'd':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "d");
+            break;
+        case 'i':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "i");
+            break;
+        case 'o':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "o");
+            break;
+        case 'u':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "u");
+            break;
+        case 'X':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "X");
+            break;
+        case 'x':
+            pFormat->nType = VFMT_INTEGER;
+            strcat(pFormat->szFmt, "x");
+            break;
+        case 'E':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "E");
+            break;
+        case 'e':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "e");
+            break;
+        case 'f':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "f");
+            break;
+        case 'G':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "G");
+            break;
+        case 'g':
+            pFormat->nType = VFMT_DOUBLE;
+            strcat(pFormat->szFmt, "g");
+            break;
+        case 'n':
+            pFormat->nType = VFMT_INT_LENGTH;
+            strcat(pFormat->szFmt, "n");
+            break;
+        case 'p':
+            pFormat->nType = VFMT_POINTER;
+            strcat(pFormat->szFmt, "p");
+            break;
+        case 'I':
+            if ((szFmt[1] == '6') && (szFmt[2] == '4'))
+            {
+                pFormat->nType = VFMT_INTEGER;
+                strcat(pFormat->szFmt, "i");
+                FIXME("I64 format type prefix is not fully supported\n");
+                break;
+            }
+        default:
+            pFormat->nType = VFMT_UNKNOWN;
+            TRACE("Unhandled format specifier %%[...]%c\n", *szFmt);
+            break;
+    }
+
+    return 1;
+}
+
+
+/*********************************************************************
+ *      VFPRINTF_parseFormatA
+ *      (internal, non-exported)
+ *
+ * Parses a ASCII format string
+ */
+static INT VFPRINTF_parseFormatA(LPCSTR szSpec, VFPRINTF_PFORMAT pFormat)
+{
+    LPCSTR szFmt = szSpec;
+
+    pFormat->szFmt[0] = '%';
+    pFormat->szFmt[1] = '\0';
+    pFormat->nFlags = 0;
+    pFormat->nWidth = 0;
+    pFormat->nPrecision = 0;
+
+    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 Unicode format string
+ */
+static INT VFPRINTF_parseFormatW(LPCWSTR szSpec, VFPRINTF_PFORMAT pFormat)
+{
+    LPCWSTR szFmt = szSpec;
+
+    pFormat->szFmt[0] = '%';
+    pFormat->szFmt[1] = '\0';
+    pFormat->nFlags = 0;
+    pFormat->nWidth = 0;
+    pFormat->nPrecision = 0;
+
+    szFmt += VFPRINTF_parseFormatPrefixW(szFmt, pFormat);
+    szFmt += VFPRINTF_parseFormatWidthW(szFmt, &(pFormat->nWidth), pFormat);
+    szFmt += VFPRINTF_parseFormatPrecisionW(szFmt, &(pFormat->nPrecision), pFormat);
+    szFmt += VFPRINTF_parseFormatFlagsW(szFmt, pFormat);
+    szFmt += VFPRINTF_parseFormatTypeW(szFmt, pFormat);
+
+    return (INT)(szFmt - szSpec);
+}
+
+
+/*********************************************************************
+ *      vfprintf (MSVCRT.@)
+ */
+int MSVCRT_vfprintf(MSVCRT_FILE *fFile, const char *szFormat, va_list vaList)
+{
+    VFPRINTF_FILE fOut;
+
+    fOut.fIOFile = fFile;
+    fOut.nBufLen = -1;
+    fOut.nTotLen = 0;
+    fOut.nThisLen = 0;
+
+    TRACE("(fFile == %p, szFormat == %s, ...)\n", fFile, debugstr_a(szFormat));
+
+    while (*szFormat)
+    {
+        if (*szFormat == '%')
+        {
+            if (*(++szFormat) != '%')
+            {
+                VFPRINTF_FORMAT fSpec;
+                szFormat += VFPRINTF_parseFormatA(szFormat, &fSpec);
+                vaList = VFPRINTF_printFormatA(&fOut, &fSpec, vaList);
+            }
+            else
+                szFormat += VFPRINTF_printCharA(&fOut, '%');
+        }
+        else
+            szFormat += VFPRINTF_printCharA(&fOut, *szFormat);
+    }
+
+    return fOut.nTotLen;
+}
+
+
+/*********************************************************************
+ *      vfwprintf (MSVCRT.@)
+ */
+int MSVCRT_vfwprintf(MSVCRT_FILE *fFile, const WCHAR *szFormat, va_list vaList)
+{
+    VFPRINTF_FILE fOut;
+
+    fOut.fIOFile = fFile;
+    fOut.nBufLen = -1;
+    fOut.nTotLen = 0;
+    fOut.nThisLen = 0;
+
+    TRACE("(fFile == %p, szFormat == %s, ...)\n", fFile, debugstr_w(szFormat));
+
+    while (*szFormat)
+    {
+        if (*szFormat == '%')
+        {
+            if (*(++szFormat) != '%')
+            {
+                VFPRINTF_FORMAT fSpec;
+                szFormat += VFPRINTF_parseFormatW(szFormat, &fSpec);
+                vaList = VFPRINTF_printFormatW(&fOut, &fSpec, vaList);
+            }
+            else
+                szFormat += VFPRINTF_printCharW(&fOut, '%');
+        }
+        else
+            szFormat += VFPRINTF_printCharW(&fOut, *szFormat);
+    }
+
+    return fOut.nTotLen;
+}


More information about the wine-patches mailing list