in CoreCLRProfiler/native/coreclr_headers/src/pal/src/cruntime/printfcpp.cpp [1020:1448]
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;
LPCWSTR TempWStr = NULL;
LPWSTR AllocedTempWStr = NULL;
LPWSTR WorkingWStr = NULL;
WCHAR TempWChar[2];
INT Flags;
INT Width;
INT Precision;
INT Prefix;
INT Type;
INT TempInt;
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))
{
AllocedTempWStr = NULL;
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. */
LPCSTR s = va_arg(ap, LPSTR );
if (s == NULL)
{
TempWStr = NULL;
}
else
{
UINT Length = 0;
Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
if ( Length != 0 )
{
AllocedTempWStr =
(LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) );
if ( AllocedTempWStr )
{
MultiByteToWideChar( CP_ACP, 0, s, -1,
AllocedTempWStr, Length );
TempWStr = AllocedTempWStr;
}
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;
}
}
}
if (TempWStr == NULL)
{
TempWStr = __wnullstring;
}
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);
free(AllocedTempWStr);
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");
free(AllocedTempWStr);
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");
free(AllocedTempWStr);
free(WorkingWStr);
LOGEXIT("vfwprintf returns int -1\n");
PERF_EXIT(vfwprintf);
va_end(ap);
return (-1);
}
written += paddingReturnValue;
free(WorkingWStr);
free(AllocedTempWStr);
}
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_s(TempSprintfStr, TEMP_COUNT, _TRUNCATE, 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_s(TempSprintfStr, TempInt, _TRUNCATE, 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);
}