inline S change_windows_replacement_parameters_to_fastformat(S const& str)
{
    typedef ss_typename_type_k S::const_iterator    iter_t;

    enum state_t
    {
        normal, percent, number
    }       state   =   normal;
    S       str2;
    int     index   =   0;

    str2.reserve(str.size() + 10);

    { for(iter_t begin = str.begin(); begin != str.end(); ++begin)
    {
        bool isNumber = false;

        switch(*begin)
        {
            case    '0':
            case    '1':
            case    '2':
            case    '3':
            case    '4':
            case    '5':
            case    '6':
            case    '7':
            case    '8':
            case    '9':
                isNumber = true;
        }

        if( number == state &&
            !isNumber)
        {
            ff_char_t   parameter[32];
            int         cch = fastformat_util_snprintf(&parameter[0], STLSOFT_NUM_ELEMENTS(parameter), FASTFORMAT_LITERAL_STRING("{%d}"), index - 1);

            str2.append(parameter, size_t(cch));
            str2.append(1u, *begin);

            state = normal;
        }
        else
        {
            switch(*begin)
            {
                case    '%':
                    switch(state)
                    {
                        default:
                        case    number:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("unexpected state");
                        case    normal:
                            state = percent;
                            break;
                        case    percent:
                            state = normal;
                            str2.append(1, '%');
                            break;
                    }
                    break;
                case    '0':
                case    '1':
                case    '2':
                case    '3':
                case    '4':
                case    '5':
                case    '6':
                case    '7':
                case    '8':
                case    '9':
                    switch(state)
                    {
                        default:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("unexpected state");
                        case    normal:
                            str2.append(1, *begin);
                            break;
                        case    percent:
                            state = number;
                            index = (*begin - '0');
                            break;
                        case    number:
                            index = (10 * index) + (*begin - '0');
                            break;
                    }
                    break;
                default:
                    state = normal;
                    str2.append(1, *begin);
                    break;
            }
        }
    }}

    if(number == state)
	{
        ff_char_t   parameter[32];
        int         cch = fastformat_util_snprintf(&parameter[0], STLSOFT_NUM_ELEMENTS(parameter), FASTFORMAT_LITERAL_STRING("{%d}"), index - 1);

        str2.append(parameter, size_t(cch));
    }

    return str2;
}
Example #2
0
FASTFORMAT_CALL(size_t) fastformat_fillReplacements(
    string_slice_t*                 resultElements      // Pointer to receiver of result slices
,   format_element_t const*         formatElements      // Pointer to format elements
,   size_t                          numFormatElements
,   string_slice_t const*           arguments           // Pointer to arguments
,   size_t                          numArguments
,   fastformat_mismatchedHandler_t  handler
,   void*                           param
,   size_t*                         pnumResultElements
)
{
    FASTFORMAT_COVER_MARK_ENTRY();

    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API(NULL != resultElements, "result elements may not be null");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API(NULL != pnumResultElements, "result element count pointer may not be null");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API((NULL != formatElements || 0 == numFormatElements), "pattern elements may not be null, unless numFormatElements is 0");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API((0 != numArguments) == (NULL != arguments), "arguments can only be null when there are 0 arguments, and vice versa");

    mismatched_handler_info_t   handler_info        =   { handler, param };
    size_t                      cchTotal            =   0;
    string_slice_t              defaultSlice        =   {   0,  NULL    };
    int                         handlerReturned     =   0;
    string_slice_t* const       resultElementsBase  =   resultElements;

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
    stlsoft::auto_buffer<unreferenced_argument_flag_t>   argumentReferenceFlags(numArguments);

    std::fill(argumentReferenceFlags.begin(), argumentReferenceFlags.end(), 0);
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        handler_info = fastformat_getThreadMismatchedHandler();
    }

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        handler_info = fastformat_getProcessMismatchedHandler();
    }

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

    handler_info = fastformat_getDefaultMismatchedHandler();
    }

    // Process every format element:
    //
    //  - if literal, copy over
    //  - if replacement, lookup argument and copy over/report mismatch
    //  - if spacer, evaluate whether spacing needed, and then
    { for(size_t i = 0; i != numFormatElements; ++i, ++resultElements)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        format_element_t const& pattern_element = formatElements[i];

        if(FASTFORMAT_INTERNAL_FORMAT_ELEMENT_INDEX_LITERAL_ == pattern_element.index)
        {
            // A literal fragment, so just copy into destination

            FASTFORMAT_COVER_MARK_ENTRY();

            resultElements->len  =   pattern_element.len;
            resultElements->ptr  =   pattern_element.ptr;

            cchTotal += pattern_element.len;
        }
        else
        {
            // A replacement parameter, so work out whether to truncate or
            // to insert any fill slices (before, after, or both)
            //
            // 1. If a maximum width is specified and the source slice
            //    length is greater than the maximum, then we truncate
            // 2. If a minimum width is specified and the source slice
            //    length is less than the minimum, then we insert one or
            //    more slices:
            // 2.a. If left-aligned, then we insert a pad slice after
            //      the current slice
            // 2.b. If right-aligned, then we insert a pad slice before
            //      the current slice
            // 2.c. If centre-aligned, then we insert pad slices before
            //      and after the current slice
            // 3. If none of these are satisfied, then copy over the
            //    source slice as-is

            // But, first, we need to validate the index
            if(pattern_element.index >= static_cast<int>(numArguments))
            {
                // Pattern element index is out of range, e.g. fmtln(sink, "val0={2}", v0, v1);

                FASTFORMAT_COVER_MARK_ENTRY();

                FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

                if(handlerReturned >= 0)
                {
                    handlerReturned = (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_MISSING_ARGUMENT, numArguments, pattern_element.index, &defaultSlice, NULL, 0, NULL);
                }

                // Handler has returned, so no exception has been thrown
                //
                // If 0, insert the pattern_element, otherwise insert the
                // default slice.

                if(handlerReturned != 0)
                {
                    FASTFORMAT_COVER_MARK_ENTRY();

#if 0
                    // We cannot take the default slice, because the application has
                    // not provided any space for us to write it, so ...
                    resultElements->len  =   defaultSlice.len;
                    resultElements->ptr  =   defaultSlice.ptr;
#else /* ? 0 */
                    // ... we skip it (by decrementing in anticipation of the increment
                    // as we loop round again).
                    --resultElements;
#endif /* 0 */
                }
                else
                {
                    FASTFORMAT_COVER_MARK_ENTRY();

                    resultElements->len  =   pattern_element.len;
                    resultElements->ptr  =   pattern_element.ptr;
                }
            }
            else
            {
                string_slice_t const&   src_slice = arguments[pattern_element.index];
                ff_char_t const*        (FASTFORMAT_CALLCONV* pfnFill)(size_t) = ('#' == pattern_element.fill) ? fastformat_getHashesSlice : fastformat_getSpacesSlice;

                if( pattern_element.maxWidth >= 0 &&
                    size_t(pattern_element.maxWidth) < src_slice.len)
                {
                    // Truncating, so see if we're truncating left/centre/right

                    resultElements->len = pattern_element.maxWidth;

                    switch(pattern_element.alignment)
                    {
                        default:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("invalid enumerator");
                        case    FASTFORMAT_ALIGNMENT_NONE:
                        case    FASTFORMAT_ALIGNMENT_RIGHT:
                            resultElements->ptr = src_slice.ptr + (src_slice.len - pattern_element.maxWidth);
                            break;
                        case    FASTFORMAT_ALIGNMENT_CENTRE:
                            resultElements->ptr = src_slice.ptr + (src_slice.len - pattern_element.maxWidth) / 2;
                            break;
                        case    FASTFORMAT_ALIGNMENT_LEFT:
                            resultElements->ptr = src_slice.ptr;
                            break;
                    }

                    cchTotal += pattern_element.maxWidth;
                }
                else if(0 != pattern_element.minWidth &&
                        size_t(pattern_element.minWidth) > src_slice.len)
                {
                    switch(pattern_element.alignment)
                    {
                        default:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("invalid enumerator");
                        case    FASTFORMAT_ALIGNMENT_NONE:
                        case    FASTFORMAT_ALIGNMENT_RIGHT:
                            // insert a spaces slice before the source slice
                            resultElements->len = size_t(pattern_element.minWidth) - src_slice.len;
                            resultElements->ptr = pfnFill(resultElements->len);

                            ++resultElements;

                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;
                            break;
                        case    FASTFORMAT_ALIGNMENT_CENTRE:
                            // insert a spaces slice before and after the source slice
                            resultElements->len = (size_t(pattern_element.minWidth) - src_slice.len) / 2;
                            resultElements->ptr = pfnFill(resultElements->len);

                            ++resultElements;

                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;

                            ++resultElements;

                            resultElements->len = size_t(pattern_element.minWidth) - (resultElements[-1].len + resultElements[-2].len);
                            resultElements->ptr = pfnFill(resultElements->len);
                            break;
                        case    FASTFORMAT_ALIGNMENT_LEFT:
                            // insert a spaces slice after the source slice
                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;

                            ++resultElements;

                            resultElements->len = size_t(pattern_element.minWidth) - src_slice.len;
                            resultElements->ptr = pfnFill(resultElements->len);
                            break;
                    }

                    cchTotal += pattern_element.minWidth;
                }
                else
                {
                    // Not truncating, so just copy over

                    resultElements->len = src_slice.len;
                    resultElements->ptr = src_slice.ptr;

                    cchTotal += src_slice.len;
                }
            }

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
            // Have to do a runtime test here, in case where additional
            // arguments are specified (and exception suppressed by use of
            // fastformat::ignore_missing_arguments_scope).
            if(size_t(pattern_element.index) < argumentReferenceFlags.size())
            {
                argumentReferenceFlags[size_t(pattern_element.index)] = 1;
            }
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */
        }
    }}

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
    stlsoft::auto_buffer<unreferenced_argument_flag_t>::iterator it;

    if(argumentReferenceFlags.end() != (it = std::find(argumentReferenceFlags.begin(), argumentReferenceFlags.end(), 0)))
    {
        int firstMismatchedReplacementIndex = static_cast<int>(it - argumentReferenceFlags.begin());

        FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

        (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_UNREFERENCED_ARGUMENT, numArguments, firstMismatchedReplacementIndex, NULL, NULL, 0, NULL);
    }
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */

    if(0 != handlerReturned)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

        (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_SUCCESS, numArguments, -1, NULL, NULL, 0, NULL);
    }

    *pnumResultElements = static_cast<size_t>(resultElements - resultElementsBase);

    return cchTotal;
}