diff --git a/include/sys/cbprintf.h b/include/sys/cbprintf.h index 83a33f3f30ba6..51700bca37a7f 100644 --- a/include/sys/cbprintf.h +++ b/include/sys/cbprintf.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef CONFIG_CBPRINTF_LIBC_SUBSTS #include @@ -20,12 +21,32 @@ extern "C" { #endif +/* Determine if _Generic is supported. + * In general it's a C11 feature but it was added also in: + * - GCC 4.9.0 https://gcc.gnu.org/gcc-4.9/changes.html + * - Clang 3.0 https://releases.llvm.org/3.0/docs/ClangReleaseNotes.html + */ +#ifndef Z_C_GENERIC +#if ((__STDC_VERSION__ >= 201112L) || \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900) || \ + ((__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) >= 30000)) +#define Z_C_GENERIC 1 +#else +#define Z_C_GENERIC 0 +#endif +#endif + /** * @defgroup cbprintf_apis Formatted Output APIs * @ingroup support_apis * @{ */ +/** @brief Required alignment of the buffer used for packaging. */ +#define CBPRINTF_PACKAGE_ALIGNMENT \ + (IS_ENABLED(CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE) ? \ + sizeof(long double) : MAX(sizeof(double), sizeof(long long))) + /** @brief Signature for a cbprintf callback function. * * This function expects two parameters: @@ -45,6 +66,50 @@ extern "C" { */ typedef int (*cbprintf_cb)(/* int c, void *ctx */); +/** @brief Determine if string must be packaged in run time. + * + * Static packaging can be applied if size of the package can be determined + * at compile time. In general, package size can be determined at compile time + * if there are no string arguments which might be copied into package body if + * they are considered transient. + * + * @param skip number of read only string arguments in the parameter list. It + * shall be non-zero if there are known read only string arguments present + * in the string (e.g. function name prefix in the log message). + * + * @param ... String with arguments. + * + * @retval 1 if string must be packaged in run time. + * @retval 0 string can be statically packaged. + */ +#define CBPRINTF_MUST_RUNTIME_PACKAGE(skip, .../* fmt, ... */) \ + Z_CBPRINTF_MUST_RUNTIME_PACKAGE(skip, __VA_ARGS__) + +/** @brief Statically package string. + * + * Build string package from formatted string. It assumes that formatted + * string is in the read only memory. + * + * If _Generic is not supported then runtime packaging is performed. + * + * @param packaged pointer to where the packaged data can be stored. Pass a null + * pointer to skip packaging but still calculate the total space required. + * The data stored here is relocatable, that is it can be moved to another + * contiguous block of memory. It must be aligned to the size of the longest + * argument. It is recommended to use CBPRINTF_PACKAGE_ALIGNMENT for alignment. + * + * @param inlen set to the number of bytes available at @p packaged. If + * @p packaged is NULL the value is ignored. + * + * @param outlen variable updated to the number of bytes required to completely + * store the packed information. If input buffer was too small it is set to + * -ENOSPC. + * + * @param ... formatted string with arguments. Format string must be constant. + */ +#define CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, ... /* fmt, ... */) \ + Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, __VA_ARGS__) + /** @brief Capture state required to output formatted data later. * * Like cbprintf() but instead of processing the arguments and emitting the @@ -74,6 +139,7 @@ typedef int (*cbprintf_cb)(/* int c, void *ctx */); * @retval nonegative the number of bytes successfully stored at @p packaged. * This will not exceed @p len. * @retval -EINVAL if @p format is not acceptable + * @retval -EFAULT if @p packaged alignment is not acceptable * @retval -ENOSPC if @p packaged was not null and the space required to store * exceed @p len. */ diff --git a/include/sys/cbprintf_internal.h b/include/sys/cbprintf_internal.h new file mode 100644 index 0000000000000..75cb8d9f3a71c --- /dev/null +++ b/include/sys/cbprintf_internal.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_CBPRINTF_INTERNAL_H_ +#define ZEPHYR_INCLUDE_SYS_CBPRINTF_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Special alignment cases + */ + +#if defined(__i386__) +/* there are no gaps on the stack */ +#define VA_STACK_ALIGN(type) 1 +#elif defined(__sparc__) +/* there are no gaps on the stack */ +#define VA_STACK_ALIGN(type) 1 +#elif defined(__x86_64__) +#define VA_STACK_MIN_ALIGN 8 +#elif defined(__aarch64__) +#define VA_STACK_MIN_ALIGN 8 +#elif defined(__riscv) +#define VA_STACK_MIN_ALIGN (__riscv_xlen / 8) +#endif + +/* + * Default alignment values if not specified by architecture config + */ + +#ifndef VA_STACK_MIN_ALIGN +#define VA_STACK_MIN_ALIGN 1 +#endif + +#ifndef VA_STACK_ALIGN +#define VA_STACK_ALIGN(type) MAX(VA_STACK_MIN_ALIGN, __alignof__(type)) +#endif + +/** @brief Return 1 if argument is a pointer to char or wchar_t + * + * @param x argument. + * + * @return 1 if char * or wchar_t *, 0 otherwise. + */ +#define Z_CBPRINTF_IS_PCHAR(x) _Generic((x), \ + char * : 1, \ + const char * : 1, \ + volatile char * : 1, \ + const volatile char * : 1, \ + wchar_t * : 1, \ + const wchar_t * : 1, \ + volatile wchar_t * : 1, \ + const volatile wchar_t * : 1, \ + default : \ + 0) + +/** @brief Calculate number of char * or wchar_t * arguments in the arguments. + * + * @param fmt string. + * + * @param ... string arguments. + * + * @return number of arguments which are char * or wchar_t *. + */ +#define Z_CBPRINTF_HAS_PCHAR_ARGS(fmt, ...) \ + (FOR_EACH(Z_CBPRINTF_IS_PCHAR, (+), __VA_ARGS__)) + +/** + * @brief Check if formatted string must be packaged in runtime. + * + * @param skip number of char/wchar_t pointers in the argument list which are + * accepted for static packaging. + * + * @param ... String with arguments (fmt, ...). + * + * @retval 1 if string must be packaged at runtime. + * @retval 0 if string can be statically packaged. + */ +#if Z_C_GENERIC +#define Z_CBPRINTF_MUST_RUNTIME_PACKAGE(skip, ...) \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \ + (0), \ + (((Z_CBPRINTF_HAS_PCHAR_ARGS(__VA_ARGS__) - skip) > 0))) +#else +#define Z_CBPRINTF_MUST_RUNTIME_PACKAGE(skip, ...) 1 +#endif + +/** @brief Get storage size for given argument. + * + * Floats are promoted to double so they use size of double, others int storage + * or it's own storage size if it is bigger than int. Strings are stored in + * the package with 1 byte header indicating if string is stored as pointer or + * by value. + * + * @param x argument. + * + * @return Number of bytes used for storing the argument. + */ +#define Z_CBPRINTF_ARG_SIZE(v) \ + _Generic((v), \ + float : sizeof(double), \ + default : \ + _Generic((v), \ + void * : 0, \ + default : \ + sizeof((v)+0) \ + ) \ + ) + +/** @brief Promote and store argument in the buffer. + * + * @param buf Buffer. + * + * @param arg Argument. + */ +#define Z_CBPRINTF_STORE_ARG(buf, arg) \ + *_Generic((arg) + 0, \ + char : (int *)buf, \ + unsigned char: (int *)buf, \ + short : (int *)buf, \ + unsigned short : (int *)buf, \ + int : (int *)buf, \ + unsigned int : (unsigned int *)buf, \ + long : (long *)buf, \ + unsigned long : (unsigned long *)buf, \ + long long : (long long *)buf, \ + unsigned long long : (unsigned long long *)buf, \ + float : (double *)buf, \ + double : (double *)buf, \ + long double : (long double *)buf, \ + default : \ + (const void **)buf) = arg + +/** @brief Return alignment needed for given argument. + * + * @param _arg Argument + * + * @return Alignment in bytes. + */ +#define Z_CBPRINTF_ALIGNMENT(_arg) \ + MAX(_Generic((_arg) + 0, \ + float : VA_STACK_ALIGN(double), \ + double : VA_STACK_ALIGN(double), \ + long double : VA_STACK_ALIGN(long double), \ + long long : VA_STACK_ALIGN(long long), \ + unsigned long long : VA_STACK_ALIGN(long long), \ + default : \ + __alignof__((_arg) + 0)), VA_STACK_MIN_ALIGN) + +/** @brief Detect long double variable. + * + * @param x Argument. + * + * @return 1 if @p x is a long double, 0 otherwise. + */ +#define Z_CBPRINTF_IS_LONGDOUBLE(x) \ + _Generic((x) + 0, long double : 1, default : 0) + +/** @brief Safely package arguments to a buffer. + * + * Argument is put into the buffer if capable buffer is provided. Length is + * incremented even if data is not packaged. + * + * @param _buf buffer. + * + * @param _idx index. Index is postincremented. + * + * @param _max maximum index (buffer capacity). + * + * @param _arg argument. + */ +#define Z_CBPRINTF_PACK_ARG2(_buf, _idx, _max, _arg) do { \ + BUILD_ASSERT(!((sizeof(double) < VA_STACK_ALIGN(long double)) && \ + Z_CBPRINTF_IS_LONGDOUBLE(_arg) && \ + !IS_ENABLED(CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE)),\ + "Packaging of long double not enabled in Kconfig."); \ + while (_idx % Z_CBPRINTF_ALIGNMENT(_arg)) { \ + _idx += sizeof(int); \ + }; \ + uint32_t _arg_size = Z_CBPRINTF_ARG_SIZE(_arg); \ + if (_buf && _idx < _max) { \ + Z_CBPRINTF_STORE_ARG(&_buf[_idx], _arg); \ + } \ + _idx += _arg_size; \ +} while (0) + +/** @brief Package single argument. + * + * Macro is called in a loop for each argument in the string. + * + * @param arg argument. + */ +#define Z_CBPRINTF_PACK_ARG(arg) \ + Z_CBPRINTF_PACK_ARG2(_pbuf, _pkg_len, _pmax, arg) + +/** @brief Package descriptor. + * + * @param len Package length. + * + * @param str_cnt Number of strings stored in the package. + */ +struct z_cbprintf_desc { + uint8_t len; + uint8_t str_cnt; +}; + +/** @brief Package header. */ +union z_cbprintf_hdr { + struct z_cbprintf_desc desc; + void *raw; +}; + +/** @brief Statically package a formatted string with arguments. + * + * @param buf buffer. If null then only length is calculated. + * + * @param _inlen buffer capacity on input. Ignored when @p buf is null. + * + * @param _outlen number of bytes required to store the package. + * + * @param ... String with variable list of arguments. + */ +#define Z_CBPRINTF_STATIC_PACKAGE_GENERIC(buf, _inlen, _outlen, \ + ... /* fmt, ... */) \ +do { \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \ + if (IS_ENABLED(CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT)) { \ + __ASSERT(!((uintptr_t)buf & (CBPRINTF_PACKAGE_ALIGNMENT - 1)), \ + "Buffer must be aligned."); \ + } \ + uint8_t *_pbuf = buf; \ + size_t _pmax = (buf != NULL) ? *_inlen : SIZE_MAX; \ + size_t _pkg_len = 0; \ + union z_cbprintf_hdr *_len_loc; \ + /* package starts with string address and field with length */ \ + if (_pmax < sizeof(char *) + 2 * sizeof(uint16_t)) { \ + break; \ + } \ + _len_loc = (union z_cbprintf_hdr *)_pbuf; \ + _pkg_len += sizeof(union z_cbprintf_hdr); \ + if (_pbuf) { \ + *(char **)&_pbuf[_pkg_len] = GET_ARG_N(1, __VA_ARGS__); \ + } \ + _pkg_len += sizeof(char *); \ + /* Pack remaining arguments */\ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (), ( \ + FOR_EACH(Z_CBPRINTF_PACK_ARG, (;), GET_ARGS_LESS_N(1, __VA_ARGS__));\ + )) \ + /* Store length */ \ + _outlen = (_pkg_len > _pmax) ? -ENOSPC : _pkg_len; \ + /* Store length in the header, set number of dumped strings to 0 */ \ + if (_pbuf) { \ + union z_cbprintf_hdr hdr = { .desc = {.len = _pkg_len }}; \ + *_len_loc = hdr; \ + } \ + _Pragma("GCC diagnostic pop") \ +} while (0) + +#if Z_C_GENERIC +#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, ... /* fmt, ... */) \ + Z_CBPRINTF_STATIC_PACKAGE_GENERIC(packaged, inlen, outlen, __VA_ARGS__) +#else +#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, ... /* fmt, ... */) \ +do { \ + /* Small trick needed to avoid warning on always true */ \ + if (((uintptr_t)packaged + 1) != 1) { \ + outlen = cbprintf_package(packaged, inlen, __VA_ARGS__); \ + } else { \ + outlen = cbprintf_package(NULL, 0, __VA_ARGS__); \ + } \ +} while (0) +#endif /* Z_C_GENERIC */ + +#ifdef __cplusplus +} +#endif + + +#endif /* ZEPHYR_INCLUDE_SYS_CBPRINTF_INTERNAL_H_ */ diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf index cc4cebec40e30..93b38c253f6bf 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -115,3 +115,19 @@ config CBPRINTF_LIBC_SUBSTS When used with CBPRINTF_NANO this increases the implementation code size by a small amount. + +config CBPRINTF_PACKAGE_LONGDOUBLE + bool "Support packaging of long doubles" + help + Option impact required alignment for buffers used for packaging + (CBPRINTF_PACKAGE_ALIGNMENT). On most platforms long doubles + requires buffer to be 16 bytes aligned. Long doubles are rarely used + so such alignment is an unnecessary waste. If option is disabled, + then compilation fails if long double is used. + +config CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT + bool "Validate alignment of a static package buffer" + help + When enabled, CBPRINTF_STATIC_PACKAGE asserts when buffer is not + properly aligned. If macro is widely used then assert may impact + memory footprint. diff --git a/lib/os/cbprintf_packaged.c b/lib/os/cbprintf_packaged.c index e6975d0ddbce8..24e50d2f512f9 100644 --- a/lib/os/cbprintf_packaged.c +++ b/lib/os/cbprintf_packaged.c @@ -94,8 +94,6 @@ static int cbprintf_via_va_list(cbprintf_cb out, void *ctx, return cbvprintf(out, ctx, fmt, u.ap); } -#define VA_STACK_MIN_ALIGN 8 - #elif defined(__x86_64__) /* * Reference: @@ -131,8 +129,6 @@ static int cbprintf_via_va_list(cbprintf_cb out, void *ctx, return cbvprintf(out, ctx, fmt, u.ap); } -#define VA_STACK_MIN_ALIGN 8 - #elif defined(__xtensa__) /* * Reference: @@ -193,38 +189,10 @@ static int cbprintf_via_va_list(cbprintf_cb out, void *ctx, #endif -/* - * Special alignment cases - */ - -#if defined(__i386__) -/* there are no gaps on the stack */ -#define VA_STACK_ALIGN(type) 1 -#endif - -#if defined(__riscv) -#define VA_STACK_MIN_ALIGN (__riscv_xlen / 8) -#endif - #if defined(__sparc__) -/* no gaps on the stack even though the CPU can't do unaligned accesses */ -#define VA_STACK_ALIGN(type) 1 +/* CPU can't do unaligned accesses even though no gaps on the stack.*/ #define VA_STACK_LL_DBL_MEMCPY true -#endif - -/* - * Default alignment values if not specified by architecture config - */ - -#ifndef VA_STACK_MIN_ALIGN -#define VA_STACK_MIN_ALIGN 1 -#endif - -#ifndef VA_STACK_ALIGN -#define VA_STACK_ALIGN(type) MAX(VA_STACK_MIN_ALIGN, __alignof__(type)) -#endif - -#ifndef VA_STACK_LL_DBL_MEMCPY +#else #define VA_STACK_LL_DBL_MEMCPY false #endif @@ -406,6 +374,11 @@ int cbvprintf_package(void *packaged, size_t len, /* align destination buffer location */ buf = (void *) ROUND_UP(buf, align); + /* Check if buffer is properly aligned. */ + if ((uintptr_t)buf0 & (align - 1)) { + return -EFAULT; + } + /* make sure the data fits */ if (buf0 && buf - buf0 + size > len) { return -ENOSPC; diff --git a/tests/lib/cbprintf_package/prj.conf b/tests/lib/cbprintf_package/prj.conf index 6dc80c0d7b77a..9467c2926896d 100644 --- a/tests/lib/cbprintf_package/prj.conf +++ b/tests/lib/cbprintf_package/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_CBPRINTF_COMPLETE=y diff --git a/tests/lib/cbprintf_package/src/main.c b/tests/lib/cbprintf_package/src/main.c index aedd482a5bde2..7af886b3fe48c 100644 --- a/tests/lib/cbprintf_package/src/main.c +++ b/tests/lib/cbprintf_package/src/main.c @@ -27,7 +27,8 @@ static int out(int c, void *dest) return rv; } -static char runtime_buf[128]; +static char static_buf[512]; +static char runtime_buf[512]; static char compare_buf[128]; void dump(const char *desc, uint8_t *package, size_t len) @@ -58,13 +59,23 @@ void unpack(const char *desc, struct out_buffer *buf, }; \ int rc = cbprintf_package(NULL, 0, fmt, __VA_ARGS__); \ zassert_true(rc > 0, "cbprintf_package() returned %d", rc); \ - size_t len = rc; \ - uint8_t __aligned(8) rt_package[len]; \ + int len = rc; \ + /* Aligned so the package is similar to the static one. */ \ + uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) rt_package[len]; \ memset(rt_package, 0, len); \ rc = cbprintf_package(rt_package, len, fmt, __VA_ARGS__); \ zassert_equal(rc, len, "cbprintf_package() returned %d, expected %d", rc, len); \ dump("runtime", rt_package, len); \ unpack("runtime", &rt_buf, rt_package, len); \ + \ + struct out_buffer st_buf = { \ + .buf = static_buf, .idx = 0, .size = sizeof(static_buf) \ + }; \ + CBPRINTF_STATIC_PACKAGE(NULL, 0, len, fmt, __VA_ARGS__); \ + uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len]; \ + CBPRINTF_STATIC_PACKAGE(package, len, len, fmt, __VA_ARGS__); \ + dump("static", package, len); \ + unpack("static", &st_buf, package, len); \ } while (0) void test_cbprintf_package(void) @@ -97,6 +108,11 @@ void test_cbprintf_package(void) TEST_PACKAGING("test %c %p", c, &c); if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) { TEST_PACKAGING("test %f %a", f, d); +#if CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE + long double ld = 1.2333; + + TEST_PACKAGING("test %Lf", ld); +#endif } } diff --git a/tests/lib/cbprintf_package/testcase.yaml b/tests/lib/cbprintf_package/testcase.yaml index e8ee855d36610..c6733a15a6fc0 100644 --- a/tests/lib/cbprintf_package/testcase.yaml +++ b/tests/lib/cbprintf_package/testcase.yaml @@ -7,6 +7,9 @@ tests: qemu_arc_em qemu_arc_hs qemu_cortex_a53 qemu_cortex_m0 qemu_cortex_m3 qemu_cortex_r5 qemu_leon3 qemu_nios2 qemu_riscv32 qemu_riscv64 qemu_x86 qemu_x86_64 qemu_xtensa + extra_configs: + - CONFIG_CBPRINTF_COMPLETE=y + libraries.cbprintf_package_fp: tags: cbprintf integration_platforms: @@ -17,3 +20,29 @@ tests: qemu_x86_64 qemu_xtensa extra_configs: - CONFIG_CBPRINTF_FP_SUPPORT=y + - CONFIG_CBPRINTF_COMPLETE=y + + libraries.cbprintf_package_long_double: + tags: cbprintf + integration_platforms: + - native_posix + platform_allow: > + qemu_arc_em qemu_arc_hs qemu_cortex_a53 qemu_cortex_m0 qemu_cortex_m3 + qemu_cortex_r5 qemu_leon3 qemu_nios2 qemu_riscv64 + qemu_x86_64 qemu_xtensa + platform_exclude: qemu_riscv32 + extra_configs: + - CONFIG_CBPRINTF_FP_SUPPORT=y + - CONFIG_CBPRINTF_COMPLETE=y + - CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE=y + + libraries.cbprintf_package_nano: + tags: cbprintf + integration_platforms: + - native_posix + platform_allow: > + qemu_arc_em qemu_arc_hs qemu_cortex_a53 qemu_cortex_m0 qemu_cortex_m3 + qemu_cortex_r5 qemu_leon3 qemu_nios2 qemu_riscv32 qemu_riscv64 qemu_x86 + qemu_x86_64 qemu_xtensa + extra_configs: + - CONFIG_CBPRINTF_NANO=y diff --git a/tests/unit/cbprintf/main.c b/tests/unit/cbprintf/main.c index e74be032544f3..64c7561c5bdd0 100644 --- a/tests/unit/cbprintf/main.c +++ b/tests/unit/cbprintf/main.c @@ -90,6 +90,11 @@ #endif #if (VIA_TWISTER & 0x200) != 0 #define USE_PACKAGED 1 +#else +#define USE_PACKAGED 0 +#endif +#if (VIA_TWISTER & 0x400) != 0 +#define CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE 1 #endif #endif /* VIA_TWISTER */ @@ -163,28 +168,43 @@ static inline int match_sfx(const char **ptr) /* This has to be more than 255 so we can test over-sized widths. */ static char buf[512]; -static char *bp; + +struct out_buffer { + char *buf; + size_t idx; + size_t size; +}; + +static struct out_buffer outbuf; static inline void reset_out(void) { - bp = buf; - *bp = 0; + outbuf.buf = buf; + outbuf.size = ARRAY_SIZE(buf); + outbuf.idx = 0; +} + +static void outbuf_null_terminate(struct out_buffer *outbuf) +{ + int idx = outbuf->idx - ((outbuf->idx == outbuf->size) ? 1 : 0); + + outbuf->buf[idx] = 0; } static int out(int c, void *dest) { int rv = EOF; + struct out_buffer *buf = dest; - ARG_UNUSED(dest); - if (bp < (buf + ARRAY_SIZE(buf))) { - *bp++ = (char)(unsigned char)c; + if (buf->idx < buf->size) { + buf->buf[buf->idx++] = (char)(unsigned char)c; rv = (int)(unsigned char)c; } return rv; } -__printf_like(1, 2) -static int prf(const char *format, ...) +__printf_like(2, 3) +static int prf(char *static_package_str, const char *format, ...) { va_list ap; int rv; @@ -197,15 +217,15 @@ static int prf(const char *format, ...) #if USE_PACKAGED rv = cbvprintf_package(packaged, sizeof(packaged), format, ap); if (rv >= 0) { - rv = cbpprintf(out, NULL, packaged); + rv = cbpprintf(out, &outbuf, packaged); + if (rv == 0 && static_package_str) { + rv = strcmp(static_package_str, outbuf.buf); + } } #else - rv = cbvprintf(out, NULL, format, ap); + rv = cbvprintf(out, &outbuf, format, ap); #endif - if (bp == (buf + ARRAY_SIZE(buf))) { - --bp; - } - *bp = 0; + outbuf_null_terminate(&outbuf); #endif va_end(ap); return rv; @@ -220,22 +240,58 @@ static int rawprf(const char *format, ...) #if USE_PACKAGED rv = cbvprintf_package(packaged, sizeof(packaged), format, ap); if (rv >= 0) { - rv = cbpprintf(out, NULL, packaged); + rv = cbpprintf(out, &outbuf, packaged); } #else - rv = cbvprintf(out, NULL, format, ap); + rv = cbvprintf(out, &outbuf, format, ap); #endif va_end(ap); if (IS_ENABLED(CONFIG_CBPRINTF_NANO) && !IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) { zassert_equal(rv, 0, NULL); - rv = bp - buf; + rv = outbuf.idx; } return rv; } -#define TEST_PRF(_fmt, ...) prf(WRAP_FMT(_fmt), PASS_ARG(__VA_ARGS__)) +#define TEST_PRF2(rc, _fmt, ...) do { \ + char _buf[512]; \ + char *sp_buf = NULL; /* static package buffer */\ + if (USE_PACKAGED && !CBPRINTF_MUST_RUNTIME_PACKAGE(0, _fmt, __VA_ARGS__)) { \ + int rv = 0; \ + size_t _len; \ + struct out_buffer package_buf = { \ + .buf = _buf, .size = ARRAY_SIZE(_buf), .idx = 0 \ + }; \ + CBPRINTF_STATIC_PACKAGE(NULL, 0, _len, _fmt, __VA_ARGS__); \ + uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[_len]; \ + int st_pkg_rv; \ + CBPRINTF_STATIC_PACKAGE(package, _len - 1, st_pkg_rv, \ + _fmt, __VA_ARGS__); \ + zassert_equal(st_pkg_rv, -ENOSPC, NULL); \ + CBPRINTF_STATIC_PACKAGE(package, _len, st_pkg_rv, \ + _fmt, __VA_ARGS__); \ + zassert_equal(st_pkg_rv, _len, NULL); \ + rv = cbpprintf(out, &package_buf, package); \ + if (rv >= 0) { \ + sp_buf = _buf; \ + } \ + } \ + *rc = prf(sp_buf, _fmt, __VA_ARGS__); \ +} while (0) + +#define TEST_PRF(rc, _fmt, ...) \ + TEST_PRF2(rc, WRAP_FMT(_fmt), PASS_ARG(__VA_ARGS__)) + +#ifdef CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE +#define TEST_PRF_LONG_DOUBLE(rc, _fmt, ...) \ + TEST_PRF(rc, _fmt, __VA_ARGS__) +#else +/* Skip testing of static packaging if long double support not enabled. */ +#define TEST_PRF_LONG_DOUBLE(rc, _fmt, ...) \ + *rc = prf(NULL, WRAP_FMT(_fmt), PASS_ARG(__VA_ARGS__)) +#endif struct context { const char *expected; @@ -323,7 +379,9 @@ static inline bool prf_check(const char *expected, static void test_pct(void) { - int rc = TEST_PRF("/%%/%c/", 'a'); + int rc; + + TEST_PRF(&rc, "/%%/%c/", 'a'); PRF_CHECK("/%/a/", rc); } @@ -332,10 +390,10 @@ static void test_c(void) { int rc; - rc = TEST_PRF("%c", 'a'); + TEST_PRF(&rc, "%c", 'a'); PRF_CHECK("a", rc); - rc = prf("/%256c/", 'a'); + rc = prf(NULL, "/%256c/", 'a'); const char *bp = buf; size_t spaces = 255; @@ -356,7 +414,7 @@ static void test_c(void) return; } - rc = TEST_PRF("%lc", (wint_t)'a'); + TEST_PRF(&rc, "%lc", (wint_t)'a'); if (ENABLED_USE_LIBC) { PRF_CHECK("a", rc); } else { @@ -370,13 +428,13 @@ static void test_s(void) static wchar_t ws[] = L"abc"; int rc; - rc = TEST_PRF("/%s/", s); + TEST_PRF(&rc, "/%s/", s); PRF_CHECK("/123/", rc); - rc = TEST_PRF("/%6s/%-6s/%2s/", s, s, s); + TEST_PRF(&rc, "/%6s/%-6s/%2s/", s, s, s); PRF_CHECK("/ 123/123 /123/", rc); - rc = TEST_PRF("/%.6s/%.2s/%.s/", s, s, s); + TEST_PRF(&rc, "/%.6s/%.2s/%.s/", s, s, s); PRF_CHECK("/123/12//", rc); if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) { @@ -384,7 +442,7 @@ static void test_s(void) return; } - rc = TEST_PRF("%ls", ws); + TEST_PRF(&rc, "%ls", ws); if (ENABLED_USE_LIBC) { PRF_CHECK("abc", rc); } else { @@ -414,21 +472,21 @@ static void test_d_length(void) long long svll2 = -2LL; int rc; - rc = TEST_PRF("%d/%d", min, max); + TEST_PRF(&rc, "%d/%d", min, max); PRF_CHECK("-1234567890/1876543210", rc); - rc = TEST_PRF("%u/%u", min, max); + TEST_PRF(&rc, "%u/%u", min, max); PRF_CHECK("3060399406/1876543210", rc); if (!IS_ENABLED(CONFIG_CBPRINTF_NANO)) { - rc = TEST_PRF("%hd/%hd", min, max); + TEST_PRF(&rc, "%hd/%hd", min, max); PRF_CHECK("-722/-14614", rc); - rc = TEST_PRF("%hhd/%hhd", min, max); + TEST_PRF(&rc, "%hhd/%hhd", min, max); PRF_CHECK("46/-22", rc); } - rc = TEST_PRF("%ld/%ld", (long)min, (long)max); + TEST_PRF(&rc, "%ld/%ld", (long)min, (long)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL) || (sizeof(long) <= 4) || IS_ENABLED(CONFIG_CBPRINTF_NANO)) { @@ -437,7 +495,7 @@ static void test_d_length(void) PRF_CHECK("%ld/%ld", rc); } - rc = TEST_PRF("/%lld/%lld/%lld/", svll, -svll, svll2); + TEST_PRF(&rc, "/%lld/%lld/%lld/", svll, -svll, svll2); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) { PRF_CHECK("/34621422135410688/-34621422135410688/-2/", rc); } else if (IS_ENABLED(CONFIG_CBPRINTF_COMPLETE)) { @@ -448,7 +506,7 @@ static void test_d_length(void) zassert_true(false, "Missed case!"); } - rc = TEST_PRF("%lld/%lld", (long long)min, (long long)max); + TEST_PRF(&rc, "%lld/%lld", (long long)min, (long long)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) { PRF_CHECK("-1234567890/1876543210", rc); } else if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) { @@ -462,14 +520,14 @@ static void test_d_length(void) return; } - rc = TEST_PRF("%jd/%jd", (intmax_t)min, (intmax_t)max); + TEST_PRF(&rc, "%jd/%jd", (intmax_t)min, (intmax_t)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) { PRF_CHECK("-1234567890/1876543210", rc); } else { PRF_CHECK("%jd/%jd", rc); } - rc = TEST_PRF("%zd/%td/%td", (size_t)min, (ptrdiff_t)min, + TEST_PRF(&rc, "%zd/%td/%td", (size_t)min, (ptrdiff_t)min, (ptrdiff_t)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL) || (sizeof(size_t) <= 4)) { @@ -494,32 +552,32 @@ static void test_d_flags(void) int rc; /* Stuff related to sign */ - rc = TEST_PRF("/%d/%-d/%+d/% d/", + TEST_PRF(&rc, "/%d/%-d/%+d/% d/", sv, sv, sv, sv); PRF_CHECK("/123/123/+123/ 123/", rc); /* Stuff related to width padding */ - rc = TEST_PRF("/%1d/%4d/%-4d/%04d/%15d/%-15d/", + TEST_PRF(&rc, "/%1d/%4d/%-4d/%04d/%15d/%-15d/", sv, sv, sv, sv, sv, sv); PRF_CHECK("/123/ 123/123 /0123/" " 123/123 /", rc); /* Stuff related to precision */ - rc = TEST_PRF("/%.6d/%6.4d/", sv, sv); + TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv); PRF_CHECK("/000123/ 0123/", rc); /* Now with negative values */ sv = -sv; - rc = TEST_PRF("/%d/%-d/%+d/% d/", + TEST_PRF(&rc, "/%d/%-d/%+d/% d/", sv, sv, sv, sv); PRF_CHECK("/-123/-123/-123/-123/", rc); - rc = TEST_PRF("/%1d/%6d/%-6d/%06d/%13d/%-13d/", + TEST_PRF(&rc, "/%1d/%6d/%-6d/%06d/%13d/%-13d/", sv, sv, sv, sv, sv, sv); PRF_CHECK("/-123/ -123/-123 /-00123/" " -123/-123 /", rc); - rc = TEST_PRF("/%.6d/%6.4d/", sv, sv); + TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv); PRF_CHECK("/-000123/ -0123/", rc); /* These have to be tested without the format validation @@ -540,10 +598,10 @@ static void test_x_length(void) unsigned int max = 0x4d3d2d1d; int rc; - rc = TEST_PRF("%x/%X", min, max); + TEST_PRF(&rc, "%x/%X", min, max); PRF_CHECK("4c3c2c1c/4D3D2D1D", rc); - rc = TEST_PRF("%lx/%lX", (unsigned long)min, (unsigned long)max); + TEST_PRF(&rc, "%lx/%lX", (unsigned long)min, (unsigned long)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL) || (sizeof(long) <= 4) || IS_ENABLED(CONFIG_CBPRINTF_NANO)) { @@ -557,22 +615,22 @@ static void test_x_length(void) return; } - rc = TEST_PRF("%hx/%hX", min, max); + TEST_PRF(&rc, "%hx/%hX", min, max); PRF_CHECK("2c1c/2D1D", rc); - rc = TEST_PRF("%hhx/%hhX", min, max); + TEST_PRF(&rc, "%hhx/%hhX", min, max); PRF_CHECK("1c/1D", rc); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) { - rc = TEST_PRF("%llx/%llX", (unsigned long long)min, + TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min, (unsigned long long)max); PRF_CHECK("4c3c2c1c/4D3D2D1D", rc); - rc = TEST_PRF("%jx/%jX", (uintmax_t)min, (uintmax_t)max); + TEST_PRF(&rc, "%jx/%jX", (uintmax_t)min, (uintmax_t)max); PRF_CHECK("4c3c2c1c/4D3D2D1D", rc); } - rc = TEST_PRF("%zx/%zX", (size_t)min, (size_t)max); + TEST_PRF(&rc, "%zx/%zX", (size_t)min, (size_t)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL) || (sizeof(size_t) <= 4)) { PRF_CHECK("4c3c2c1c/4D3D2D1D", rc); @@ -580,7 +638,7 @@ static void test_x_length(void) PRF_CHECK("%zx/%zX", rc); } - rc = TEST_PRF("%tx/%tX", (ptrdiff_t)min, (ptrdiff_t)max); + TEST_PRF(&rc, "%tx/%tX", (ptrdiff_t)min, (ptrdiff_t)max); if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL) || (sizeof(ptrdiff_t) <= 4)) { PRF_CHECK("4c3c2c1c/4D3D2D1D", rc); @@ -593,7 +651,7 @@ static void test_x_length(void) unsigned long long min = 0x8c7c6c5c4c3c2c1cULL; unsigned long long max = 0x8d7d6d5d4d3d2d1dULL; - rc = TEST_PRF("%llx/%llX", (unsigned long long)min, + TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min, (unsigned long long)max); PRF_CHECK("8c7c6c5c4c3c2c1c/8D7D6D5D4D3D2D1D", rc); } @@ -607,12 +665,12 @@ static void test_x_flags(void) /* Stuff related to sign flags, which have no effect on * unsigned conversions, and alternate form */ - rc = TEST_PRF("/%x/%-x/%#x/", + TEST_PRF(&rc, "/%x/%-x/%#x/", sv, sv, sv); PRF_CHECK("/123/123/0x123/", rc); /* Stuff related to width and padding */ - rc = TEST_PRF("/%1x/%4x/%-4x/%04x/%#15x/%-15x/", + TEST_PRF(&rc, "/%1x/%4x/%-4x/%04x/%#15x/%-15x/", sv, sv, sv, sv, sv, sv); PRF_CHECK("/123/ 123/123 /0123/" " 0x123/123 /", rc); @@ -637,9 +695,9 @@ static void test_o(void) return; } - rc = TEST_PRF("%o", v); + TEST_PRF(&rc, "%o", v); PRF_CHECK("1234567", rc); - rc = TEST_PRF("%#o", v); + TEST_PRF(&rc, "%#o", v); PRF_CHECK("01234567", rc); } @@ -653,15 +711,15 @@ static void test_fp_value(void) double dv = 1234.567; int rc; - rc = TEST_PRF("/%f/%F/", dv, dv); + TEST_PRF(&rc, "/%f/%F/", dv, dv); PRF_CHECK("/1234.567000/1234.567000/", rc); - rc = TEST_PRF("%g", dv); + TEST_PRF(&rc, "%g", dv); PRF_CHECK("1234.57", rc); - rc = TEST_PRF("%e", dv); + TEST_PRF(&rc, "%e", dv); PRF_CHECK("1.234567e+03", rc); - rc = TEST_PRF("%E", dv); + TEST_PRF(&rc, "%E", dv); PRF_CHECK("1.234567E+03", rc); - rc = TEST_PRF("%a", dv); + TEST_PRF(&rc, "%a", dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("0x1.34a449ba5e354p+10", rc); } else { @@ -669,40 +727,40 @@ static void test_fp_value(void) } dv = 1E3; - rc = TEST_PRF("%.2f", dv); + TEST_PRF(&rc, "%.2f", dv); PRF_CHECK("1000.00", rc); dv = 1E20; - rc = TEST_PRF("%.0f", dv); + TEST_PRF(&rc, "%.0f", dv); PRF_CHECK("100000000000000000000", rc); - rc = TEST_PRF("%.20e", dv); + TEST_PRF(&rc, "%.20e", dv); PRF_CHECK("1.00000000000000000000e+20", rc); dv = 1E-3; - rc = TEST_PRF("%.3e", dv); + TEST_PRF(&rc, "%.3e", dv); PRF_CHECK("1.000e-03", rc); dv = 1E-3; - rc = TEST_PRF("%g", dv); + TEST_PRF(&rc, "%g", dv); PRF_CHECK("0.001", rc); dv = 1234567.89; - rc = TEST_PRF("%g", dv); + TEST_PRF(&rc, "%g", dv); PRF_CHECK("1.23457e+06", rc); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { dv = (double)BIT64(40); - rc = TEST_PRF("/%a/%.4a/%.20a/", dv, dv, dv); + TEST_PRF(&rc, "/%a/%.4a/%.20a/", dv, dv, dv); PRF_CHECK("/0x1p+40/0x1.0000p+40/" "0x1.00000000000000000000p+40/", rc); dv += (double)BIT64(32); - rc = TEST_PRF("%a", dv); + TEST_PRF(&rc, "%a", dv); PRF_CHECK("0x1.01p+40", rc); } dv = INFINITY; - rc = TEST_PRF("%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", + TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", dv, dv, dv, dv, dv, dv, dv, dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("inf.f INF.F inf.e INF.E " @@ -713,7 +771,7 @@ static void test_fp_value(void) } dv = -INFINITY; - rc = TEST_PRF("%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", + TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", dv, dv, dv, dv, dv, dv, dv, dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("-inf.f -INF.F -inf.e -INF.E " @@ -724,7 +782,7 @@ static void test_fp_value(void) } dv = NAN; - rc = TEST_PRF("%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", + TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A", dv, dv, dv, dv, dv, dv, dv, dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("nan.f NAN.F nan.e NAN.E " @@ -735,7 +793,7 @@ static void test_fp_value(void) } dv = DBL_MIN; - rc = TEST_PRF("%a %e", dv, dv); + TEST_PRF(&rc, "%a %e", dv, dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("0x1p-1022 2.225074e-308", rc); } else { @@ -743,7 +801,7 @@ static void test_fp_value(void) } dv /= 4; - rc = TEST_PRF("%a %e", dv, dv); + TEST_PRF(&rc, "%a %e", dv, dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { PRF_CHECK("0x0.4p-1022 5.562685e-309", rc); } else { @@ -756,83 +814,83 @@ static void test_fp_value(void) */ dv = 0x1.0p-3; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.125", rc); dv = 0x1.0p-4; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.0625", rc); dv = 0x1.8p-4; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.09375", rc); dv = 0x1.cp-4; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.109375", rc); dv = 0x1.9999999800000p-7; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.01249999999708962", rc); dv = 0x1.9999999ffffffp-8; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("0.006250000005820765", rc); dv = 0x1.0p+0; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("1", rc); dv = 0x1.fffffffffffffp-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("4.450147717014402e-308", rc); dv = 0x1.ffffffffffffep-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("4.450147717014402e-308", rc); dv = 0x1.ffffffffffffdp-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("4.450147717014401e-308", rc); dv = 0x1.0000000000001p-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("2.225073858507202e-308", rc); dv = 0x1p-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("2.225073858507201e-308", rc); dv = 0x0.fffffffffffffp-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("2.225073858507201e-308", rc); dv = 0x0.0000000000001p-1022; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("4.940656458412465e-324", rc); dv = 0x1.1fa182c40c60dp-1019; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("2e-307", rc); dv = 0x1.fffffffffffffp+1023; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("1.797693134862316e+308", rc); dv = 0x1.ffffffffffffep+1023; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("1.797693134862316e+308", rc); dv = 0x1.ffffffffffffdp+1023; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("1.797693134862315e+308", rc); dv = 0x1.0000000000001p+1023; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("8.988465674311582e+307", rc); dv = 0x1p+1023; - rc = TEST_PRF("%.16g", dv); + TEST_PRF(&rc, "%.16g", dv); PRF_CHECK("8.98846567431158e+307", rc); } @@ -846,21 +904,21 @@ static void test_fp_length(void) double dv = 1.2345; int rc; - rc = TEST_PRF("/%g/", dv); + TEST_PRF(&rc, "/%g/", dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) { PRF_CHECK("/1.2345/", rc); } else { PRF_CHECK("/%g/", rc); } - rc = TEST_PRF("/%lg/", dv); + TEST_PRF(&rc, "/%lg/", dv); if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) { PRF_CHECK("/1.2345/", rc); } else { PRF_CHECK("/%lg/", rc); } - rc = TEST_PRF("/%Lg/", (long double)dv); + TEST_PRF_LONG_DOUBLE(&rc, "/%Lg/", (long double)dv); if (ENABLED_USE_LIBC) { PRF_CHECK("/1.2345/", rc); } else { @@ -887,24 +945,24 @@ static void test_fp_flags(void) double dv = 1.23; int rc; - rc = TEST_PRF("/%g/% g/%+g/", dv, dv, dv); + TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv); PRF_CHECK("/1.23/ 1.23/+1.23/", rc); if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) { - rc = TEST_PRF("/%a/%.1a/%.2a/", dv, dv, dv); + TEST_PRF(&rc, "/%a/%.1a/%.2a/", dv, dv, dv); PRF_CHECK("/0x1.3ae147ae147aep+0/" "0x1.4p+0/0x1.3bp+0/", rc); } dv = -dv; - rc = TEST_PRF("/%g/% g/%+g/", dv, dv, dv); + TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv); PRF_CHECK("/-1.23/-1.23/-1.23/", rc); dv = 23; - rc = TEST_PRF("/%g/%#g/%.0f/%#.0f/", dv, dv, dv, dv); + TEST_PRF(&rc, "/%g/%#g/%.0f/%#.0f/", dv, dv, dv, dv); PRF_CHECK("/23/23.0000/23/23./", rc); - rc = prf("% .380f", 0x1p-400); + rc = prf(NULL, "% .380f", 0x1p-400); zassert_equal(rc, 383, NULL); zassert_equal(strncmp(buf, " 0.000", 6), 0, NULL); zassert_equal(strncmp(&buf[119], "00003872", 8), 0, NULL); @@ -914,10 +972,10 @@ static void test_star_width(void) { int rc; - rc = TEST_PRF("/%3c/%-3c/", 'a', 'a'); + TEST_PRF(&rc, "/%3c/%-3c/", 'a', 'a'); PRF_CHECK("/ a/a /", rc); - rc = TEST_PRF("/%*c/%*c/", 3, 'a', -3, 'a'); + TEST_PRF(&rc, "/%*c/%*c/", 3, 'a', -3, 'a'); PRF_CHECK("/ a/a /", rc); } @@ -925,7 +983,7 @@ static void test_star_precision(void) { int rc; - rc = TEST_PRF("/%.*x/%10.*x/", + TEST_PRF(&rc, "/%.*x/%10.*x/", 5, 0x12, 5, 0x12); PRF_CHECK("/00012/ 00012/", rc); @@ -937,11 +995,11 @@ static void test_star_precision(void) if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) { double dv = 1.2345678; - rc = TEST_PRF("/%.3g/%.5g/%.8g/%g/", + TEST_PRF(&rc, "/%.3g/%.5g/%.8g/%g/", dv, dv, dv, dv); PRF_CHECK("/1.23/1.2346/1.2345678/1.23457/", rc); - rc = TEST_PRF("/%.*g/%.*g/%.*g/%.*g/", + TEST_PRF(&rc, "/%.*g/%.*g/%.*g/%.*g/", 3, dv, 5, dv, 8, dv, @@ -971,30 +1029,30 @@ static void test_n(void) ptrdiff_t l_t = 0; int rc; - rc = prf("12345%n", &l); + rc = prf(NULL, "12345%n", &l); zassert_equal(l, rc, "%d != %d", l, rc); zassert_equal(rc, 5, NULL); - rc = prf("12345%hn", &l_h); + rc = prf(NULL, "12345%hn", &l_h); zassert_equal(l_h, rc, NULL); - rc = prf("12345%hhn", &l_hh); + rc = prf(NULL, "12345%hhn", &l_hh); zassert_equal(l_hh, rc, NULL); - rc = prf("12345%ln", &l_l); + rc = prf(NULL, "12345%ln", &l_l); zassert_equal(l_l, rc, NULL); - rc = prf("12345%lln", &l_ll); + rc = prf(NULL, "12345%lln", &l_ll); zassert_equal(l_ll, rc, NULL); - rc = prf("12345%jn", &l_j); + rc = prf(NULL, "12345%jn", &l_j); zassert_equal(l_j, rc, NULL); - rc = prf("12345%zn", &l_z); + rc = prf(NULL, "12345%zn", &l_z); zassert_equal(l_z, rc, NULL); - rc = prf("12345%tn", &l_t); + rc = prf(NULL, "12345%tn", &l_t); zassert_equal(l_t, rc, NULL); } @@ -1012,9 +1070,9 @@ static void test_p(void) void *ptr = (void *)uip; int rc; - rc = TEST_PRF("%p", ptr); + TEST_PRF(&rc, "%p", ptr); PRF_CHECK("0xcafe21", rc); - rc = TEST_PRF("%p", NULL); + TEST_PRF(&rc, "%p", NULL); PRF_CHECK("(nil)", rc); reset_out(); @@ -1139,7 +1197,7 @@ static void test_cbpprintf(void) * version. */ reset_out(); - rc = cbpprintf(out, NULL, NULL); + rc = cbpprintf(out, &outbuf, NULL); zassert_equal(rc, -EINVAL, NULL); } diff --git a/tests/unit/cbprintf/testcase.yaml b/tests/unit/cbprintf/testcase.yaml index f9a407adf10ce..2e48580aef596 100644 --- a/tests/unit/cbprintf/testcase.yaml +++ b/tests/unit/cbprintf/testcase.yaml @@ -80,3 +80,18 @@ tests: utilities.prf.m64v281: # PACKAGED NANO + FULL extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x281 + + utilities.prf.m64v600: # PACKAGED REDUCED + LONG_DOUBLE PACKAGING + extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x600 + + utilities.prf.m64v601: # PACKAGED FULL + LONG_DOUBLE PACKAGING + extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x601 + + utilities.prf.m64v607: # PACKAGED FULL + FP + FP_A + LONG_DOUBLE PACKAGING + extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x607 + + utilities.prf.m64v608: # PACKAGED %n + LONG_DOUBLE PACKAGING + extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x608 + + utilities.prf.m64v681: # PACKAGED NANO + FULL + LONG_DOUBLE PACKAGING + extra_args: M64_MODE=1 EXTRA_CPPFLAGS=-DVIA_TWISTER=0x681