From 41750c31cfcd46ddafaeb6328f952368639341e3 Mon Sep 17 00:00:00 2001 From: jzlv Date: Fri, 25 Nov 2022 20:17:49 +0800 Subject: [PATCH] [feat][util] add vsnprintf nano, reduce codesize for boot2 --- utils/CMakeLists.txt | 7 +- utils/libc/printf.c | 4 + utils/libc/vsnprintf_nano.c | 524 ++++++++++++++++++++++++++++++++++++ 3 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 utils/libc/vsnprintf_nano.c diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 6a1ebf71..2f98b98c 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -59,7 +59,12 @@ if(CONFIG_VLIBC) sdk_library_add_sources(vlibc/vlibc_vsnprintf.c) sdk_add_include_directories(vlibc) else() + if(CONFIG_VSNPRINTF_NANO) + sdk_library_add_sources(libc/vsnprintf_nano.c) + else() sdk_library_add_sources(libc/vsnprintf.c) + endif() + sdk_library_add_sources(libc/syscalls.c) sdk_library_add_sources(libc/printf.c) endif() @@ -106,4 +111,4 @@ sdk_library_add_sources(bflb_timestamp/bflb_timestamp.c) sdk_add_include_directories(bflb_timestamp) sdk_add_compile_options(-fno-builtin-printf) -sdk_add_link_options(-u_malloc_r -u_vsnprintf) \ No newline at end of file +# sdk_add_link_options(-u_malloc_r -u_vsnprintf) \ No newline at end of file diff --git a/utils/libc/printf.c b/utils/libc/printf.c index 969b60d0..6faee0e1 100644 --- a/utils/libc/printf.c +++ b/utils/libc/printf.c @@ -9,6 +9,10 @@ int printf(const char *fmt, ...) uint32_t len; va_list ap; + if (console == NULL) { + return 0; + } + va_start(ap, fmt); len = vsnprintf(print_buf, sizeof(print_buf), fmt, ap); va_end(ap); diff --git a/utils/libc/vsnprintf_nano.c b/utils/libc/vsnprintf_nano.c new file mode 100644 index 00000000..a7d3637a --- /dev/null +++ b/utils/libc/vsnprintf_nano.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-16 Bernard the first version + * 2006-05-25 Bernard rewrite vsprintf + * 2006-08-10 Bernard add rt_show_version + * 2010-03-17 Bernard remove rt_strlcpy function + * fix gcc compiling issue. + * 2010-04-15 Bernard remove weak definition on ICCM16C compiler + * 2012-07-18 Arda add the alignment display for signed integer + * 2012-11-23 Bernard fix IAR compiler error. + * 2012-12-22 Bernard fix rt_kprintf issue, which found by Grissiom. + * 2013-06-24 Bernard remove rt_kprintf if RT_USING_CONSOLE is not defined. + * 2013-09-24 aozima make sure the device is in STREAM mode when used by rt_kprintf. + * 2015-07-06 Bernard Add rt_assert_handler routine. + * 2021-02-28 Meco Man add RT_KSERVICE_USING_STDLIB + */ + +#include "string.h" +#include "stdint.h" +#include "stdarg.h" + +/* use precision */ +#define RT_PRINTF_PRECISION + +/* private function */ +#define _ISDIGIT(c) ((unsigned)((c) - '0') < 10) + +#ifdef RT_PRINTF_LONGLONG +/** + * This function will duplicate a string. + * + * @param n is the string to be duplicated. + * + * @param base is support divide instructions value. + * + * @return the duplicated string pointer. + */ +static inline int divide(long long *n, int base) +{ + int res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) { + res = (int)(((unsigned long long)*n) % 10U); + *n = (long long)(((unsigned long long)*n) / 10U); + } else { + res = (int)(((unsigned long long)*n) % 16U); + *n = (long long)(((unsigned long long)*n) / 16U); + } + + return res; +} +#else +static inline int divide(long *n, int base) +{ + int res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) { + res = (int)(((unsigned long)*n) % 10U); + *n = (long)(((unsigned long)*n) / 10U); + } else { + res = (int)(((unsigned long)*n) % 16U); + *n = (long)(((unsigned long)*n) / 16U); + } + + return res; +} +#endif /* RT_PRINTF_LONGLONG */ + +static inline int skip_atoi(const char **s) +{ + register int i = 0; + while (_ISDIGIT(**s)) + i = i * 10 + *((*s)++) - '0'; + + return i; +} + +#define ZEROPAD (1 << 0) /* pad with zero */ +#define SIGN (1 << 1) /* unsigned/signed long */ +#define PLUS (1 << 2) /* show plus */ +#define SPACE (1 << 3) /* space if plus */ +#define LEFT (1 << 4) /* left justified */ +#define SPECIAL (1 << 5) /* 0x */ +#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */ + +#ifdef RT_PRINTF_PRECISION +static char *print_number(char *buf, + char *end, +#ifdef RT_PRINTF_LONGLONG + long long num, +#else + long num, +#endif /* RT_PRINTF_LONGLONG */ + int base, + int s, + int precision, + int type) +#else +static char *print_number(char *buf, + char *end, +#ifdef RT_PRINTF_LONGLONG + long long num, +#else + long num, +#endif /* RT_PRINTF_LONGLONG */ + int base, + int s, + int type) +#endif /* RT_PRINTF_PRECISION */ +{ + char c, sign; +#ifdef RT_PRINTF_LONGLONG + char tmp[32]; +#else + char tmp[16]; +#endif /* RT_PRINTF_LONGLONG */ + int precision_bak = precision; + const char *digits; + static const char small_digits[] = "0123456789abcdef"; + static const char large_digits[] = "0123456789ABCDEF"; + register int i; + register int size; + + size = s; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + + c = (type & ZEROPAD) ? '0' : ' '; + + /* get sign */ + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + } else if (type & PLUS) + sign = '+'; + else if (type & SPACE) + sign = ' '; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } +#endif /* RT_PRINTF_SPECIAL */ + + i = 0; + if (num == 0) + tmp[i++] = '0'; + else { + while (num != 0) + tmp[i++] = digits[divide(&num, base)]; + } + +#ifdef RT_PRINTF_PRECISION + if (i > precision) + precision = i; + size -= precision; +#else + size -= i; +#endif /* RT_PRINTF_PRECISION */ + + if (!(type & (ZEROPAD | LEFT))) { + if ((sign) && (size > 0)) + size--; + + while (size-- > 0) { + if (buf < end) + *buf = ' '; + ++buf; + } + } + + if (sign) { + if (buf < end) { + *buf = sign; + } + --size; + ++buf; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) { + if (base == 8) { + if (buf < end) + *buf = '0'; + ++buf; + } else if (base == 16) { + if (buf < end) + *buf = '0'; + ++buf; + if (buf < end) { + *buf = type & LARGE ? 'X' : 'x'; + } + ++buf; + } + } +#endif /* RT_PRINTF_SPECIAL */ + + /* no align to the left */ + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf < end) + *buf = c; + ++buf; + } + } + +#ifdef RT_PRINTF_PRECISION + while (i < precision--) { + if (buf < end) + *buf = '0'; + ++buf; + } +#endif /* RT_PRINTF_PRECISION */ + + /* put number in the temporary buffer */ + while (i-- > 0 && (precision_bak != 0)) { + if (buf < end) + *buf = tmp[i]; + ++buf; + } + + while (size-- > 0) { + if (buf < end) + *buf = ' '; + ++buf; + } + + return buf; +} + +int vsnprintf (char *, size_t, const char *, va_list) __attribute__ ((alias ("rt_vsnprintf"))); + +/** + * This function will fill a formatted string to buffer. + * + * @param buf is the buffer to save formatted string. + * + * @param size is the size of buffer. + * + * @param fmt is the format parameters. + * + * @param args is a list of variable parameters. + * + * @return The number of characters actually written to buffer. + */ +int32_t rt_vsnprintf(char *buf, + size_t size, + const char *fmt, + va_list args) +{ +#ifdef RT_PRINTF_LONGLONG + unsigned long long num; +#else + uint32_t num; +#endif /* RT_PRINTF_LONGLONG */ + int i, len; + char *str, *end, c; + const char *s; + + uint8_t base; /* the base of number */ + uint8_t flags; /* flags to print number */ + uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */ + int32_t field_width; /* width of output field */ + +#ifdef RT_PRINTF_PRECISION + int precision; /* min. # of digits for integers and max for a string */ +#endif /* RT_PRINTF_PRECISION */ + + str = buf; + end = buf + size; + + /* Make sure end is always >= buf */ + if (end < buf) { + end = ((char *)-1); + size = end - buf; + } + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + if (str < end) + *str = *fmt; + ++str; + continue; + } + + /* process flags */ + flags = 0; + + while (1) { + /* skips the first '%' also */ + ++fmt; + if (*fmt == '-') + flags |= LEFT; + else if (*fmt == '+') + flags |= PLUS; + else if (*fmt == ' ') + flags |= SPACE; + else if (*fmt == '#') + flags |= SPECIAL; + else if (*fmt == '0') + flags |= ZEROPAD; + else + break; + } + + /* get field width */ + field_width = -1; + if (_ISDIGIT(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + +#ifdef RT_PRINTF_PRECISION + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (_ISDIGIT(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } +#endif /* RT_PRINTF_PRECISION */ + /* get the conversion qualifier */ + qualifier = 0; +#ifdef RT_PRINTF_LONGLONG + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') +#else + if (*fmt == 'h' || *fmt == 'l') +#endif /* RT_PRINTF_LONGLONG */ + { + qualifier = *fmt; + ++fmt; +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } +#endif /* RT_PRINTF_LONGLONG */ + } + + /* the default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + } + + /* get character */ + c = (uint8_t)va_arg(args, int); + if (str < end) + *str = c; + ++str; + + /* put width */ + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "(NULL)"; + + for (len = 0; (len != field_width) && (s[len] != '\0'); len++) + ; +#ifdef RT_PRINTF_PRECISION + if (precision > 0 && len > precision) + len = precision; +#endif /* RT_PRINTF_PRECISION */ + + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + } + + for (i = 0; i < len; ++i) { + if (str < end) + *str = *s; + ++str; + ++s; + } + + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 'p': + if (field_width == -1) { + field_width = sizeof(void *) << 1; + flags |= ZEROPAD; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, precision, flags); +#else + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, flags); +#endif /* RT_PRINTF_PRECISION */ + continue; + + case '%': + if (str < end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str < end) + *str = '%'; + ++str; + + if (*fmt) { + if (str < end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; + } + +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') +#else + if (qualifier == 'l') +#endif /* RT_PRINTF_LONGLONG */ + { + num = va_arg(args, uint32_t); + if (flags & SIGN) + num = (int32_t)num; + } else if (qualifier == 'h') { + num = (uint16_t)va_arg(args, int32_t); + if (flags & SIGN) + num = (int16_t)num; + } else { + num = va_arg(args, uint32_t); + if (flags & SIGN) + num = (int32_t)num; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, num, base, field_width, precision, flags); +#else + str = print_number(str, end, num, base, field_width, flags); +#endif /* RT_PRINTF_PRECISION */ + } + + if (size > 0) { + if (str < end) + *str = '\0'; + else { + end[-1] = '\0'; + } + } + + /* the trailing null byte doesn't count towards the total + * ++str; + */ + return str - buf; +} +