blob: d0c35bf6527d5ab61a52240636283536cdf3ca43 [file]
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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 char16_t *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());
InternalFree(newBuff);
return -1;
}
ret = InternalFwrite(newBuff, 1, nsize, stream, &iError);
if (iError != 0)
{
ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
InternalFree(newBuff);
return -1;
}
InternalFree(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 */
InternalFree(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 */
InternalFree(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:
InternalFree(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");
InternalFree(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");
InternalFree(OutOriginal);
pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
return -1;
}
Out += LengthInStr;
iLen -= LengthInStr;
}
if (Length > 0) {
Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(char16_t), Length,
(FILE*)(stream->bsdFilePtr), convert);
if (-1 == Written)
{
ERROR("fwrite() failed with errno == %d\n", errno);
}
}
InternalFree(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)
{
return CoreVsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap);
}
/*******************************************************************************
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 char16_t *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 char16_t *format, va_list ap)
{
return CoreVfwprintf(pthrCurrent, stream, format, ap);
}
int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char16_t *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)
{
InternalFree(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)
{
InternalFree(TempWStr);
}
InternalFree(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)
{
InternalFree(TempWStr);
}
InternalFree(WorkingWStr);
LOGEXIT("vfwprintf returns int -1\n");
PERF_EXIT(vfwprintf);
va_end(ap);
return (-1);
}
written += paddingReturnValue;
InternalFree(WorkingWStr);
if (WStrWasMalloced)
{
InternalFree(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)
{
InternalFree(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)
{
InternalFree(TempSprintfStrPtr);
}
va_end(ap);
return -1;
}
MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1,
TempWideBuffer, mbtowcResult);
ret = Internal_Convertfwrite(
pthrCurrent,
TempWideBuffer,
sizeof(char16_t),
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);
InternalFree(TempWideBuffer);
if(TempSprintfStrPtr)
{
InternalFree(TempSprintfStrPtr);
}
va_end(ap);
return -1;
}
if(TempSprintfStrPtr)
{
InternalFree(TempSprintfStrPtr);
}
InternalFree(TempWideBuffer);
}
}
else
{
ret = Internal_Convertfwrite(
pthrCurrent,
Fmt++,
sizeof(char16_t),
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());
InternalFree(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());
InternalFree(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);
InternalFree(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);
BOOL precisionSet = false;
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);
precisionSet = true;
}
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 = 0;
if (precisionSet)
{
for(; Length <= Precision && TempWStr[Length] != 0; Length++);
}
else
{
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)
{
InternalFree(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) != SAFECRT_SUCCESS)
{
ERROR("CoreWvsnprintf failed\n");
if (needToFree)
{
InternalFree(TempWStr);
}
InternalFree(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)
{
InternalFree(TempWStr);
}
InternalFree(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");
InternalFree(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());
InternalFree(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");
InternalFree(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());
InternalFree(TempNumberBuffer);
va_end(ap);
return -1;
}
BufferPtr += TempInt;
}
InternalFree(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());
InternalFree(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());
InternalFree(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");
InternalFree(TempStr);
PERF_EXIT(vfprintf);
va_end(ap);
return -1;
}
written += paddingReturnValue;
InternalFree(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;
}