static DWORD FormatMessageToBufferA()

in source/shared/FormattedPrint.cpp [1216:1383]


static DWORD FormatMessageToBufferA( const char * format, char * buffer, DWORD bufferWCharSize, const std::vector< vararg_t > & args )
{
    char * msg = buffer;
    DWORD bufsize = std::min(bufferWCharSize, (DWORD)64000);
    DWORD msg_pos = 0;
    const DWORD fmtsize = 32;
    char fmt[fmtsize] = {'\0'};
    DWORD fmt_pos;
    char fmt_ch;

    const char * p = format;
    while( msg_pos < bufsize && '\0' != (fmt_ch = *p++) )
    {
        if ( '%' != fmt_ch )
        {
            msg[msg_pos++] = fmt_ch;
        }
        else if ( '0' == *p || '\0' == *p )
        {
            // %0 or null term means end formatting
            break;
        }
        else if ( *p < '1' || '9' < *p )
        {
            // Escaped char, print and keep going
            // Eg.  "%n" == '\n'
            switch ( *p )
            {
            case 'a': msg[msg_pos++] = '\a'; break;
            case 'b': msg[msg_pos++] = '\b'; break;
            case 'f': msg[msg_pos++] = '\f'; break;
            case 'n': msg[msg_pos++] = '\n'; break;
            case 'r': msg[msg_pos++] = '\r'; break;
            case 't': msg[msg_pos++] = '\t'; break;
            case 'v': msg[msg_pos++] = '\v'; break;
            default:   msg[msg_pos++] = *p;    break;
            }
            ++p;
        }
        else
        {
            // Integer must be [1..99]
            size_t argPos = *p++ - '0';
            if ( '0' <= *p && *p <= '9' )
            {
                argPos *= 10;
                argPos += *p++ - '0';
            }
            assert( 0 < argPos && argPos < 100 );

            fmt_pos = 0;
            fmt[fmt_pos++] = '%';

            if ( '!' != *p )
            {
                // Assume %s as per spec
                fmt[fmt_pos++] = 's';
                fmt[fmt_pos] = '\0';
                int chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].PtrValue() );
                if ( chars_printed < 0 )
                {
                    errno = EINVAL;
                    return 0;
                }
                msg_pos += chars_printed;
            }
            else
            {
                // Skip over '!' and build format string
                ++p;
                char ch;
                int flags = 0;
                int advance = 0;
                enum CHARTYPE chclass;
                enum STATE state = ST_PERCENT;
                bool found_terminator = false;
                while ( fmt_pos < fmtsize && !found_terminator && ('\0' != (ch = *p++)) )
                {
                    chclass = GetCharType( ch );
                    state = GetState( chclass, state );

                    switch ( state )
                    {
                    case ST_SIZE:
                        state = ProcessSize( ch, p, &advance, &flags );
                        fmt[fmt_pos++] = ch;
                        while ( fmt_pos < fmtsize && 0 < advance-- )
                        {
                            fmt[fmt_pos++] = *p++;
                        }
                        break;

                    case ST_NORMAL:
                        assert( '!' == ch );
                        found_terminator = true;
                        break;

                    case ST_INVALID:
                    case ST_PERCENT:
                        errno = EINVAL;
                        return 0;

                    default:
                        fmt[fmt_pos++] = ch;
                        break;
                    }
                }

                if ( fmtsize <= fmt_pos )
                {
                    // Should not have a format string longer than 31 chars
                    // It can happen but shouldn't (eg. a bunch of size mods like %llllllllllllllld)
                    errno = EINVAL;
                    return 0;
                }

                fmt[fmt_pos] = '\0';

                // Format string might need up to 3 args (eg. %*.*d )
                // If more than one arg, then the first ones must be 32-bit ints
                // Hence, first 64-bit arg tells us the last arg we need to send.
                int chars_printed = 0;
                if ( vararg_t::Int64 == args[argPos-1].Type() )
                {
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int64Value() );
                }
                else if ( args.size() == argPos )
                {
                    // No more args so send the one Int
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value() );
                }
                else if ( vararg_t::Int64 == args[argPos].Type() )
                {
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int64Value() );
                }
                else if ( args.size() == (argPos+1) )
                {
                    // No more args so send the two Ints
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos-1].Int32Value() );
                }
                else if ( vararg_t::Int64 == args[argPos+1].Type() )
                {
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int64Value() );
                }
                else
                {
                    chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int32Value() );
                }

                if ( chars_printed < 0 )
                {
                    errno = EINVAL;
                    return 0;
                }
                msg_pos += chars_printed;
            }
        }
    }

    if ( bufsize <= msg_pos )
    {
        errno = ERANGE;
        return 0;
    }

    msg[msg_pos] = '\0';
    return msg_pos;
}