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