From ceffb6ddeb6c6d2d8712579a142a8b2f67571b6b Mon Sep 17 00:00:00 2001 From: Hugues Kamba Date: Tue, 22 Oct 2019 15:25:26 +0100 Subject: [PATCH] minimal-printf: Fix handling of the two character sequence %% The two character sequence %% is used in standard implementations of printf to print a single %. This is because % is essentially printf's escape character for format specifiers and as \% cannot work printf uses %%. Therefore to be compatible with string buffers containing %%, minimal-printf also needs to only print a single %. --- .../minimal-printf/compliance/main.cpp | 46 +++++++++++++++++++ .../mbed_printf_implementation.c | 19 +++----- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/TESTS/mbed_platform/minimal-printf/compliance/main.cpp b/TESTS/mbed_platform/minimal-printf/compliance/main.cpp index cd9cf70862f..80d31d24e6c 100644 --- a/TESTS/mbed_platform/minimal-printf/compliance/main.cpp +++ b/TESTS/mbed_platform/minimal-printf/compliance/main.cpp @@ -404,6 +404,21 @@ static control_t test_printf_x(const size_t call_count) return CaseNext; } +static control_t test_printf_percent(const size_t call_count) +{ + int result_baseline; + int result_minimal; + int result_file; + + result_minimal = mbed_printf("%% \r\n"); + result_file = mbed_fprintf(stderr, "%% \r\n"); + result_baseline = printf("%% \r\n"); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_file); + + return CaseNext; +} + /******************************************************************************/ /* */ /* SNPRINTF */ @@ -721,6 +736,34 @@ static control_t test_snprintf_x(const size_t call_count) return CaseNext; } +static control_t test_snprintf_percent(const size_t call_count) +{ + char buffer_baseline[100]; + char buffer_minimal[100]; + int result_baseline; + int result_minimal; + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "%% \r\n"); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "%% \r\n"); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + return CaseNext; +} + +static control_t test_snprintf_unsupported_specifier(const size_t call_count) +{ + char buffer_minimal[100]; + + TEST_ASSERT_NOT_EQUAL( + 0, + mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "%a \r\n", 5) + ); + TEST_ASSERT_EQUAL_STRING("%a \r\n", buffer_minimal); + + return CaseNext; +} + #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT static control_t test_printf_f(const size_t call_count) { @@ -902,6 +945,9 @@ Case cases[] = { Case("snprintf %u", test_snprintf_u), Case("printf %x", test_printf_x), Case("snprintf %x", test_snprintf_x), + Case("printf %%", test_printf_percent), + Case("snprintf %%", test_snprintf_percent), + Case("snprintf unsupported specifier", test_snprintf_unsupported_specifier), #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT Case("printf %f", test_printf_f), Case("snprintf %f", test_snprintf_f), diff --git a/platform/source/minimal-printf/mbed_printf_implementation.c b/platform/source/minimal-printf/mbed_printf_implementation.c index 821d660e7d8..ea18edd46cc 100644 --- a/platform/source/minimal-printf/mbed_printf_implementation.c +++ b/platform/source/minimal-printf/mbed_printf_implementation.c @@ -626,19 +626,14 @@ int mbed_minimal_formatted_string(char *buffer, size_t length, const char *forma mbed_minimal_formatted_string_void_pointer(buffer, length, &result, value, stream); } else { - /* write all characters between format beginning and unrecognied modifier */ - while (index < next_index) { - mbed_minimal_formatted_string_character(buffer, length, &result, format[index], stream); - index++; - } - - /* if this is not the end of the string, write unrecognized modifier */ - if (next != '\0') { - mbed_minimal_formatted_string_character(buffer, length, &result, format[index], stream); - } else { - /* break out of for loop */ - break; + // Unrecognised, or `%%`. Print the `%` that led us in. + mbed_minimal_formatted_string_character(buffer, length, &result, '%', stream); + if (next == '%') { + // Continue printing loop after `%%` + index = next_index; } + // Otherwise we continue the printing loop after the leading `%`, so an + // unrecognised thing like "Blah = %a" will just come out as "Blah = %a" } } else /* not a format specifier */