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@puxedo.org> - Cater for the %C and %S formatting characters in all the *printf[W] functions. (Both widechar and multibyte versions) -- [jaco@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
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; +} +