Bug #321: msvcrt-vfprintf-3.diff
Jaco Greeff
jaco at puxedo.org
Tue Oct 29 04:58:29 CST 2002
Ok, try number 3. I've made the changes as requested
* Get result length before allocating and copying with WideCharToMultiByte;
* Make intentions clear on strncat, replaced with strcat
* Removed CHAR castings to get the WCHAR formatting character.
* Fixes as requested by Dimitri and included in previous version;
The new improved version is attached to this mail. In addition, I've
compiled the MSDN sample at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_printf.2c_.wprintf.asp
and am including the results thereof after the changelog. Feel free to
compare this to the above URL. As always, comments are appreciated.
--
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 *printf[W]
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 11:40:14 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 == (WCHAR)L'-')
+ {
+ strcat(pFormat->szFmt, "-");
+ pFormat->nFlags |= VFPRINTF_LEFTALIGN;
+ szFmt += sizeof(WCHAR);
+ nLen++;
+ }
+ if (*szFmt == (WCHAR)L'#')
+ {
+ strcat(pFormat->szFmt, "#");
+ pFormat->nFlags |= VFPRINTF_PREFIX_HEX;
+ szFmt += sizeof(WCHAR);
+ nLen++;
+ }
+ if (*szFmt == (WCHAR)L'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 >= (WCHAR)L'0') && (*szFmt <= (WCHAR)L'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 - (WCHAR)L'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 == (WCHAR)L'.')
+ {
+ 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 (WCHAR)L'l':
+ pFormat->nFlags |= VFPRINTF_LONG;
+ return 1;
+ case (WCHAR)L'h':
+ pFormat->nFlags |= VFPRINTF_SHORT;
+ return 1;
+ case (WCHAR)L'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 (WCHAR)L'd': ADD_FORMAT_TYPE(VFMT_INTEGER, "d");
+ case (WCHAR)L'i': ADD_FORMAT_TYPE(VFMT_INTEGER, "i");
+ case (WCHAR)L'o': ADD_FORMAT_TYPE(VFMT_INTEGER, "o");
+ case (WCHAR)L'u': ADD_FORMAT_TYPE(VFMT_INTEGER, "u");
+ case (WCHAR)L'X': ADD_FORMAT_TYPE(VFMT_INTEGER, "X");
+ case (WCHAR)L'x': ADD_FORMAT_TYPE(VFMT_INTEGER, "x");
+ case (WCHAR)L'E': ADD_FORMAT_TYPE(VFMT_DOUBLE, "E");
+ case (WCHAR)L'e': ADD_FORMAT_TYPE(VFMT_DOUBLE, "e");
+ case (WCHAR)L'f': ADD_FORMAT_TYPE(VFMT_DOUBLE, "f");
+ case (WCHAR)L'G': ADD_FORMAT_TYPE(VFMT_DOUBLE, "G");
+ case (WCHAR)L'g': ADD_FORMAT_TYPE(VFMT_DOUBLE, "g");
+ case (WCHAR)L'n': ADD_FORMAT_TYPE(VFMT_INT_LENGTH, "n");
+ case (WCHAR)L'p': ADD_FORMAT_TYPE(VFMT_POINTER, "p");
+ case (WCHAR)L'c':
+ {
+ pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_CHAR : VFMT_WCHAR;
+ strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+ break;
+ }
+ case (WCHAR)L'C':
+ {
+ pFormat->nType = (pFormat->nFlags & VFPRINTF_LONG) ? VFMT_WCHAR : VFMT_CHAR;
+ strcat(pFormat->szFmt, (pFormat->nType == VFMT_WCHAR) ? "s" : "c");
+ break;
+ }
+
+ case (WCHAR)L's':
+ {
+ pFormat->nType = (pFormat->nFlags & VFPRINTF_SHORT) ? VFMT_STRING : VFMT_WSTRING;
+ strcat(pFormat->szFmt, "s");
+ break;
+ }
+ case (WCHAR)L'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 (WCHAR)L'%':
+ {
+ 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