summaryrefslogtreecommitdiff
path: root/src/pal/src/cruntime/printfcpp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/cruntime/printfcpp.cpp')
-rw-r--r--src/pal/src/cruntime/printfcpp.cpp2556
1 files changed, 2556 insertions, 0 deletions
diff --git a/src/pal/src/cruntime/printfcpp.cpp b/src/pal/src/cruntime/printfcpp.cpp
new file mode 100644
index 0000000000..ea074a604b
--- /dev/null
+++ b/src/pal/src/cruntime/printfcpp.cpp
@@ -0,0 +1,2556 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ printfcpp.cpp
+
+Abstract:
+
+ Implementation of suspension safe printf functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+#include "pal/printfcpp.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+using namespace CorUnix;
+
+int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap);
+int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap);
+int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap);
+int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap);
+
+extern "C"
+{
+
+/*******************************************************************************
+Function:
+ Internal_Convertfwrite
+ This function is a wrapper around fwrite for cases where the buffer has
+ to be converted from WideChar to MultiByte
+*******************************************************************************/
+
+static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, size_t size, size_t count, FILE *stream, BOOL convert)
+{
+ int ret;
+ int iError = 0;
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream);
+#endif
+
+ if(convert)
+ {
+ int nsize;
+ LPSTR newBuff = 0;
+ nsize = WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)buffer, count, 0, 0, 0, 0);
+ if (!nsize)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError());
+ return -1;
+ }
+ newBuff = (LPSTR) InternalMalloc(nsize);
+ if (!newBuff)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ nsize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)buffer, count, newBuff, nsize, 0, 0);
+ if (!nsize)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError());
+ free(newBuff);
+ return -1;
+ }
+ ret = InternalFwrite(newBuff, 1, count, stream, &iError);
+ if (iError != 0)
+ {
+ ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
+ free(newBuff);
+ return -1;
+ }
+ free(newBuff);
+ }
+ else
+ {
+ ret = InternalFwrite(buffer, size, count, stream, &iError);
+ if (iError != 0)
+ {
+ ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
+ return -1;
+ }
+ }
+ return ret;
+
+}
+
+/*******************************************************************************
+Function:
+ Internal_ExtractFormatA
+
+Paramaters:
+ Fmt
+ - format string to parse
+ - first character must be a '%'
+ - paramater gets updated to point to the character after
+ the %<foo> format string
+ Out
+ - buffer will contain the %<foo> format string
+ Flags
+ - paramater will be set with the PRINTF_FORMAT_FLAGS defined above
+ Width
+ - will contain the width specified by the format string
+ - -1 if none given
+ Precision
+ - will contain the precision specified in the format string
+ - -1 if none given
+ Prefix
+ - an enumeration of the type prefix
+ Type
+ - an enumeration of the type value
+
+Notes:
+ - I'm also handling the undocumented %ws, %wc, %w...
+ - %#10x, when we have a width greater than the length (i.e padding) the
+ length of the padding is not consistent with MS's wsprintf
+ (MS adds an extra 2 padding chars, length of "0x")
+ - MS's wsprintf seems to ingore a 'h' prefix for number types
+ - MS's "%p" is different than gcc's
+ e.g. printf("%p", NULL);
+ MS --> 00000000
+ gcc --> 0x0
+ - the length of the exponent (precision) for floating types is different
+ between MS and gcc
+ e.g. printf("%E", 256.0);
+ MS --> 2.560000E+002
+ gcc --> 2.560000E+02
+*******************************************************************************/
+BOOL Internal_ExtractFormatA(CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LPINT Flags,
+ LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = WIDTH_DEFAULT;
+ *Precision = PRECISION_DEFAULT;
+ *Flags = PFF_NONE;
+ *Prefix = PFF_PREFIX_DEFAULT;
+ *Type = PFF_TYPE_DEFAULT;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) InternalMalloc(strlen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse flags */
+ while (**Fmt && (**Fmt == '-' || **Fmt == '+' ||
+ **Fmt == '0' || **Fmt == ' ' || **Fmt == '#'))
+ {
+ switch (**Fmt)
+ {
+ case '-':
+ *Flags |= PFF_MINUS; break;
+ case '+':
+ *Flags |= PFF_PLUS; break;
+ case '0':
+ *Flags |= PFF_ZERO; break;
+ case ' ':
+ *Flags |= PFF_SPACE; break;
+ case '#':
+ *Flags |= PFF_POUND; break;
+ }
+ *Out++ = *(*Fmt)++;
+ }
+ /* '-' flag negates '0' flag */
+ if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO))
+ {
+ *Flags -= PFF_ZERO;
+ }
+
+ /* grab width specifier */
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Width = WIDTH_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid width because we have a * then a number */
+ /* printf handles this by just printing the whole string */
+ *Width = WIDTH_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+
+
+ /* grab precision specifier */
+ if (**Fmt == '.')
+ {
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Precision = atoi(TempStr);
+ if (*Precision < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Precision = PRECISION_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid precision because we have a .* then a number */
+ /* printf handles this by just printing the whole string */
+ *Precision = PRECISION_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+ else
+ {
+ *Precision = PRECISION_DOT;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+#endif
+ if ((*Fmt)[0] == 'I')
+ {
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Fmt += 3;
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+ /* grab prefix of 'I32' for __int32 */
+ else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2')
+ {
+ *Fmt += 3;
+ }
+ else
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Prefix = PFF_PREFIX_LONGLONG;
+ #endif
+ }
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = PFF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+#ifdef BIT64
+ // Only want to change the prefix on 64 bit when printing characters.
+ if (**Fmt == 'c' || **Fmt == 's')
+#endif
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = PFF_TYPE_CHAR;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S')
+ {
+ *Type = PFF_TYPE_STRING;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X')
+ {
+ *Type = PFF_TYPE_INT;
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ else if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ *Type = PFF_TYPE_FLOAT;
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = PFF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'p')
+ {
+ *Type = PFF_TYPE_P;
+ (*Fmt)++;
+
+ if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 16;
+ *Out++ = '.';
+ *Out++ = '1';
+ *Out++ = '6';
+ }
+ /* native *printf does not support %I64p
+ (actually %llp), so we need to cheat a little bit */
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ else
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 8;
+ *Out++ = '.';
+ *Out++ = '8';
+ }
+ }
+ *Out++ = 'X';
+ Result = TRUE;
+ }
+
+ *Out = 0; /* end the string */
+ free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ Internal_ExtractFormatW
+
+ -- see Internal_ExtractFormatA above
+*******************************************************************************/
+BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, LPINT Flags,
+ LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = WIDTH_DEFAULT;
+ *Precision = PRECISION_DEFAULT;
+ *Flags = PFF_NONE;
+ *Prefix = PFF_PREFIX_DEFAULT;
+ *Type = PFF_TYPE_DEFAULT;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) InternalMalloc(PAL_wcslen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse flags */
+ while (**Fmt && (**Fmt == '-' || **Fmt == '+' ||
+ **Fmt == '0' || **Fmt == ' ' || **Fmt == '#'))
+ {
+ switch (**Fmt)
+ {
+ case '-':
+ *Flags |= PFF_MINUS; break;
+ case '+':
+ *Flags |= PFF_PLUS; break;
+ case '0':
+ *Flags |= PFF_ZERO; break;
+ case ' ':
+ *Flags |= PFF_SPACE; break;
+ case '#':
+ *Flags |= PFF_POUND; break;
+ }
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ /* '-' flag negates '0' flag */
+ if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO))
+ {
+ *Flags -= PFF_ZERO;
+ }
+
+ /* grab width specifier */
+ if (isdigit(**Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit(**Fmt))
+ {
+ *TempStrPtr++ = (CHAR) **Fmt;
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Width = WIDTH_STAR;
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ /* this is an invalid width because we have a * then a number */
+ /* printf handles this by just printing the whole string */
+ *Width = WIDTH_INVALID;
+ while (isdigit(**Fmt))
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ }
+ }
+
+ /* grab precision specifier */
+ if (**Fmt == '.')
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit(**Fmt))
+ {
+ *TempStrPtr++ = (CHAR) **Fmt;
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Precision = atoi(TempStr);
+ if (*Precision < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Precision = PRECISION_STAR;
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ /* this is an invalid precision because we have a .* then a number */
+ /* printf handles this by just printing the whole string */
+ *Precision = PRECISION_INVALID;
+ while (isdigit(**Fmt))
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ }
+ }
+ else
+ {
+ *Precision = PRECISION_DOT;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+#endif
+ if ((*Fmt)[0] == 'I')
+ {
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Fmt += 3;
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+ /* grab prefix of 'I32' for __int32 */
+ else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2')
+ {
+ *Fmt += 3;
+ }
+ else
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Prefix = PFF_PREFIX_LONGLONG;
+ #endif
+ }
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = PFF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ // Only want to change the prefix on 64 bit when printing characters.
+ if (**Fmt == 'C' || **Fmt == 'S')
+#endif
+ {
+ *Prefix = PFF_PREFIX_LONG_W;
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = PFF_TYPE_CHAR;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'c')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Out++ = 'l';
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S' )
+ {
+ if ( **Fmt == 'S' )
+ {
+ *Type = PFF_TYPE_WSTRING;
+ }
+ else
+ {
+ *Type = PFF_TYPE_STRING;
+ }
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 's')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X')
+ {
+ *Type = PFF_TYPE_INT;
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Out++ = 'l';
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ else if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+
+ *Type = PFF_TYPE_FLOAT;
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = PFF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'p')
+ {
+ *Type = PFF_TYPE_P;
+ (*Fmt)++;
+
+ if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 16;
+ *Out++ = '.';
+ *Out++ = '1';
+ *Out++ = '6';
+ }
+ /* native *printf does not support %I64p
+ (actually %llp), so we need to cheat a little bit */
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ else
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 8;
+ *Out++ = '.';
+ *Out++ = '8';
+ }
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ }
+ *Out++ = 'X';
+ Result = TRUE;
+ }
+
+ *Out = 0; /* end the string */
+ free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingW
+
+Parameters:
+ Out
+ - buffer to place padding and given string (In)
+ Count
+ - maximum chars to be copied so as not to overrun given buffer
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+
+BOOL Internal_AddPaddingW(LPWSTR *Out, INT Count, LPWSTR In, INT Padding, INT Flags)
+{
+ LPWSTR OutOriginal = *Out;
+ INT PaddingOriginal = Padding;
+ INT LengthInStr;
+ LengthInStr = PAL_wcslen(In);
+
+
+ if (Padding < 0)
+ {
+ /* this is used at the bottom to determine if the buffer ran out */
+ PaddingOriginal = 0;
+ }
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (wcsncpy_s(*Out, Count, In, min(LengthInStr + 1, Count - 1)) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count - 1);
+ }
+ if (Padding > 0)
+ {
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = '0';
+ }
+ }
+ else /* pad left with spaces */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (wcsncpy_s(*Out, Count - (*Out - OutOriginal), In,
+ min(LengthInStr, Count - (*Out - OutOriginal) - 1)) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count - (*Out - OutOriginal) - 1);
+ }
+
+ if (LengthInStr + PaddingOriginal > Count - 1)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingVfprintf
+
+Parameters:
+ stream
+ - file stream to place padding and given string (In)
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+
+INT Internal_AddPaddingVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPSTR In,
+ INT Padding, INT Flags)
+{
+ LPSTR Out;
+ INT LengthInStr;
+ INT Length;
+ LPSTR OutOriginal;
+ INT Written;
+
+ LengthInStr = strlen(In);
+ Length = LengthInStr;
+
+ if (Padding > 0)
+ {
+ Length += Padding;
+ }
+ Out = (LPSTR) InternalMalloc(Length+1);
+ int iLength = Length+1;
+ if (!Out)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ OutOriginal = Out;
+
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLength -= LengthInStr;
+ }
+ if (Padding > 0)
+ {
+ iLength -= Padding;
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding--)
+ {
+ *Out++ = '0';
+ }
+ }
+ else /* pad with spaces */
+ {
+ while (Padding--)
+ {
+ *Out++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLength -= LengthInStr;
+ }
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream->bsdFilePtr);
+#endif
+
+ Written = InternalFwrite(OutOriginal, 1, Length, stream->bsdFilePtr, &stream->PALferrorCode);
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ }
+
+Done:
+ free(OutOriginal);
+
+ return Written;
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingVfwprintf
+
+Parameters:
+ stream
+ - file stream to place padding and given string (In)
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+static INT Internal_AddPaddingVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPWSTR In,
+ INT Padding, INT Flags,BOOL convert)
+{
+ LPWSTR Out;
+ LPWSTR OutOriginal;
+ INT LengthInStr;
+ INT Length;
+ INT Written = 0;
+
+ LengthInStr = PAL_wcslen(In);
+ Length = LengthInStr;
+
+ if (Padding > 0)
+ {
+ Length += Padding;
+ }
+
+ int iLen = (Length+1);
+ Out = (LPWSTR) InternalMalloc(iLen * sizeof(WCHAR));
+ if (!Out)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ OutOriginal = Out;
+
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("wcscpy_s failed!\n");
+ free(OutOriginal);
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+ if (Padding > 0)
+ {
+ iLen -= Padding;
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding--)
+ {
+ *Out++ = '0';
+ }
+ }
+ else /* pad with spaces */
+ {
+ while (Padding--)
+ {
+ *Out++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("wcscpy_s failed!\n");
+ free(OutOriginal);
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+
+ if (Length > 0) {
+ Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(wchar_16), Length,
+ (FILE*)(stream->bsdFilePtr), convert);
+
+ if (-1 == Written)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ }
+ free(OutOriginal);
+ }
+
+ return Written;
+}
+
+/*******************************************************************************
+Function:
+ PAL_vsnprintf
+
+Parameters:
+ Buffer
+ - out buffer
+ Count
+ - buffer size
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL__vsnprintf(LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap)
+{
+ LONG Length;
+
+ PERF_ENTRY(PAL__vsnprintf);
+ ENTRY("PAL__vsnprintf (buffer=%p, count=%d, format=%p (%s), argptr=%p)\n",
+ Buffer, Count, Format, Format, ap);
+
+ Length = CoreVsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap);
+
+ LOGEXIT("PAL__vsnprintf returns int %d\n", Length);
+ PERF_EXIT(PAL__vsnprintf);
+
+ return Length;
+}
+
+/*******************************************************************************
+Function:
+ PAL_wvsnprintf
+
+ -- see PAL_vsnprintf above
+*******************************************************************************/
+
+int __cdecl PAL__wvsnprintf(LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap)
+{
+ return CoreWvsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap);
+}
+
+/*******************************************************************************
+Function:
+ PAL_vfprintf
+
+Parameters:
+ stream
+ - out stream
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap)
+{
+ return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap);
+}
+
+/*******************************************************************************
+Function:
+ PAL_vfwprintf
+
+Parameters:
+ stream
+ - out stream
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL_vfwprintf(PAL_FILE *stream, const wchar_16 *format, va_list ap)
+{
+ return CoreVfwprintf(InternalGetCurrentThread(), stream, format, ap);
+}
+
+} // end extern "C"
+
+int CorUnix::InternalWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap)
+{
+ return CoreWvsnprintf(pthrCurrent, Buffer, Count, Format, ap);
+}
+
+int CorUnix::InternalVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap)
+{
+ return CoreVsnprintf(pthrCurrent, Buffer, Count, Format, ap);
+}
+
+int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap)
+{
+ return CoreVfprintf(pthrCurrent, stream, format, ap);
+}
+
+int CorUnix::InternalVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap)
+{
+ return CoreVfwprintf(pthrCurrent, stream, format, ap);
+}
+
+int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list aparg)
+{
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPCWSTR Fmt = format;
+ LPWSTR TempWStr = NULL;
+ LPWSTR WorkingWStr = NULL;
+ WCHAR TempWChar[2];
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT TempInt;
+ BOOL WStrWasMalloced = FALSE;
+ int mbtowcResult;
+ int written=0;
+ int paddingReturnValue;
+ int ret;
+ va_list ap;
+
+ /* fwprintf for now in the PAL is always used on file opened
+ in text mode. In those case the output should be ANSI not Unicode */
+ BOOL textMode = TRUE;
+
+ PERF_ENTRY(vfwprintf);
+ ENTRY("vfwprintf (stream=%p, format=%p (%S))\n",
+ stream, format, format);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) &&
+ (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) ||
+ (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0))
+ {
+ WStrWasMalloced = FALSE;
+
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W)
+ {
+ TempWStr = va_arg(ap, LPWSTR);
+ }
+ else
+ {
+ /* %lS assumes a LPSTR argument. */
+ LPSTR s = va_arg(ap, LPSTR );
+ UINT Length = 0;
+ Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
+ if ( Length != 0 )
+ {
+ TempWStr =
+ (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) );
+ if ( TempWStr )
+ {
+ WStrWasMalloced = TRUE;
+ MultiByteToWideChar( CP_ACP, 0, s, -1,
+ TempWStr, Length );
+ }
+ else
+ {
+ ERROR( "InternalMalloc failed.\n" );
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ }
+ else
+ {
+ ASSERT( "Unable to convert from multibyte "
+ " to wide char.\n" );
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ }
+
+ INT Length = PAL_wcslen(TempWStr);
+ WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1)));
+ if (!WorkingWStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *WorkingWStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length)
+ {
+ if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("wcsncpy_s failed!\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (-1);
+ }
+
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ PAL_wcscpy(WorkingWStr, TempWStr);
+ }
+
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr,
+ Width - Length,
+ Flags,textMode);
+
+ if (paddingReturnValue == -1)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (-1);
+ }
+ written += paddingReturnValue;
+
+ free(WorkingWStr);
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar[0] = va_arg(ap, int);
+ TempWChar[1] = 0;
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar,
+ Width - 1,
+ Flags,textMode);
+ if (paddingReturnValue == -1)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return(-1);
+ }
+ written += paddingReturnValue;
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = written;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = written;
+ }
+ }
+ else
+ {
+ // Types that sprintf can handle.
+
+ /* note: I'm using the wide buffer as a (char *) buffer when I
+ pass it to sprintf(). After I get the buffer back I make a
+ backup of the chars copied and then convert them to wide
+ and place them in the buffer (BufferPtr) */
+
+ // This argument will be limited to 1024 characters.
+ // It should be enough.
+ size_t TEMP_COUNT = 1024;
+ char TempSprintfStrBuffer[1024];
+ char *TempSprintfStrPtr = NULL;
+ char *TempSprintfStr = TempSprintfStrBuffer;
+ LPWSTR TempWideBuffer;
+
+ TempInt = 0;
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ snprintf(TempSprintfStr, TempInt, TempBuff, trunc2);
+ }
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ snprintf(TempSprintfStr, TempInt, TempBuff, s);
+ }
+ }
+ else
+ {
+ va_list apcopy;
+
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf(TempSprintfStr, TEMP_COUNT, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ va_copy(apcopy, ap);
+ vsnprintf(TempSprintfStr, TempInt, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempSprintfStr, -1,
+ NULL, 0);
+
+ if (mbtowcResult == 0)
+ {
+ ERROR("MultiByteToWideChar failed\n");
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+
+ TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR));
+ if (!TempWideBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ va_end(ap);
+ return -1;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1,
+ TempWideBuffer, mbtowcResult);
+
+ ret = Internal_Convertfwrite(
+ pthrCurrent,
+ TempWideBuffer,
+ sizeof(wchar_16),
+ mbtowcResult-1,
+ (FILE*)stream->bsdFilePtr,
+ textMode);
+
+ if (-1 == ret)
+ {
+ ERROR("fwrite() failed with errno == %d (%s)\n", errno, strerror(errno));
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ free(TempWideBuffer);
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ free(TempWideBuffer);
+ }
+ }
+ else
+ {
+ ret = Internal_Convertfwrite(
+ pthrCurrent,
+ Fmt++,
+ sizeof(wchar_16),
+ 1,
+ (FILE*)stream->bsdFilePtr,
+ textMode); /* copy regular chars into buffer */
+
+ if (-1 == ret)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ ++written;
+ }
+ }
+
+ LOGEXIT("vfwprintf returns int %d\n", written);
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (written);
+}
+
+int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list aparg)
+{
+ BOOL BufferRanOut = FALSE;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPSTR BufferPtr = Buffer;
+ LPCSTR Fmt = Format;
+ LPWSTR TempWStr;
+ LPSTR TempStr;
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ va_list ap;
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int
+ {
+ BufferRanOut = TRUE;
+ break;
+ }
+ else if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0,
+ 0, 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ va_end(ap);
+ return -1;
+ }
+ TempStr = (LPSTR) InternalMalloc(Length);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr,
+ Precision, TempStr, Length,
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1,
+ TempStr, Length, 0, 0);
+ if (!wctombResult)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempStr,
+ Width - Length,
+ Flags);
+
+ free(TempStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[5];
+
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1,
+ TempBuffer, sizeof(TempBuffer),
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempBuffer,
+ Width - Length,
+ Flags);
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = BufferPtr - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
+ }
+ }
+ else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded chars,
+ // so we handle them here.
+ char ch[2];
+
+ ch[0] = (char) va_arg(ap, int);
+ ch[1] = '\0';
+ Length = 1;
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ ch,
+ Width - Length,
+ Flags);
+ }
+ else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded strings,
+ // so we handle them here.
+ char *tempStr;
+
+ tempStr = va_arg(ap, char *);
+ Length = strlen(tempStr);
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ tempStr,
+ Width - Length,
+ Flags);
+ }
+ else
+ {
+ // Types that sprintf can handle
+ size_t TempCount = Count - (BufferPtr - Buffer);
+
+#if !HAVE_LARGE_SNPRINTF_SUPPORT
+ // Limit TempCount to 0x40000000, which is sufficient
+ // for platforms on which snprintf fails for very large
+ // sizes.
+ if (TempCount > 0x40000000)
+ {
+ TempCount = 0x40000000;
+ }
+#endif // HAVE_LARGE_SNPRINTF_SUPPORT
+
+ TempInt = 0;
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short) trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf(BufferPtr, TempCount, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */
+ {
+ BufferPtr += TempCount;
+ BufferRanOut = TRUE;
+ }
+ else
+ {
+ BufferPtr += TempInt;
+ }
+ }
+ }
+ else
+ {
+ *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
+ }
+ }
+
+ if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int
+ {
+ *BufferPtr = 0; /* end the string */
+ }
+
+ va_end(ap);
+
+ if (BufferRanOut)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+ else
+ {
+ return BufferPtr - Buffer;
+ }
+}
+
+int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list aparg)
+{
+ BOOL BufferRanOut = FALSE;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPWSTR BufferPtr = Buffer;
+ LPCWSTR Fmt = Format;
+ LPWSTR TempWStr = NULL;
+ LPWSTR WorkingWStr = NULL;
+ WCHAR TempWChar[2];
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT TempInt;
+ LPSTR TempNumberBuffer;
+ int mbtowcResult;
+ va_list(ap);
+
+ PERF_ENTRY(wvsnprintf);
+ ENTRY("wvsnprintf (buffer=%p, count=%u, format=%p (%S))\n",
+ Buffer, Count, Format, Format);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int
+ {
+ BufferRanOut = TRUE;
+ break;
+ }
+ else if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) &&
+ (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) ||
+ (Prefix == PFF_PREFIX_SHORT && Type == PFF_TYPE_STRING) ||
+ (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0))
+ {
+ BOOL needToFree = FALSE;
+
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if ((Type == PFF_TYPE_STRING && Prefix == PFF_PREFIX_LONG) ||
+ Prefix == PFF_PREFIX_LONG_W)
+ {
+ TempWStr = va_arg(ap, LPWSTR);
+ }
+ else
+ {
+ // %lS and %hs assume an LPSTR argument.
+ LPSTR s = va_arg(ap, LPSTR );
+ UINT Length = 0;
+ Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
+ if ( Length != 0 )
+ {
+ TempWStr =
+ (LPWSTR)InternalMalloc((Length + 1 ) * sizeof( WCHAR ) );
+ if ( TempWStr )
+ {
+ needToFree = TRUE;
+ MultiByteToWideChar( CP_ACP, 0, s, -1,
+ TempWStr, Length );
+ }
+ else
+ {
+ ERROR( "InternalMalloc failed.\n" );
+ va_end(ap);
+ return -1;
+ }
+ }
+ else
+ {
+ ASSERT( "Unable to convert from multibyte "
+ " to wide char.\n" );
+ va_end(ap);
+ return -1;
+ }
+
+ }
+
+ INT Length = PAL_wcslen(TempWStr);
+ WorkingWStr = (LPWSTR) InternalMalloc(sizeof(WCHAR) * (Length + 1));
+ if (!WorkingWStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ // Copy nothing
+ *WorkingWStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length)
+ {
+ if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS)
+ {
+ ERROR("CoreWvsnprintf failed\n");
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("wcsncpy_s failed!\n");
+ PERF_EXIT(wvsnprintf);
+ va_end(ap);
+ return (-1);
+ }
+
+ Length = Precision;
+ }
+ else
+ {
+ // Copy everything
+ PAL_wcscpy(WorkingWStr, TempWStr);
+ }
+
+ // Add padding if needed.
+ BufferRanOut = !Internal_AddPaddingW(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ WorkingWStr,
+ Width - Length,
+ Flags);
+
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar[0] = va_arg(ap, int);
+ TempWChar[1] = 0;
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingW(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempWChar,
+ Width - 1,
+ Flags);
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = BufferPtr - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
+ }
+ }
+ else
+ {
+ // Types that sprintf can handle
+
+ /* note: I'm using the wide buffer as a (char *) buffer when I
+ pass it to sprintf(). After I get the buffer back I make a
+ backup of the chars copied and then convert them to wide
+ and place them in the buffer (BufferPtr) */
+ size_t TempCount = Count - (BufferPtr - Buffer);
+ TempInt = 0;
+
+#if !HAVE_LARGE_SNPRINTF_SUPPORT
+ // Limit TempCount to 0x40000000, which is sufficient
+ // for platforms on which snprintf fails for very large
+ // sizes.
+ if (TempCount > 0x40000000)
+ {
+ TempCount = 0x40000000;
+ }
+#endif // HAVE_LARGE_SNPRINTF_SUPPORT
+
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf((LPSTR) BufferPtr, TempCount, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (TempInt == 0)
+ {
+ // The argument is "".
+ continue;
+ }
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */
+ {
+ TempNumberBuffer = (LPSTR) InternalMalloc(TempCount+1);
+ if (!TempNumberBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ errno = ENOMEM;
+ va_end(ap);
+ return -1;
+ }
+
+ if (strncpy_s(TempNumberBuffer, TempCount+1, (LPSTR) BufferPtr, TempCount) != SAFECRT_SUCCESS)
+ {
+ ASSERT("strncpy_s failed!\n");
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempNumberBuffer,
+ TempCount,
+ BufferPtr, TempCount);
+ if (!mbtowcResult)
+ {
+ ASSERT("MultiByteToWideChar failed. Error is %d\n",
+ GetLastError());
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+ BufferPtr += TempCount;
+ BufferRanOut = TRUE;
+ }
+ else
+ {
+ TempNumberBuffer = (LPSTR) InternalMalloc(TempInt+1);
+ if (!TempNumberBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ if (strncpy_s(TempNumberBuffer, TempInt+1, (LPSTR) BufferPtr, TempInt) != SAFECRT_SUCCESS)
+ {
+ ASSERT("strncpy_s failed!\n");
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempNumberBuffer,
+ TempInt,
+ BufferPtr, TempInt);
+ if (!mbtowcResult)
+ {
+ ASSERT("MultiByteToWideChar failed. Error is %d\n",
+ GetLastError());
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+ BufferPtr += TempInt;
+ }
+ free(TempNumberBuffer);
+ }
+ }
+ else
+ {
+ *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
+ }
+ }
+
+ if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int
+ {
+ *BufferPtr = 0; /* end the string */
+ }
+
+ va_end(ap);
+
+ if (BufferRanOut)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+ else
+ {
+ return BufferPtr - Buffer;
+ }
+}
+
+int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list aparg)
+{
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPCSTR Fmt = format;
+ LPWSTR TempWStr;
+ LPSTR TempStr;
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ int written = 0;
+ int paddingReturnValue;
+ va_list ap;
+
+ PERF_ENTRY(vfprintf);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0,
+ 0, 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempStr = (LPSTR) InternalMalloc(Length);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr,
+ Precision, TempStr, Length,
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1,
+ TempStr, Length, 0, 0);
+ if (!wctombResult)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfprintf(pthrCurrent, stream, TempStr,
+ Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ free(TempStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[5];
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1,
+ TempBuffer, sizeof(TempBuffer),
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfprintf(pthrCurrent, stream, TempBuffer,
+ Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = written;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = written;
+ }
+ }
+ else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of fprintf don't support 0-padded chars,
+ // so we handle them here.
+ char ch[2];
+
+ ch[0] = (char) va_arg(ap, int);
+ ch[1] = '\0';
+ Length = 1;
+ paddingReturnValue = Internal_AddPaddingVfprintf(
+ pthrCurrent,
+ stream,
+ ch,
+ Width - Length,
+ Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+ }
+ else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of fprintf don't support 0-padded strings,
+ // so we handle them here.
+ char *tempStr;
+
+ tempStr = va_arg(ap, char *);
+ Length = strlen(tempStr);
+ paddingReturnValue = Internal_AddPaddingVfprintf(
+ pthrCurrent,
+ stream,
+ tempStr,
+ Width - Length,
+ Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+ }
+ else
+ {
+ // Types that fprintf can handle.
+ TempInt = 0;
+
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = fprintf(stream->bsdFilePtr, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = fprintf( stream->bsdFilePtr, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vfprintf(stream->bsdFilePtr, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (-1 == TempInt)
+ {
+ ERROR("vfprintf returned an error\n");
+ }
+ else
+ {
+ written += TempInt;
+ }
+ }
+ }
+ else
+ {
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream->bsdFilePtr);
+#endif
+
+ InternalFwrite(Fmt++, 1, 1, stream->bsdFilePtr, &stream->PALferrorCode); /* copy regular chars into buffer */
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ ++written;
+ }
+ }
+
+ va_end(ap);
+
+ PERF_EXIT(vfprintf);
+ return written;
+}