msvcrt-A02: vfprintf/vfwprintf

Jaco Greeff jaco at puxedo.org
Sun Nov 3 09:37:03 CST 2002


This msvcrt-A?? series patch implements the full vfprintf
(ASCII) and vfwprintf (Unicode) functions.

License:
LGPL

Changelog:
* dlls/msvcrt/vfprintf.c:
Jaco Greeff <jaco at puxedo.org>
- Implementation of the vfprintf/vfwprintf functions to allow
for the Microsoft format specifier extentions, %C and %S
- Full implementation of vfwprintf to actually output Unicode
strings, instead of the ASCII strings printed before

--[ inline patch ]--

diff -aurN msvcrt-A01/dlls/msvcrt/vfprintf.c msvcrt-A02/dlls/msvcrt/vfprintf.c
--- msvcrt-A01/dlls/msvcrt/vfprintf.c	2002-11-03 11:23:45.000000000 +0000
+++ msvcrt-A02/dlls/msvcrt/vfprintf.c	2002-11-03 11:43:18.000000000 +0000
@@ -38,60 +38,946 @@
 
 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 (MSVCRT.@)
+ *      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)
  *
- * FIXME: We don't handle the Microsoft format flag extentions
- * %C and %S at all
+ * 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)
 {
-    char buf[2048], *mem = buf;
-    int written, resize = sizeof(buf), retval;
+    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);
+    }
 
-    /* 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, szFormat, 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, fFile);
-    if (mem != buf)
-        MSVCRT_free (mem);
-    return retval;
+    return fOut.nTotLen;
 }
 
+
 /*********************************************************************
  *      vfwprintf (MSVCRT.@)
- *
- * FIXME: We don't handle the Microsoft format flag extentions
- * %C and %S at all
  */
 int MSVCRT_vfwprintf(MSVCRT_FILE *fFile, const WCHAR *szFormat, va_list vaList)
 {
-    WCHAR buf[2048], *mem = buf;
-    int written, resize = sizeof(buf) / sizeof(WCHAR), retval;
+    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);
+    }
 
-    /* See vfprintf comments */
-    while ((written = _vsnwprintf(mem, resize, szFormat, 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, fFile);
-    if (mem != buf)
-        MSVCRT_free (mem);
-    return retval;
+    return fOut.nTotLen;
 }




More information about the wine-patches mailing list