diff --git a/Sming/System/include/m_printf.h b/Sming/System/include/m_printf.h index ed36499842..46e74ea98a 100644 --- a/Sming/System/include/m_printf.h +++ b/Sming/System/include/m_printf.h @@ -37,10 +37,10 @@ nputs_callback_t m_setPuts(nputs_callback_t callback); extern "C" { #endif -int m_vsnprintf(char* buf, size_t maxLen, const char* fmt, va_list args); -int m_snprintf(char* buf, int length, const char* fmt, ...); -int m_printf(char const*, ...); -int m_vprintf(const char* format, va_list arg); +int m_vsnprintf(char* buf, size_t maxLen, const char* fmt, va_list args) __attribute__((format(printf, 3, 0))); +int m_snprintf(char* buf, int length, const char* fmt, ...) __attribute__((format(printf, 3, 4))); +int m_printf(char const*, ...) __attribute__((format(printf, 1, 2))); +int m_vprintf(const char* format, va_list arg) __attribute__((format(printf, 1, 0))); /** @brief output a single character * @param c diff --git a/Sming/System/m_printf.cpp b/Sming/System/m_printf.cpp index 46b29172ac..de12db413a 100644 --- a/Sming/System/m_printf.cpp +++ b/Sming/System/m_printf.cpp @@ -28,6 +28,18 @@ static nputs_callback_t _puts_callback; #define is_digit(c) ((c) >= '0' && (c) <= '9') #define is_print(c) ((c) >= ' ' && (c) <= '~') +static char to_upper(char c) +{ + return (c >= 'a' && c <= 'z') ? (c + 'A' - 'a') : c; +} + +static void str_upper(char* s) +{ + for(; *s != '\0'; ++s) { + *s = to_upper(*s); + } +} + static int skip_atoi(const char **s) { int i = 0; @@ -125,6 +137,8 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) int8_t precision = -1; int8_t width = 0; char pad = ' '; + uint8_t length = 0; + bool upcase = false; while (char f = *fmt) { if (f == '-') minus = 1; @@ -152,8 +166,19 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) if ( is_digit(*fmt) ) precision = skip_atoi(&fmt); } - // ignore length - while (*fmt == 'l' || *fmt == 'h' || *fmt == 'L') fmt++; + // while (*fmt == 'l' || *fmt == 'h' || *fmt == 'L') fmt++; + + // process length + do { + if ( *fmt == 'l' ) { + ++length; + ++fmt; + } else if ( *fmt == 'h' || *fmt == 'L' ) { + ++fmt; // ignore + } else { + break; + } + } while(true); // process type switch (char f = *fmt++) { @@ -202,8 +227,12 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) break; case 'x': + ubase = 16; + break; + case 'X': ubase = 16; + upcase = true; break; case 'u': @@ -217,7 +246,16 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) } // format unsigned numbers - if (ubase) s = ultoa_wp(va_arg(args, unsigned int), tempNum, ubase, width, pad); + if (ubase != 0) { + if(length >= 2) { + s = ulltoa_wp(va_arg(args, uint64_t), tempNum, ubase, width, pad); + } else { + s = ultoa_wp(va_arg(args, uint32_t), tempNum, ubase, width, pad); + } + if (upcase) { + str_upper(tempNum); + } + } // copy string to target while (*s) add(*s++); diff --git a/tests/HostTests/modules/Libc.cpp b/tests/HostTests/modules/Libc.cpp index 2ae0596fa1..73f0183068 100644 --- a/tests/HostTests/modules/Libc.cpp +++ b/tests/HostTests/modules/Libc.cpp @@ -66,6 +66,21 @@ class LibcTest : public TestGroup REQUIRE(isRomPtr(strstr)); } #endif + + TEST_CASE("64-bit mprintf") + { + char buffer[256]; + m_snprintf(buffer, sizeof(buffer), "%x", 0x12345678); + REQUIRE_EQ(String(buffer), "12345678"); + m_snprintf(buffer, sizeof(buffer), "%u", 12345678); + REQUIRE_EQ(String(buffer), "12345678"); + m_snprintf(buffer, sizeof(buffer), "%llx", 0x123456789ABCDEFULL); + REQUIRE_EQ(String(buffer), "123456789abcdef"); + m_snprintf(buffer, sizeof(buffer), "0x%016llX", 0x123456789ABCDEFULL); + REQUIRE_EQ(String(buffer), "0x0123456789ABCDEF"); + m_snprintf(buffer, sizeof(buffer), "%llu", 123456789123456789ULL); + REQUIRE_EQ(String(buffer), "123456789123456789"); + } } }; diff --git a/tests/HostTests/modules/Stream.cpp b/tests/HostTests/modules/Stream.cpp index 0f52776c96..d360be6d1d 100644 --- a/tests/HostTests/modules/Stream.cpp +++ b/tests/HostTests/modules/Stream.cpp @@ -95,7 +95,7 @@ class StreamTest : public TestGroup TEST_CASE("ChunkedStream / StreamTransformer") { DEFINE_FSTR_LOCAL(FS_INPUT, "Some test data"); - DEFINE_FSTR_LOCAL(FS_OUTPUT, "e\r\nSome test data\r\n0\r\n\r\n"); + DEFINE_FSTR_LOCAL(FS_OUTPUT, "E\r\nSome test data\r\n0\r\n\r\n"); ChunkedStream chunked(new FlashMemoryStream(FS_INPUT)); MemoryDataStream output; output.copyFrom(&chunked);