in CoreCLRProfiler/native/coreclr_headers/src/pal/src/cruntime/printf.cpp [585:868]
static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, LPBOOL Store,
LPINT Width, LPINT Prefix, LPINT Type)
{
BOOL Result = FALSE;
LPSTR TempStr;
LPSTR TempStrPtr;
*Width = -1;
*Store = TRUE;
*Prefix = -1;
*Type = -1;
if (*Fmt && **Fmt == '%')
{
*Out++ = *(*Fmt)++;
}
else
{
return Result;
}
/* we'll never need a temp string longer than the original */
TempStrPtr = TempStr = (LPSTR) PAL_malloc(PAL_wcslen(*Fmt)+1);
if (!TempStr)
{
ERROR("PAL_malloc failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return Result;
}
/* parse '*' flag which means don't store */
if (**Fmt == '*')
{
*Store = FALSE;
*Out++ = *(*Fmt)++;
}
/* grab width specifier */
if (isdigit(**Fmt))
{
TempStrPtr = TempStr;
while (isdigit(**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");
SetLastError(ERROR_INTERNAL_ERROR);
return Result;
}
}
#ifdef HOST_64BIT
if (**Fmt == 'p')
{
*Prefix = SCANF_PREFIX_LONGLONG;
}
#endif
/* grab prefix of 'I64' for __int64 */
if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
{
/* convert to 'q'/'ll' so that Unix sscanf can handle it */
*Fmt += 3;
*Prefix = SCANF_PREFIX_LONGLONG;
}
/* grab a prefix of 'h' */
else if (**Fmt == 'h')
{
*Prefix = SCANF_PREFIX_SHORT;
++(*Fmt);
}
/* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
else if (**Fmt == 'l' || **Fmt == 'w')
{
++(*Fmt);
#ifdef HOST_64BIT
// Only want to change the prefix on 64 bit when inputing characters.
if (**Fmt == 'C' || **Fmt == 'S')
#endif
{
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
}
if (**Fmt == 'l')
{
*Prefix = SCANF_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 = SCANF_TYPE_CHAR;
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'c')
{
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
}
if (*Prefix == SCANF_PREFIX_LONG)
{
*Out++ = 'l';
}
*Out++ = 'c';
++(*Fmt);
Result = TRUE;
}
/* grab type 's' */
else if (**Fmt == 's' || **Fmt == 'S')
{
*Type = SCANF_TYPE_STRING;
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 's')
{
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
}
if (*Prefix == SCANF_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' ||
**Fmt == 'p')
{
*Type = SCANF_TYPE_INT;
if (*Prefix == SCANF_PREFIX_SHORT)
{
*Out++ = 'h';
}
else if (*Prefix == SCANF_PREFIX_LONG)
{
*Out++ = 'l';
}
else if (*Prefix == SCANF_PREFIX_LONGLONG)
{
if (strcpy_s(Out, iOutSize, scanf_longlongfmt) != SAFECRT_SUCCESS)
{
ERROR("strcpy_s failed\n");
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
Out += strlen(scanf_longlongfmt);
}
*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 = SCANF_TYPE_FLOAT;
/* this gets rid of %E/%G since they're they're the
same when scanning */
*Out++ = tolower( *(*Fmt)++ );
Result = TRUE;
}
else if (**Fmt == 'n')
{
if (*Prefix == SCANF_PREFIX_SHORT)
{
*Out++ = 'h';
}
*Out++ = *(*Fmt)++;
*Type = SCANF_TYPE_N;
Result = TRUE;
}
else if (**Fmt == '[')
{
/* There is a small compatibility problem in the handling of the []
option in FreeBSD vs. Windows. In Windows, you can have [z-a]
as well as [a-z]. In FreeBSD, [z-a] fails. So, we need to
reverse the instances of z-a to a-z (and [m-e] to [e-m], etc). */
/* step 1 : copy the leading [ */
*Out++ = '[';
(*Fmt)++;
/* step 2 : copy a leading ^, if present */
if( '^' == **Fmt )
{
*Out++ = '^';
(*Fmt)++;
}
/* step 3 : copy a leading ], if present; a ] immediately after the
leading [ (or [^) does *not* end the sequence, it is part of the
characters to match */
if( ']' == **Fmt )
{
*Out++ = ']';
(*Fmt)++;
}
/* step 4 : if the next character is already a '-', it's not part of an
interval specifier, so just copy it */
if('-' == **Fmt )
{
*Out++ = '-';
(*Fmt)++;
}
/* ok then, process the rest of it */
while( '\0' != **Fmt )
{
if(']' == **Fmt)
{
/* ']' marks end of the format specifier; we're done */
*Out++ = ']';
(*Fmt)++;
break;
}
if('-' == **Fmt)
{
if( ']' == (*Fmt)[1] )
{
/* got a '-', next character is the terminating ']';
copy '-' literally */
*Out++ = '-';
(*Fmt)++;
}
else
{
/* got a '-' indicating an interval specifier */
unsigned char prev, next;
/* get the interval boundaries */
prev = (*Fmt)[-1];
next = (*Fmt)[1];
/* if boundaries were inverted, replace the already-copied
low boundary by the 'real' low boundary */
if( prev > next )
{
Out[-1] = next;
/* ...and save the 'real' upper boundary, which will be
copied to 'Out' below */
next = prev;
}
*Out++ = '-';
*Out++ = next;
/* skip over the '-' and the next character, which we
already copied */
(*Fmt)+=2;
}
}
else
{
/* plain character; just copy it */
*Out++ = **Fmt;
(*Fmt)++;
}
}
*Type = SCANF_TYPE_BRACKETS;
Result = TRUE;
}
else if (**Fmt == ' ')
{
*Type = SCANF_TYPE_SPACE;
}
/* add %n so we know how far to increment the pointer */
*Out++ = '%';
*Out++ = 'n';
*Out = 0; /* end the string */
PAL_free(TempStr);
return Result;
}