diff --git a/features/minimal-printf/README.md b/features/minimal-printf/README.md index b21d3bd483..1838368a45 100755 --- a/features/minimal-printf/README.md +++ b/features/minimal-printf/README.md @@ -1,15 +1,15 @@ # Minimal printf and snprintf -Library supports both printf and snprintf in 960 bytes of flash. +Library supports both printf and snprintf in 1252 bytes of flash. -Prints directly to stdio/UART without using malloc. All flags, length, and precision modifiers are ignored. Floating point is disabled by default. +Prints directly to stdio/UART without using malloc. All flags and precision modifiers are ignored. Floating point is disabled by default. Supports: -* %d: signed long int. -* %i: signed long int. -* %u: unsigned long int. -* %x: unsigned char printed as hexadecimal number (e.g., FF). -* %X: unsigned char printed as hexadecimal number (e.g., FF). +* %d: signed integer [h, hh, (none), l, ll, z, j, t]. +* %i: signed integer [h, hh, (none), l, ll, z, j, t]. +* %u: unsigned integer [h, hh, (none), l, ll, z, j, t]. +* %x: unsigned integer [h, hh, (none), l, ll, z, j, t], printed as hexadecimal number (e.g., FF). +* %X: unsigned integer [h, hh, (none), l, ll, z, j, t], printed as hexadecimal number (e.g., FF). * %f: floating point (disabled by default). * %F: floating point (disabled by default). * %g: floating point (disabled by default). diff --git a/features/minimal-printf/TESTS/minimal-printf/compliance/main.cpp b/features/minimal-printf/TESTS/minimal-printf/compliance/main.cpp new file mode 100755 index 0000000000..6a8694c790 --- /dev/null +++ b/features/minimal-printf/TESTS/minimal-printf/compliance/main.cpp @@ -0,0 +1,642 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "mbed_printf.h" + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include +#include +#include +#include + +#ifndef ULLONG_MAX +#define ULLONG_MAX UINT64_MAX +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX INT64_MAX +#endif + +#ifndef LLONG_MIN +#define LLONG_MIN INT64_MIN +#endif + +using namespace utest::v1; + + +static control_t test_printf_d(const size_t call_count) +{ + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + result_minimal = mbed_printf("hhd: %hhd\r\n", SCHAR_MIN); + result_baseline = printf("hhd: %hhd\r\n", SCHAR_MIN); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hhd: %hhd\r\n", SCHAR_MAX); + result_baseline = printf("hhd: %hhd\r\n", SCHAR_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hd: %hd\r\n", SHRT_MIN); + result_baseline = printf("hd: %hd\r\n", SHRT_MIN); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hd: %hd\r\n", SHRT_MAX); + result_baseline = printf("hd: %hd\r\n", SHRT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("d: %d\r\n", INT_MIN); + result_baseline = printf("d: %d\r\n", INT_MIN); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("d: %d\r\n", INT_MAX); + result_baseline = printf("d: %d\r\n", INT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("ld: %ld\r\n", LONG_MIN); + result_baseline = printf("ld: %ld\r\n", LONG_MIN); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("ld: %ld\r\n", LONG_MAX); + result_baseline = printf("ld: %ld\r\n", LONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("lld: %lld\r\n", LLONG_MIN); + result_baseline = printf("lld: %lld\r\n", LLONG_MIN); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("lld: %lld\r\n", LLONG_MAX); + result_baseline = printf("lld: %lld\r\n", LLONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + printf("%%jd not supported by mbed\r\n"); + + result_minimal = mbed_printf("jd: %jd\r\n", INT32_MIN); + result_baseline = printf("jd: %jd\r\n", (intmax_t) INT32_MIN); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_printf("jd: %jd\r\n", INT32_MAX); + result_baseline = printf("jd: %jd\r\n", (intmax_t) INT32_MAX); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + printf("%%zd not supported by mbed\r\n"); + + result_minimal = mbed_printf("zd: %zd\r\n", INT32_MIN); + result_baseline = printf("zd: %zd\r\n", (ssize_t) INT32_MIN); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_printf("zd: %zd\r\n", INT32_MAX); + result_baseline = printf("zd: %zd\r\n", (ssize_t) INT32_MAX); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + printf("%%td not supported by mbed\r\n"); + + result_minimal = mbed_printf("td: %td\r\n", PTRDIFF_MIN); + result_baseline = printf("td: %td\r\n", PTRDIFF_MIN); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_printf("td: %td\r\n", PTRDIFF_MAX); + result_baseline = printf("td: %td\r\n", PTRDIFF_MAX); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + return CaseNext; +} + +static control_t test_printf_u(const size_t call_count) +{ + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + result_minimal = mbed_printf("hhu: %hhu\r\n", 0); + result_baseline = printf("hhu: %hhu\r\n", 0); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hhu: %hhu\r\n", UCHAR_MAX); + result_baseline = printf("hhu: %hhu\r\n", UCHAR_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hu: %hu\r\n", 0); + result_baseline = printf("hu: %hu\r\n", 0); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hu: %hu\r\n", USHRT_MAX); + result_baseline = printf("hu: %hu\r\n", USHRT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("u: %u\r\n", 0); + result_baseline = printf("u: %u\r\n", 0); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("u: %u\r\n", UINT_MAX); + result_baseline = printf("u: %u\r\n", UINT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("lu: %lu\r\n", 0); + result_baseline = printf("lu: %lu\r\n", 0UL); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("lu: %lu\r\n", ULONG_MAX); + result_baseline = printf("lu: %lu\r\n", ULONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("llu: %llu\r\n", 0); + result_baseline = printf("llu: %llu\r\n", 0ULL); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("llu: %llu\r\n", ULLONG_MAX); + result_baseline = printf("llu: %llu\r\n", ULLONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("ju: %ju\r\n", 0); + result_baseline = printf("ju: %ju\r\n",(uintmax_t) 0); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_printf("ju: %ju\r\n", UINTMAX_MAX); + result_baseline = printf("ju: %ju\r\n", UINTMAX_MAX); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_printf("zu: %zu\r\n", 0); + result_baseline = printf("zu: %zu\r\n", 0); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_printf("zu: %zu\r\n", SIZE_MAX); + result_baseline = printf("zu: %zu\r\n", SIZE_MAX); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + result_minimal = mbed_printf("tu: %tu\r\n", 0); + result_baseline = printf("tu: %tu\r\n", 0); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_printf("tu: %tu\r\n", UINTPTR_MAX); + result_baseline = printf("tu: %tu\r\n", UINTPTR_MAX); + TEST_ASSERT_EQUAL_INT(26, result_minimal); + + return CaseNext; +} + +static control_t test_printf_x(const size_t call_count) +{ + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + printf("%%x always prints even characters\r\n"); + + result_minimal = mbed_printf("hhX: %hhX\r\n", 0); + result_baseline = printf("hhX: %hhX\r\n", 0); + TEST_ASSERT_EQUAL_INT(9, result_minimal); + + result_minimal = mbed_printf("hhX: %hhX\r\n", UCHAR_MAX); + result_baseline = printf("hhX: %hhX\r\n", UCHAR_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("hX: %hX\r\n", 0); + result_baseline = printf("hX: %hX\r\n", 0); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("hX: %hX\r\n", USHRT_MAX); + result_baseline = printf("hX: %hX\r\n", USHRT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("X: %X\r\n", 0); + result_baseline = printf("X: %X\r\n", 0); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_printf("X: %X\r\n", UINT_MAX); + result_baseline = printf("X: %X\r\n", UINT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("lX: %lX\r\n", 0); + result_baseline = printf("lX: %lX\r\n", 0UL); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("lX: %lX\r\n", ULONG_MAX); + result_baseline = printf("lX: %lX\r\n", ULONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("llX: %llX\r\n", 0); + result_baseline = printf("llX: %llX\r\n", 0ULL); + TEST_ASSERT_EQUAL_INT(9, result_minimal); + + result_minimal = mbed_printf("llX: %llX\r\n", ULLONG_MAX); + result_baseline = printf("llX: %llX\r\n", ULLONG_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("jX: %jX\r\n", 0); + result_baseline = printf("jX: %jX\r\n", (uintmax_t) 0); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("jX: %jX\r\n", UINTMAX_MAX); + result_baseline = printf("jX: %jX\r\n", UINTMAX_MAX); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("zX: %zX\r\n", 0); + result_baseline = printf("zX: %zX\r\n", 0); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("zX: %zX\r\n", SIZE_MAX); + result_baseline = printf("zX: %zX\r\n", SIZE_MAX); + TEST_ASSERT_EQUAL_INT(14, result_minimal); + + result_minimal = mbed_printf("tX: %tX\r\n", 0); + result_baseline = printf("tX: %tX\r\n", 0); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("tX: %tX\r\n", UINTPTR_MAX); + result_baseline = printf("tX: %tX\r\n", UINTPTR_MAX); + TEST_ASSERT_EQUAL_INT(22, result_minimal); + + return CaseNext; +} + +/******************************************************************************/ +/* */ +/* SNPRINTF */ +/* */ +/******************************************************************************/ + +static control_t test_snprintf_d(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), "hhd: %hhd\r\n", SCHAR_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhd: %hhd\r\n", SCHAR_MIN); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hhd: %hhd\r\n", SCHAR_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhd: %hhd\r\n", SCHAR_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hd: %hd\r\n", SHRT_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hd: %hd\r\n", SHRT_MIN); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hd: %hd\r\n", SHRT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hd: %hd\r\n", SHRT_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "d: %d\r\n", INT_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "d: %d\r\n", INT_MIN); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "d: %d\r\n", INT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "d: %d\r\n", INT_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "ld: %ld\r\n", LONG_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "ld: %ld\r\n", LONG_MIN); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "ld: %ld\r\n", LONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "ld: %ld\r\n", LONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lld: %lld\r\n", LLONG_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lld: %lld\r\n", LLONG_MIN); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lld: %lld\r\n", LLONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lld: %lld\r\n", LLONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + printf("%%jd not supported by mbed\r\n"); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "jd: %jd\r\n", INT32_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "jd: %jd\r\n", (intmax_t) INT32_MIN); + TEST_ASSERT_EQUAL_STRING("jd: -2147483648\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "jd: %jd\r\n", INT32_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "jd: %jd\r\n", (intmax_t) INT32_MAX); + TEST_ASSERT_EQUAL_STRING("jd: 2147483647\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + printf("%%zd not supported by mbed\r\n"); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zd: %zd\r\n", INT32_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zd: %zd\r\n", (ssize_t) INT32_MIN); + TEST_ASSERT_EQUAL_STRING("zd: -2147483648\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zd: %zd\r\n", INT32_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zd: %zd\r\n", (ssize_t) INT32_MAX); + TEST_ASSERT_EQUAL_STRING("zd: 2147483647\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + printf("%%td not supported by mbed\r\n"); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "td: %td\r\n", PTRDIFF_MIN); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "td: %td\r\n", PTRDIFF_MIN); + TEST_ASSERT_EQUAL_STRING("td: -2147483648\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(17, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "td: %td\r\n", PTRDIFF_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "td: %td\r\n", PTRDIFF_MAX); + TEST_ASSERT_EQUAL_STRING("td: 2147483647\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + return CaseNext; +} + +static control_t test_snprintf_u(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), "hhu: %hhu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhu: %hhu\r\n", 0); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hhu: %hhu\r\n", UCHAR_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhu: %hhu\r\n", UCHAR_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hu: %hu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hu: %hu\r\n", 0); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hu: %hu\r\n", USHRT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hu: %hu\r\n", USHRT_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "u: %u\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "u: %u\r\n", 0); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "u: %u\r\n", UINT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "u: %u\r\n", UINT_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lu: %lu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lu: %lu\r\n", 0UL); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lu: %lu\r\n", ULONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lu: %lu\r\n", ULONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "llu: %llu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "llu: %llu\r\n", 0ULL); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "llu: %llu\r\n", ULLONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "llu: %llu\r\n", ULLONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "ju: %ju\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "ju: %ju\r\n", (uintmax_t) 0); + TEST_ASSERT_EQUAL_STRING("ju: 0\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "ju: %ju\r\n", UINTMAX_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "ju: %ju\r\n", UINTMAX_MAX); + TEST_ASSERT_EQUAL_STRING("ju: 0\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zu: %zu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zu: %zu\r\n", 0); + TEST_ASSERT_EQUAL_STRING("zu: 0\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zu: %zu\r\n", SIZE_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zu: %zu\r\n", SIZE_MAX); + TEST_ASSERT_EQUAL_STRING("zu: 4294967295\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(16, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "tu: %tu\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "tu: %tu\r\n", 0); + TEST_ASSERT_EQUAL_STRING("tu: 0\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "tu: %tu\r\n", UINTPTR_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "tu: %tu\r\n", UINTPTR_MAX); + TEST_ASSERT_EQUAL_STRING("tu: 18446744073709551615\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(26, result_minimal); + + return CaseNext; +} + +static control_t test_snprintf_x(const size_t call_count) +{ + char buffer_baseline[100]; + char buffer_minimal[100]; + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + printf("%%x always prints even characters\r\n"); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hhX: %hhX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhX: %hhX\r\n", 0); + TEST_ASSERT_EQUAL_STRING("hhX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(9, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hhX: %hhX\r\n", UCHAR_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hhX: %hhX\r\n", UCHAR_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hX: %hX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hX: %hX\r\n", 0); + TEST_ASSERT_EQUAL_STRING("hX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "hX: %hX\r\n", USHRT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "hX: %hX\r\n", USHRT_MAX); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "X: %X\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "X: %X\r\n", 0); + TEST_ASSERT_EQUAL_STRING("X: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(7, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "X: %X\r\n", UINT_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "X: %X\r\n", UINT_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lX: %lX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lX: %lX\r\n", 0UL); + TEST_ASSERT_EQUAL_STRING("lX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "lX: %lX\r\n", ULONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "lX: %lX\r\n", ULONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "llX: %llX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "llX: %llX\r\n", 0ULL); + TEST_ASSERT_EQUAL_STRING("llX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(9, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "llX: %llX\r\n", ULLONG_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "llX: %llX\r\n", ULLONG_MAX); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "jX: %jX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "jX: %jX\r\n", (uintmax_t) 0); + TEST_ASSERT_EQUAL_STRING("jX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "jX: %jX\r\n", UINTMAX_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "jX: %jX\r\n", UINTMAX_MAX); + TEST_ASSERT_EQUAL_STRING("jX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zX: %zX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zX: %zX\r\n", 0); + TEST_ASSERT_EQUAL_STRING("zX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "zX: %zX\r\n", SIZE_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "zX: %zX\r\n", SIZE_MAX); + TEST_ASSERT_EQUAL_STRING("zX: FFFFFFFF\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(14, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "tX: %tX\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "tX: %tX\r\n", 0); + TEST_ASSERT_EQUAL_STRING("tX: 00\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "tX: %tX\r\n", UINTPTR_MAX); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "tX: %tX\r\n", UINTPTR_MAX); + TEST_ASSERT_EQUAL_STRING("tX: FFFFFFFFFFFFFFFF\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(22, result_minimal); + + return CaseNext; +} + +static control_t test_printf_f(const size_t call_count) +{ + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + + double pi = 3.14159265359; + + result_minimal = mbed_printf("f: %f\r\n", -1 * pi); + result_baseline = printf("f: %f\r\n", -1 * pi); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_printf("f: %f\r\n", 0); + result_baseline = printf("f: %f\r\n", 0); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_printf("f: %f\r\n", pi); + result_baseline = printf("f: %f\r\n", pi); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + return CaseNext; +} + +static control_t test_snprintf_f(const size_t call_count) +{ + char buffer_baseline[100]; + char buffer_minimal[100]; + int result_baseline; + int result_minimal; + + /*************************************************************************/ + /*************************************************************************/ + + double pi = 3.14159265359; + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "f: %f\r\n", -1 * pi); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "f: %f\r\n", -1 * pi); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "f: %f\r\n", 0); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "f: %f\r\n", 0); + TEST_ASSERT_EQUAL_STRING("f: 0.0\r\n", buffer_minimal); + TEST_ASSERT_EQUAL_INT(8, result_minimal); + + result_minimal = mbed_snprintf(buffer_minimal, sizeof(buffer_minimal), "f: %f\r\n", pi); + result_baseline = snprintf(buffer_baseline, sizeof(buffer_baseline), "f: %f\r\n", pi); + TEST_ASSERT_EQUAL_STRING(buffer_baseline, buffer_minimal); + TEST_ASSERT_EQUAL_INT(result_baseline, result_minimal); + + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(30*60, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("printf %d", test_printf_d), + Case("snprintf %d", test_snprintf_d), + Case("printf %u", test_printf_u), + Case("snprintf %u", test_snprintf_u), + Case("printf %x", test_printf_x), + Case("snprintf %x", test_snprintf_x), +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT + Case("printf %f", test_printf_f), + Case("snprintf %f", test_snprintf_f), +#endif +}; + +Specification specification(greentea_setup, cases, greentea_test_teardown_handler); + +int main() +{ + return !Harness::run(specification); +} diff --git a/features/minimal-printf/mbed_lib.json b/features/minimal-printf/mbed_lib.json index 5b536f7b76..c7d6fb3098 100755 --- a/features/minimal-printf/mbed_lib.json +++ b/features/minimal-printf/mbed_lib.json @@ -1,13 +1,17 @@ { "name": "minimal-printf", "config": { - "floating-point": { + "enable-floating-point": { "help": "Enable floating point printing", "value": false }, - "floating-point-max-decimals": { + "set-floating-point-max-decimals": { "help": "Maximum number of decimals to be printed", - "value": 3 + "value": 6 + }, + "enable-64-bit": { + "help": "Enable printing 64 bit integers", + "value": true } } } diff --git a/features/minimal-printf/mbed_printf.c b/features/minimal-printf/mbed_printf.c old mode 100755 new mode 100644 index d6800d7782..41566989e9 --- a/features/minimal-printf/mbed_printf.c +++ b/features/minimal-printf/mbed_printf.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2016 ARM Limited + * Copyright (c) 2017 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,442 +14,12 @@ * limitations under the License. */ -#include "mbed_printf.h" +#include "mbed_printf_implementation.h" -#include -#include #include -#include - -/* module variable for keeping track of initialization */ -static bool not_initialized = true; - -/***************************/ -/* MBED */ -/***************************/ -#if TARGET_LIKE_MBED -#include "hal/serial_api.h" - -#if DEVICE_SERIAL -static serial_t stdio_uart = { 0 }; -//#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES -//static char stdio_in_prev = 0; -//static char stdio_out_prev = 0; -//#endif -#endif - -static void init_serial() -{ - if (not_initialized) - { - not_initialized = false; - -#if DEVICE_SERIAL - serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); -#if MBED_CONF_PLATFORM_STDIO_BAUD_RATE - serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); -#endif -#endif - } -} - -#define MBED_INITIALIZE_PRINT(x) { init_serial(); } -#define MBED_PRINT_CHARACTER(x) { serial_putc(&stdio_uart, x); } - -/***************************/ -/* Linux */ -/***************************/ -#else -#define MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT 1 -#define MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT_MAX_DECIMALS 10 -#define MBED_INITIALIZE_PRINT(x) { ; } -#define MBED_PRINT_CHARACTER(x) { printf("%c", x); } -#endif - -static void mbed_minimal_formatted_string_long_int(char* buffer, size_t length, int* result, long int value); -static void mbed_minimal_formatted_string_unsigned_long_int(char* buffer, size_t length, int* result, unsigned long int value); -static void mbed_minimal_formatted_string_unsigned_char(char* buffer, size_t length, int* result, int value); -static void mbed_minimal_formatted_string_void_pointer(char* buffer, size_t length, int* result, void* value); -static void mbed_minimal_formatted_string_character(char* buffer, size_t length, int* result, int character); -static void mbed_minimal_formatted_string_string(char* buffer, size_t length, int* result, char* string); - -#ifndef MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT -#define MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT 0 -#endif - -#ifndef MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT_MAX_DECIMALS -#define MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT_MAX_DECIMALS 0 -#endif - -static void mbed_minimal_formatted_string_long_int(char* buffer, size_t length, int* result, long int value) -{ - /* only continue if buffer can fit at least 1 characters */ - if ((*result + 1) <= (long int) length) - { - unsigned long int new_value = 0; - - /* if value is negative print sign and treat as positive number */ - if (value < 0) - { - /* write sign */ - if (buffer) - { - buffer[*result] = '-'; - } - else - { - MBED_PRINT_CHARACTER('-'); - } - - *result += 1; - - /* get absolute value */ - new_value = (unsigned long int) (-1 * value); - } - else - { - new_value = (unsigned long int) value; - } - - /* use unsigned long int function */ - mbed_minimal_formatted_string_unsigned_long_int(buffer, length, result, new_value); - } -} - -static void mbed_minimal_formatted_string_unsigned_long_int(char* buffer, size_t length, int* result, unsigned long int value) -{ - /* only continue if buffer can fit at least 1 characters */ - if ((*result + 1) <= (long int) length) - { - /* treat 0 as a corner case */ - if (value == 0) - { - if (buffer) - { - buffer[*result] = '0'; - } - else - { - MBED_PRINT_CHARACTER('0'); - } - - *result += 1; - } - else - { - /* allocate 3 digits per byte */ - char scratch[sizeof(unsigned long int) * 3] = { 0 }; - - size_t index = 0; - - /* write numbers in reverse order to scratch pad */ - for ( ; value > 0; index++) - { - /* use '0' as base and add digit */ - scratch[index] = '0' + (value % 10); - - /* shift value one decimal position */ - value = value / 10; - } - - /* write scratch pad to buffer or output */ - for ( ; (*result < (long int) length) && (index > 0); index--) - { - if (buffer) - { - buffer[*result] = scratch[index - 1]; - } - else - { - MBED_PRINT_CHARACTER(scratch[index - 1]); - } - - *result += 1; - } - } - } -} - -static void mbed_minimal_formatted_string_unsigned_char(char* buffer, size_t length, int* result, int value) -{ - /* only continue if buffer can fit at least 2 characters */ - if ((*result + 2) <= (long int) length) - { - unsigned int nibble_one = (value & 0xFF) >> 4; - unsigned int nibble_two = (value & 0x0F); - - const char int2hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - if (buffer) - { - buffer[*result] = int2hex[nibble_one]; - buffer[*result + 1] = int2hex[nibble_two]; - } - else - { - MBED_PRINT_CHARACTER(int2hex[nibble_one]); - MBED_PRINT_CHARACTER(int2hex[nibble_two]); - } - - *result += 2; - } -} - -static void mbed_minimal_formatted_string_void_pointer(char* buffer, size_t length, int* result, void* value) -{ - /* only continue if buffer can fit '0x' and twice the size of a void* */ - if ((*result + 2 + 2 * sizeof(void*)) <= length) - { - if (buffer) - { - buffer[*result] = '0'; - buffer[*result + 1] = 'x'; - } - else - { - MBED_PRINT_CHARACTER('0'); - MBED_PRINT_CHARACTER('x'); - } - - *result += 2; - - for (size_t index = 0; index < sizeof(void*); index++) - { - unsigned char byte = (unsigned char) (((unsigned long int) value) >> (8 * (sizeof(void*) - index - 1))); - - mbed_minimal_formatted_string_unsigned_char(buffer, length, result, byte); - } - } -} - -#if MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT -static void mbed_minimal_formatted_string_double(char* buffer, size_t length, int* result, double value) -{ - /* only continue if buffer can fit at least 1 characters */ - if ((*result + 1) <= (long int) length) - { - /* get integer part */ - long int integer = value; - - /* write integer part */ - mbed_minimal_formatted_string_long_int(buffer, length, result, integer); - - /* write decimal point */ - mbed_minimal_formatted_string_character(buffer, length, result, '.'); - - /* get decimal part */ - double precision = 1.0; - - for (size_t index = 0; index < MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT_MAX_DECIMALS; index++) - { - precision *= 10; - } - - long int decimal = (value - integer) * precision; - - /* take absolute value */ - if (decimal < 0) - { - decimal = -1 * decimal; - } - - /* write decimal part */ - mbed_minimal_formatted_string_long_int(buffer, length, result, decimal); - } -} -#endif - -static void mbed_minimal_formatted_string_character(char* buffer, size_t length, int* result, int character) -{ - /* only continue if the buffer can fit 1 character */ - if ((*result + 1) <= (long int) length) - { - if (buffer) - { - buffer[*result] = (char) character; - } - else - { - MBED_PRINT_CHARACTER((char) character); - } - - *result += 1; - } -} - -static void mbed_minimal_formatted_string_string(char* buffer, size_t length, int* result, char* string) -{ - /* only continue if the buffer can fit at least 1 character */ - if ((*result + 1) <= (long int) length) - { - /* count characters in string */ - size_t remaining = length - *result; - size_t string_length = 0; - - /* only count characters that will fit into buffer */ - while ((string[string_length] != '\0') && (string_length < remaining)) - { - string_length++; - } - - /* copy string to buffer */ - if (buffer) - { - for (size_t index = 0; index < string_length; index++) - { - buffer[*result + index] = string[index]; - } - } - /* print string */ - else - { - for (size_t index = 0; index < string_length; index++) - { - MBED_PRINT_CHARACTER(string[index]); - } - } - - /* add length to counter */ - *result += string_length; - } -} - -static int mbed_minimal_formatted_string(char* buffer, size_t length, const char* format, va_list arguments) -{ - int result = 0; - - /* if writing to buffer, reserve space for NULL termination */ - if (buffer) - { - length--; - } - - /* parse string */ - for (size_t index = 0; format[index] != '\0'; index++) - { - /* format specifier begin */ - if (format[index] == '%') - { - size_t next_index = index + 1; - - /* while there is room in buffer and format string is not empty */ - while ((next_index < length) && (format[next_index] != '\0') && - /* skip all size modifiers */ - (((format[next_index] >= '0') && (format[next_index] <= '9')) || - (format[next_index] == 'h') || - (format[next_index] == 'l') || - (format[next_index] == 'j') || - (format[next_index] == 'z') || - (format[next_index] == 't') || - (format[next_index] == 'L') || - (format[next_index] == '.'))) - { - /* skip to next character */ - next_index++; - } - - /* read out character - this a supported format character, '\0', or a not suported character */ - char next = format[next_index]; - - /* signed integer */ - if ((next == 'd') || (next == 'i')) - { - long int value = va_arg(arguments, long int); - index = next_index; - - mbed_minimal_formatted_string_long_int(buffer, length, &result, value); - } - /* unsigned integer */ - else if (next == 'u') - { - unsigned long int value = va_arg(arguments, unsigned long int); - index = next_index; - - mbed_minimal_formatted_string_unsigned_long_int(buffer, length, &result, value); - } - /* treat both hexadecimeal modifiers the same */ - else if ((next == 'x') || (next == 'X')) - { - int value = va_arg(arguments, int); - index = next_index; - - mbed_minimal_formatted_string_unsigned_char(buffer, length, &result, value); - } -#if MBED_CONF_MINIMAL_PRINTF_FLOATING_POINT - /* treat all floating points the same */ - else if ((next == 'f') || (next == 'F') || (next == 'g') || (next == 'G')) - { - double value = va_arg(arguments, double); - index = next_index; - - mbed_minimal_formatted_string_double(buffer, length, &result, value); - } -#endif - /* character */ - else if (next == 'c') - { - int value = va_arg(arguments, int); - index = next_index; - - mbed_minimal_formatted_string_character(buffer, length, &result, value); - } - /* string */ - else if (next == 's') - { - char* value = va_arg(arguments, char*); - index = next_index; - - mbed_minimal_formatted_string_string(buffer, length, &result, value); - } - /* pointer */ - else if (next == 'p') - { - void* value = va_arg(arguments, void*); - index = next_index; - - mbed_minimal_formatted_string_void_pointer(buffer, length, &result, value); - } - else - { - /* write all characters between format beginning and unrecognied modifier */ - while (index < next_index) - { - mbed_minimal_formatted_string_character(buffer, length, &result, format[index]); - 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]); - } - else - { - /* break out of for loop */ - break; - } - } - } - else - { - mbed_minimal_formatted_string_character(buffer, length, &result, format[index]); - } - } - - /* if writing to buffer, NULL terminate string in reserved space*/ - if (buffer) - { - buffer[result] = '\0'; - } - - return result; -} int mbed_printf(const char *format, ...) { - MBED_INITIALIZE_PRINT(); - va_list arguments; va_start(arguments, format); int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments); @@ -460,8 +30,6 @@ int mbed_printf(const char *format, ...) int mbed_snprintf(char* buffer, size_t length, const char* format, ...) { - MBED_INITIALIZE_PRINT(); - va_list arguments; va_start(arguments, format); int result = mbed_minimal_formatted_string(buffer, length, format, arguments); diff --git a/features/minimal-printf/mbed_printf.h b/features/minimal-printf/mbed_printf.h index f64358f1bf..0b8f6652bf 100755 --- a/features/minimal-printf/mbed_printf.h +++ b/features/minimal-printf/mbed_printf.h @@ -18,6 +18,7 @@ #define MBED_PRINTF_H #include +#include #ifdef __cplusplus extern "C" { @@ -27,14 +28,6 @@ extern "C" { * Minimal printf * * Prints directly to stdio/UART without using malloc. - * Doesn't suppoet any modifiers. - * - * Supports: - * %d: signed long int - * %u: unsigned long int - * %p: void* (e.g. 0x00123456) - * %s: string - * %X: unsigned char printed as hexadecimal number (e.g., FF) */ int mbed_printf(const char *format, ...); @@ -42,14 +35,6 @@ int mbed_printf(const char *format, ...); * Minimal snprintf * * Prints directly to buffer without using malloc. - * Doesn't suppoet any modifiers. - * - * Supports: - * %d: signed long int - * %u: unsigned long int - * %p: void* (e.g. 0x00123456) - * %s: string - * %X: unsigned char printed as hexadecimal number (e.g., FF) */ int mbed_snprintf(char* buffer, size_t length, const char* format, ...); @@ -57,14 +42,6 @@ int mbed_snprintf(char* buffer, size_t length, const char* format, ...); * Minimal printf * * Prints directly to stdio/UART without using malloc. - * Doesn't suppoet any modifiers. - * - * Supports: - * %d: signed long int - * %u: unsigned long int - * %p: void* (e.g. 0x00123456) - * %s: string - * %X: unsigned char printed as hexadecimal number (e.g., FF) */ int mbed_vprintf(const char* format, va_list arguments); @@ -72,14 +49,6 @@ int mbed_vprintf(const char* format, va_list arguments); * Minimal snprintf * * Prints directly to buffer without using malloc. - * Doesn't suppoet any modifiers. - * - * Supports: - * %d: signed long int - * %u: unsigned long int - * %p: void* (e.g. 0x00123456) - * %s: string - * %X: unsigned char printed as hexadecimal number (e.g., FF) */ int mbed_vsnprintf(char* buffer, size_t length, const char* format, va_list arguments); diff --git a/features/minimal-printf/mbed_printf_implementation.c b/features/minimal-printf/mbed_printf_implementation.c new file mode 100755 index 0000000000..6d91b84b6f --- /dev/null +++ b/features/minimal-printf/mbed_printf_implementation.c @@ -0,0 +1,756 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_printf_implementation.h" + + + +/***************************/ +/* MBED */ +/***************************/ +#if TARGET_LIKE_MBED +/* + Serial initialization and new line replacement is a direct copy from mbed_retarget.cpp + If the static modifier were to be removed, this part of the code would not be necessary. +*/ +#include "hal/serial_api.h" + +#if DEVICE_SERIAL +static serial_t stdio_uart = { 0 }; +#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES +static char mbed_stdio_out_prev = 0; +#endif +#endif + +/* module variable for keeping track of initialization */ +static bool not_initialized = true; + +static void init_serial() +{ + if (not_initialized) + { + not_initialized = false; + +#if DEVICE_SERIAL + serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); +#if MBED_CONF_PLATFORM_STDIO_BAUD_RATE + serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); +#endif +#endif + } +} + +#define MBED_INITIALIZE_PRINT(x) { init_serial(); } +#define MBED_PRINT_CHARACTER(x) { serial_putc(&stdio_uart, x); } + +/***************************/ +/* Linux */ +/***************************/ +#else +/* Linux implementation is for debug only */ +#define MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 1 +#define MBED_CONF_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6 +#define MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT 1 +#define MBED_INITIALIZE_PRINT(x) { ; } +#define MBED_PRINT_CHARACTER(x) { printf("%c", x); } +#endif + +#ifndef MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT +#define MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 0 +#endif + +#ifndef MBED_CONF_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS +#define MBED_CONF_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6 +#endif + +#ifndef MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT +#define MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT 1 +#endif + +/** + * Check architecture and choose storage data type. + * On 32 bit machines, the default storage type is 32 bit wide + * unless 64 bit integers are enabled in the configuration. + */ +#if INTPTR_MAX == INT32_MAX +#define MBED_SIGNED_NATIVE_TYPE int32_t +#define MBED_UNSIGNED_NATIVE_TYPE uint32_t +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT +#define MBED_SIGNED_STORAGE int64_t +#define MBED_UNSIGNED_STORAGE uint64_t +#else +#define MBED_SIGNED_STORAGE int32_t +#define MBED_UNSIGNED_STORAGE uint32_t +#endif + +#elif INTPTR_MAX == INT64_MAX +#define MBED_SIGNED_NATIVE_TYPE int64_t +#define MBED_UNSIGNED_NATIVE_TYPE uint64_t +#define MBED_SIGNED_STORAGE int64_t +#define MBED_UNSIGNED_STORAGE uint64_t +#else +#error unsupported architecture +#endif + +/** + * Enum for storing width modifier. + */ +typedef enum { + LENGTH_NONE, + LENGTH_HH, + LENGTH_H, + LENGTH_L, + LENGTH_LL, + LENGTH_J, + LENGTH_Z, + LENGTH_T, + LENGTH_CAPITAL_L +} length_t; + +/** + * Prototypes + */ +static void mbed_minimal_formatted_string_signed(char* buffer, size_t length, int* result, MBED_SIGNED_STORAGE value); +static void mbed_minimal_formatted_string_unsigned(char* buffer, size_t length, int* result, MBED_UNSIGNED_STORAGE value); +static void mbed_minimal_formatted_string_hexadecimal(char* buffer, size_t length, int* result, MBED_UNSIGNED_STORAGE value); +static void mbed_minimal_formatted_string_void_pointer(char* buffer, size_t length, int* result, void* value); +static void mbed_minimal_formatted_string_character(char* buffer, size_t length, int* result, char character); +static void mbed_minimal_formatted_string_string(char* buffer, size_t length, int* result, char* string); + +/** + * @brief Print signed integer. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The value to be printed. + */ +static void mbed_minimal_formatted_string_signed(char* buffer, size_t length, int* result, MBED_SIGNED_STORAGE value) +{ + /* only continue if buffer can fit at least 1 characters */ + if ((size_t)(*result + 1) <= length) + { + MBED_UNSIGNED_STORAGE new_value = 0; + + /* if value is negative print sign and treat as positive number */ + if (value < 0) + { + /* write sign */ + if (buffer) + { + buffer[*result] = '-'; + } + else + { + MBED_PRINT_CHARACTER('-'); + } + + *result += 1; + + /* get absolute value using two's complement */ + new_value = ~((MBED_UNSIGNED_STORAGE) value) + 1; + } + else + { + new_value = value; + } + + /* use unsigned long int function */ + mbed_minimal_formatted_string_unsigned(buffer, length, result, new_value); + } +} + +/** + * @brief Print unsigned integer. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The value to be printed. + */ +static void mbed_minimal_formatted_string_unsigned(char* buffer, size_t length, int* result, MBED_UNSIGNED_STORAGE value) +{ + /* only continue if buffer can fit at least 1 characters */ + if ((size_t)(*result + 1) <= length) + { + /* treat 0 as a corner case */ + if (value == 0) + { + if (buffer) + { + buffer[*result] = '0'; + } + else + { + MBED_PRINT_CHARACTER('0'); + } + + *result += 1; + } + else + { + /* allocate 3 digits per byte */ + char scratch[sizeof(MBED_UNSIGNED_STORAGE) * 3] = { 0 }; + + size_t index = 0; + + /* write numbers in reverse order to scratch pad */ + for ( ; value > 0; index++) + { + /* use '0' as base and add digit */ + scratch[index] = '0' + (value % 10); + + /* shift value one decimal position */ + value = value / 10; + } + + /* write scratch pad to buffer or output */ + for ( ; ((size_t)*result < length) && (index > 0); index--) + { + if (buffer) + { + buffer[*result] = scratch[index - 1]; + } + else + { + MBED_PRINT_CHARACTER(scratch[index - 1]); + } + + *result += 1; + } + } + } +} + +/** + * @brief Print hexadecimal. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The value to be printed. + */ +static void mbed_minimal_formatted_string_hexadecimal(char* buffer, size_t length, int* result, MBED_UNSIGNED_STORAGE value) +{ + bool print_leading_zero = false; + + /* only continue each loop if buffer can fit at least 2 characters */ + for (ssize_t index = 7; (((size_t)(*result + 2) <= length)) && (index >= 0); index--) + { + /* get most significant byte */ + uint8_t output = value >> (8 * index); + + /* only print leading zeros when set */ + if (print_leading_zero || (output != 0) || (index == 0)) + { + /* print zeroes after the first non-zero byte */ + print_leading_zero = true; + + unsigned int nibble_one = (output >> 4); + unsigned int nibble_two = (output & 0x0F); + + const char int2hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + /* write to buffer or stdout */ + if (buffer) + { + buffer[*result] = int2hex[nibble_one]; + buffer[*result + 1] = int2hex[nibble_two]; + } + else + { + MBED_PRINT_CHARACTER(int2hex[nibble_one]); + MBED_PRINT_CHARACTER(int2hex[nibble_two]); + } + + *result += 2; + } + } +} + +/** + * @brief Print pointer. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The pointer to be printed. + */ +static void mbed_minimal_formatted_string_void_pointer(char* buffer, size_t length, int* result, void* value) +{ + /* only continue if buffer can fit '0x' and twice the size of a void* */ + if ((*result + 2 + 2 * sizeof(void*)) <= length) + { + /* write leading 0x */ + if (buffer) + { + buffer[*result] = '0'; + buffer[*result + 1] = 'x'; + } + else + { + MBED_PRINT_CHARACTER('0'); + MBED_PRINT_CHARACTER('x'); + } + + *result += 2; + + /* write rest as a regular hexadecimal number */ + mbed_minimal_formatted_string_hexadecimal(buffer, length, result, (ptrdiff_t) value); + } +} + +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT +/** + * @brief Write double. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The value to be printed. + */ +static void mbed_minimal_formatted_string_double(char* buffer, size_t length, int* result, double value) +{ + /* only continue if buffer can fit at least 1 characters */ + if ((size_t)(*result + 1) <= length) + { + /* get integer part */ + MBED_SIGNED_STORAGE integer = value; + + /* write integer part */ + mbed_minimal_formatted_string_signed(buffer, length, result, integer); + + /* write decimal point */ + mbed_minimal_formatted_string_character(buffer, length, result, '.'); + + /* get decimal part */ + double precision = 1.0; + + for (size_t index = 0; index < MBED_CONF_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS; index++) + { + precision *= 10; + } + + value = (value - integer) * precision; + + /* convert to unsigned integer */ + MBED_UNSIGNED_STORAGE decimal = 0; + + if (value < 0) + { + MBED_SIGNED_STORAGE temp = value; + decimal = ~((MBED_UNSIGNED_STORAGE) temp) + 1; + } + else + { + decimal = value; + } + + /* round up or down */ + value -= decimal; + + if (!((value > -0.5) && (value < 0.5))) + { + decimal++; + } + + /* write decimal part */ + mbed_minimal_formatted_string_unsigned(buffer, length, result, decimal); + } +} +#endif + +/** + * @brief Print character. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The character to be printed. + */ +static void mbed_minimal_formatted_string_character(char* buffer, size_t length, int* result, char character) +{ + /* only continue if the buffer can fit 1 character */ + if ((size_t)(*result + 1) <= length) + { + /* write character */ + if (buffer) + { + buffer[*result] = character; + } + else + { + /* convert \n to \r\n if enabled in platform configuration */ +#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES + if (character == '\n' && mbed_stdio_out_prev != '\r') + { + MBED_PRINT_CHARACTER('\r'); + *result += 1; + } + + /* cache character */ + mbed_stdio_out_prev = character; +#endif + + /* write character to stdout */ + MBED_PRINT_CHARACTER(character); + } + + *result += 1; + } +} + +/** + * @brief Print string. + * + * @param buffer The buffer to store output (NULL for stdout). + * @param[in] length The length of the buffer. + * @param result The current output location. + * @param[in] value The string to be printed. + */ +static void mbed_minimal_formatted_string_string(char* buffer, size_t length, int* result, char* string) +{ + /* only continue if the buffer can fit at least 1 character */ + if ((size_t)(*result + 1) <= length) + { + /* count characters in string */ + size_t remaining = length - *result; + size_t string_length = 0; + + /* only count characters that will fit into buffer */ + while ((string[string_length] != '\0') && (string_length < remaining)) + { + string_length++; + } + + /* copy string to buffer */ + if (buffer) + { + for (size_t index = 0; index < string_length; index++) + { + buffer[*result + index] = string[index]; + } + } + /* print string */ + else + { + for (size_t index = 0; index < string_length; index++) + { + MBED_PRINT_CHARACTER(string[index]); + } + } + + /* add length to counter */ + *result += string_length; + } +} + +/** + * @brief Parse formatted string and invoke write handlers based on type. + * + * @param buffer The buffer to write to, write to stdout if NULL. + * @param[in] length The length of the buffer. + * @param[in] format The formatted string. + * @param[in] arguments The va_list arguments. + * + * @return Number of characters written. + */ +int mbed_minimal_formatted_string(char* buffer, size_t length, const char* format, va_list arguments) +{ + /* initialize output if needed */ + MBED_INITIALIZE_PRINT(); + + int result = 0; + + /* if writing to buffer, reserve space for NULL termination */ + if (buffer) + { + length--; + } + + /* parse string */ + for (size_t index = 0; format[index] != '\0'; index++) + { + /* format specifier begin */ + if (format[index] == '%') + { + size_t next_index = index + 1; + + /* while there is room in buffer and format string is not empty */ + while ((next_index < length) && (format[next_index] != '\0') && + /* skip all flags and precision modifiers */ + (((format[next_index] >= '0') && (format[next_index] <= '9')) || + (format[next_index] == '-') || + (format[next_index] == '+') || + (format[next_index] == '#') || + (format[next_index] == '.'))) + { + /* skip to next character */ + next_index++; + } + + /* look for length modifier, default to NONE */ + length_t length_modifier = LENGTH_NONE; + + /* look for two character length modifier */ + if (format[next_index + 1] != '\0') + { + if ((format[next_index] == 'h') && (format[next_index + 1] == 'h')) + { + length_modifier = LENGTH_HH; + } + else if ((format[next_index] == 'l') && (format[next_index + 1] == 'l')) + { + length_modifier = LENGTH_LL; + } + + /* increment next_index if length modifier was found */ + if (length_modifier != LENGTH_NONE) + { + next_index += 2; + } + } + + /* look for one character length modifier if two character search failed */ + if ((length_modifier == LENGTH_NONE) && (format[next_index] != '\0')) + { + if (format[next_index] == 'h') + { + length_modifier = LENGTH_H; + } + else if (format[next_index] == 'l') + { + length_modifier = LENGTH_L; + } + else if (format[next_index] == 'j') + { + length_modifier = LENGTH_J; + } + else if (format[next_index] == 'z') + { + length_modifier = LENGTH_Z; + } + else if (format[next_index] == 't') + { + length_modifier = LENGTH_T; + } + else if (format[next_index] == 'L') + { + length_modifier = LENGTH_CAPITAL_L; + } + + /* increment next_index if length modifier was found */ + if (length_modifier != LENGTH_NONE) + { + next_index++; + } + } + + /* read out character - this is a supported format character, '\0', or a not suported character */ + char next = format[next_index]; + + /* signed integer */ + if ((next == 'd') || (next == 'i')) + { + MBED_SIGNED_STORAGE value = 0; + +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT + /* if 64 bit is enabled and the integer types are larger than the native type */ + if (((length_modifier == LENGTH_LL) && (sizeof(long long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) || + ((length_modifier == LENGTH_L) && (sizeof(long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) || + ((length_modifier == LENGTH_NONE) && (sizeof(int) > sizeof(MBED_SIGNED_NATIVE_TYPE)))) + { + /* use 64 bit storage type for readout */ + value = va_arg(arguments, MBED_SIGNED_STORAGE); + } + else +#endif + { + /* use native storage type (which can be 32 or 64 bit) */ + value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); + } + + /* constrict value based on lenght modifier */ + switch (length_modifier) + { + case LENGTH_NONE: + value = (int) value; + break; + case LENGTH_HH: + value = (signed char) value; + break; + case LENGTH_H: + value = (short int) value; + break; + case LENGTH_L: + value = (long int) value; + break; + case LENGTH_LL: + value = (long long int) value; + break; + case LENGTH_J: + value = (intmax_t) value; + break; + case LENGTH_Z: + value = (ssize_t) value; + break; + case LENGTH_T: + value = (ptrdiff_t) value; + break; + default: + break; + } + + index = next_index; + + mbed_minimal_formatted_string_signed(buffer, length, &result, value); + } + /* unsigned integer */ + else if ((next == 'u') || (next == 'x') || (next == 'X')) + { + MBED_UNSIGNED_STORAGE value = 0; + +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_64_BIT + /* if 64 bit is enabled and the integer types are larger than the native type */ + if (((length_modifier == LENGTH_LL) && (sizeof(unsigned long long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) || + ((length_modifier == LENGTH_L) && (sizeof(unsigned long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) || + ((length_modifier == LENGTH_NONE) && (sizeof(unsigned int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE)))) + { + /* use 64 bit storage type for readout */ + value = va_arg(arguments, MBED_UNSIGNED_STORAGE); + } + else +#endif + { + /* use native storage type (which can be 32 or 64 bit) */ + value = va_arg(arguments, MBED_UNSIGNED_NATIVE_TYPE); + } + + /* constrict value based on lenght modifier */ + switch (length_modifier) + { + case LENGTH_NONE: + value = (unsigned int) value; + break; + case LENGTH_HH: + value = (unsigned char) value; + break; + case LENGTH_H: + value = (unsigned short int) value; + break; + case LENGTH_L: + value = (unsigned long int) value; + break; + case LENGTH_LL: + value = (unsigned long long int) value; + break; + case LENGTH_J: + value = (uintmax_t) value; + break; + case LENGTH_Z: + value = (size_t) value; + break; + case LENGTH_T: + value = (ptrdiff_t) value; + break; + default: + break; + } + + index = next_index; + + /* write unsigned or hexadecimal */ + if (next == 'u') + { + mbed_minimal_formatted_string_unsigned(buffer, length, &result, value); + } + else + { + mbed_minimal_formatted_string_hexadecimal(buffer, length, &result, value); + } + } +#if MBED_CONF_MINIMAL_PRINTF_ENABLE_FLOATING_POINT + /* treat all floating points the same */ + else if ((next == 'f') || (next == 'F') || (next == 'g') || (next == 'G')) + { + double value = va_arg(arguments, double); + index = next_index; + + mbed_minimal_formatted_string_double(buffer, length, &result, value); + } +#endif + /* character */ + else if (next == 'c') + { + char value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); + index = next_index; + + mbed_minimal_formatted_string_character(buffer, length, &result, value); + } + /* string */ + else if (next == 's') + { + char* value = va_arg(arguments, char*); + index = next_index; + + mbed_minimal_formatted_string_string(buffer, length, &result, value); + } + /* pointer */ + else if (next == 'p') + { + void* value = va_arg(arguments, void*); + index = next_index; + + mbed_minimal_formatted_string_void_pointer(buffer, length, &result, value); + } + else + { + /* write all characters between format beginning and unrecognied modifier */ + while (index < next_index) + { + mbed_minimal_formatted_string_character(buffer, length, &result, format[index]); + 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]); + } + else + { + /* break out of for loop */ + break; + } + } + } + else + /* not a format specifier */ + { + /* write normal character */ + mbed_minimal_formatted_string_character(buffer, length, &result, format[index]); + } + } + + /* if writing to buffer, NULL terminate string in reserved space*/ + if (buffer) + { + buffer[result] = '\0'; + } + + return result; +} diff --git a/features/minimal-printf/mbed_printf_implementation.h b/features/minimal-printf/mbed_printf_implementation.h new file mode 100644 index 0000000000..a74d469dbf --- /dev/null +++ b/features/minimal-printf/mbed_printf_implementation.h @@ -0,0 +1,20 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +int mbed_minimal_formatted_string(char* buffer, size_t length, const char* format, va_list arguments); diff --git a/features/minimal-printf/mbed_printf_wrapper.c b/features/minimal-printf/mbed_printf_wrapper.c new file mode 100644 index 0000000000..f6b0d76435 --- /dev/null +++ b/features/minimal-printf/mbed_printf_wrapper.c @@ -0,0 +1,79 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_printf_implementation.h" + +#include + +#if defined(TOOLCHAIN_GCC) +#define SUB_PRINTF __wrap_printf +#define SUB_SNPRINTF __wrap_snprintf +#define SUB_SPRINTF __wrap_sprintf +#define SUB_VSNPRINTF __wrap_vsnprintf +#elif defined(TOOLCHAIN_ARM) +#define SUPER_PRINTF $Super$$printf +#define SUB_PRINTF $Sub$$printf +#define SUPER_SNPRINTF $Super$$snprintf +#define SUB_SNPRINTF $Sub$$snprintf +#define SUPER_SPRINTF $Super$$sprintf +#define SUB_SPRINTF $Sub$$sprintf +#define SUPER_VSNPRINTF $Super$$vsnprintf +#define SUB_VSNPRINTF $Sub$$vsnprintf +#elif defined(__ICCARM__) +#define SUPER_PRINTF $Super$$__iar_printf +#define SUB_PRINTF $Sub$$__iar_printf +#define SUPER_SNPRINTF $Super$$__iar_snprintf +#define SUB_SNPRINTF $Sub$$__iar_snprintf +#define SUPER_SPRINTF $Super$$__iar_sprintf +#define SUB_SPRINTF $Sub$$__iar_sprintf +#define SUPER_VSNPRINTF $Super$$__iar_vsnprintf +#define SUB_VSNPRINTF $Sub$$__iar_vsnprintf +#endif + +int SUB_PRINTF(const char *format, ...) +{ + va_list arguments; + va_start(arguments, format); + int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments); + va_end(arguments); + + return result; +} + +int SUB_SNPRINTF(char* buffer, size_t length, const char* format, ...) +{ + va_list arguments; + va_start(arguments, format); + int result = mbed_minimal_formatted_string(buffer, length, format, arguments); + va_end(arguments); + + return result; +} + +int SUB_SPRINTF(char* buffer, const char* format, ...) +{ + va_list arguments; + va_start(arguments, format); + int result = mbed_minimal_formatted_string(buffer, LONG_MAX, format, arguments); + va_end(arguments); + + return result; +} + +int SUB_VSNPRINTF(char* buffer, size_t length, const char* format, va_list arguments) +{ + return mbed_minimal_formatted_string(buffer, length, format, arguments); +}