static BOOL Internal_ScanfExtractFormatA()

in CoreCLRProfiler/native/coreclr_headers/src/pal/src/cruntime/printf.cpp [264:577]


static BOOL Internal_ScanfExtractFormatA(LPCSTR *Fmt, LPSTR Out, int iOutSize, LPBOOL Store,
                                         LPINT Width, LPINT Prefix, LPINT Type)
{
    BOOL Result = FALSE;
    LPSTR TempStr;
    LPSTR TempStrPtr;
    LPSTR BaseOut = Out;
    LPSTR EndOut = Out + iOutSize;

    *Width = -1;
    *Store = TRUE;
    *Prefix = -1;
    *Type = -1;

    if (*Fmt && **Fmt == '%')
    {
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *Out++ = *(*Fmt)++;
    }
    else
    {
        return Result;
    }

    /* we'll never need a temp string longer than the original */
    TempStrPtr = TempStr = (LPSTR) PAL_malloc(strlen(*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;
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *Out++ = *(*Fmt)++;
    }

    /* grab width specifier */
    if (isdigit((unsigned char) **Fmt))
    {
        TempStrPtr = TempStr;
        while (isdigit((unsigned char) **Fmt))
        {
            *TempStrPtr++ = **Fmt;
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *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 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)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = 'l';
        }
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *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)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = 'l';
        }
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *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)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = 'h';
        }
        else if (*Prefix == SCANF_PREFIX_LONG)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = 'l';
        }
        else if (*Prefix == SCANF_PREFIX_LONGLONG)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)

            if (strcpy_s(Out, iOutSize-(Out-BaseOut), scanf_longlongfmt) != SAFECRT_SUCCESS)
            {
                ERROR("strcpy_s failed\n");
                SetLastError(ERROR_INSUFFICIENT_BUFFER);
                return FALSE;
            }

            Out += strlen(scanf_longlongfmt);
        }
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *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 */
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *Out++ = tolower( *(*Fmt)++ );
        Result = TRUE;
    }
    else if (**Fmt == 'n')
    {
        if (*Prefix == SCANF_PREFIX_SHORT)
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = 'h';
        }
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *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 [ */
        CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
        *Out++ = '[';
        (*Fmt)++;

        /* step 2 : copy a leading ^, if present */
        if( '^' == **Fmt )
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *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 )
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *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 )
        {
            CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
            *Out++ = '-';
            (*Fmt)++;
        }

        /* ok then, process the rest of it */
        while( '\0' != **Fmt )
        {
            if(']' == **Fmt)
            {
                /* ']' marks end of the format specifier; we're done */
                CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
                *Out++ = ']';
                (*Fmt)++;
                break;
            }
            if('-' == **Fmt)
            {
                if( ']' == (*Fmt)[1] )
                {
                    /* got a '-', next character is the terminating ']';
                       copy '-' literally */
                    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
                    *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 )
                    {
                        CHECK_OUT_IN_ITS_RANGE(Out-1,BaseOut,EndOut)
                        Out[-1] = next;

                        /* ...and save the 'real' upper boundary, which will be
                           copied to 'Out' below */
                        next = prev;
                    }

                    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
                    *Out++ = '-';
                    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
                    *Out++ = next;

                    /* skip over the '-' and the next character, which we
                       already copied */
                    (*Fmt)+=2;
                }
            }
            else
            {
                /* plain character; just copy it */
                CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
                *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 */
    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
    *Out++ = '%';
    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
    *Out++ = 'n';

    CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
    *Out = 0;  /* end the string */
    PAL_free(TempStr);
    return Result;
}