in CoreCLRProfiler/native/coreclr_headers/src/pal/src/cruntime/printfcpp.cpp [454:774]
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 HOST_64BIT
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 HOST_64BIT
/* 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 HOST_64BIT
// 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;
}