libc: switch to cbprintf as basis for printf functionality

The minimal libc provided by Zephyr can use the Zephyr system
implementation rather than have its own implementation.

When combined with CBPRINTF_NANO some sprintf tests must be
skipped as they assume a more capable libc.  Add an overlay
that supports testing this non-default combination.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2020-11-03 15:13:42 -06:00 committed by Anas Nashif
commit 7cf9a8c102
4 changed files with 85 additions and 51 deletions

View file

@ -8,19 +8,17 @@
#include <stdarg.h>
#include <stdio.h>
#include <sys/cbprintf.h>
#define DESC(d) ((void *)d)
extern int z_prf(int (*func)(), void *dest,
const char *format, va_list vargs);
int fprintf(FILE *_MLIBC_RESTRICT F, const char *_MLIBC_RESTRICT format, ...)
{
va_list vargs;
int r;
va_start(vargs, format);
r = z_prf(fputc, DESC(F), format, vargs);
r = cbvprintf(fputc, DESC(F), format, vargs);
va_end(vargs);
return r;
@ -31,7 +29,7 @@ int vfprintf(FILE *_MLIBC_RESTRICT F, const char *_MLIBC_RESTRICT format,
{
int r;
r = z_prf(fputc, DESC(F), format, vargs);
r = cbvprintf(fputc, DESC(F), format, vargs);
return r;
}
@ -42,7 +40,7 @@ int printf(const char *_MLIBC_RESTRICT format, ...)
int r;
va_start(vargs, format);
r = z_prf(fputc, DESC(stdout), format, vargs);
r = cbvprintf(fputc, DESC(stdout), format, vargs);
va_end(vargs);
return r;
@ -52,7 +50,7 @@ int vprintf(const char *_MLIBC_RESTRICT format, va_list vargs)
{
int r;
r = z_prf(fputc, DESC(stdout), format, vargs);
r = cbvprintf(fputc, DESC(stdout), format, vargs);
return r;
}

View file

@ -8,9 +8,7 @@
#include <stdarg.h>
#include <stdio.h>
extern int z_prf(int (*func)(), void *dest,
const char *format, va_list vargs);
#include <sys/cbprintf.h>
struct emitter {
char *ptr;
@ -44,7 +42,7 @@ int snprintf(char *_MLIBC_RESTRICT s, size_t len,
p.len = (int) len;
va_start(vargs, format);
r = z_prf(sprintf_out, (void *) (&p), format, vargs);
r = cbvprintf(sprintf_out, (void *) (&p), format, vargs);
va_end(vargs);
*(p.ptr) = 0;
@ -62,7 +60,7 @@ int sprintf(char *_MLIBC_RESTRICT s, const char *_MLIBC_RESTRICT format, ...)
p.len = (int) 0x7fffffff; /* allow up to "maxint" characters */
va_start(vargs, format);
r = z_prf(sprintf_out, (void *) (&p), format, vargs);
r = cbvprintf(sprintf_out, (void *) (&p), format, vargs);
va_end(vargs);
*(p.ptr) = 0;
@ -83,7 +81,7 @@ int vsnprintf(char *_MLIBC_RESTRICT s, size_t len,
p.ptr = s;
p.len = (int) len;
r = z_prf(sprintf_out, (void *) (&p), format, vargs);
r = cbvprintf(sprintf_out, (void *) (&p), format, vargs);
*(p.ptr) = 0;
return r;
@ -98,7 +96,7 @@ int vsprintf(char *_MLIBC_RESTRICT s, const char *_MLIBC_RESTRICT format,
p.ptr = s;
p.len = (int) 0x7fffffff; /* allow up to "maxint" characters */
r = z_prf(sprintf_out, (void *) (&p), format, vargs);
r = cbvprintf(sprintf_out, (void *) (&p), format, vargs);
*(p.ptr) = 0;
return r;

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2019 Nordic Semiconductor ASA
CONFIG_CBPRINTF_FP_SUPPORT=n
CONFIG_CBPRINTF_NANO=y

View file

@ -27,6 +27,12 @@
#define DEADBEEF_OCTAL_ALT_STR "033653337357"
#define DEADBEEF_PTR_STR "0xdeadbeef"
#define IS_MINIMAL_LIBC_NANO (IS_ENABLED(CONFIG_MINIMAL_LIBC) \
&& IS_ENABLED(CONFIG_CBPRINTF_NANO))
#define IS_MINIMAL_LIBC_NOFP (IS_ENABLED(CONFIG_MINIMAL_LIBC) \
&& !IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT))
/*
* A really long string (330 characters + NULL).
* The underlying sprintf() architecture will truncate it.
@ -64,10 +70,18 @@ void test_sprintf_double(void)
char buffer[400];
union raw_double_u var;
#ifndef CONFIG_FPU
ztest_test_skip();
return;
#endif
/* Conversion not supported with minimal_libc without
* CBPRINTF_FP_SUPPORT.
*
* Conversion not supported without FPU except on native POSIX.
*/
if (IS_MINIMAL_LIBC_NOFP
|| !(IS_ENABLED(CONFIG_FPU)
|| IS_ENABLED(CONFIG_BOARD_NATIVE_POSIX))) {
ztest_test_skip();
return;
}
var.u1 = 0x00000000;
var.u2 = 0x7ff00000; /* Bit pattern for +INF (double) */
@ -244,10 +258,14 @@ void test_sprintf_double(void)
buffer[241]);
var.d = 0x1p-400;
/* 3.872E-121 expressed as " 0.0...387" */
sprintf(buffer, "% .380f", var.d);
zassert_true((strlen(buffer) == 383),
"sprintf(<large output>) - incorrect length %d\n",
strlen(buffer));
zassert_equal(strncmp(&buffer[119], "00003872", 8), 0,
"sprintf(<large output>) - misplaced value\n");
buffer[10] = 0; /* log facility doesn't support %.10s */
zassert_true((strcmp(buffer, " 0.0000000") == 0),
"sprintf(<large output>) - starts with \"%s\" "
@ -497,31 +515,37 @@ void test_sprintf_misc(void)
zassert_false((strcmp(buffer, DEADBEEF_PTR_STR) != 0),
"sprintf(%%p). Expected '%s', got '%s'", DEADBEEF_PTR_STR, buffer);
/*******************/
sprintf(buffer, "test data %n test data", &count);
zassert_false((count != 10), "sprintf(%%n). Expected count to be %d, not %d",
10, count);
if (IS_MINIMAL_LIBC_NANO) {
TC_PRINT(" MINIMAL_LIBC+CPBPRINTF skipped tests\n");
} else {
sprintf(buffer, "test data %n test data", &count);
zassert_false((count != 10),
"sprintf(%%n). Expected count to be %d, not %d",
10, count);
zassert_false((strcmp(buffer, "test data test data") != 0),
"sprintf(%%p). Expected '%s', got '%s'",
"test data test data", buffer);
zassert_false((strcmp(buffer, "test data test data") != 0),
"sprintf(%%p). Expected '%s', got '%s'",
"test data test data", buffer);
/*******************/
sprintf(buffer, "%*d", 10, 1234);
zassert_true((strcmp(buffer, " 1234") == 0),
"sprintf(%%p). Expected '%s', got '%s'",
" 1234", buffer);
/*******************/
sprintf(buffer, "%*d", -10, 1234);
zassert_true((strcmp(buffer, "1234 ") == 0),
"sprintf(%%p). Expected '%s', got '%s'",
"1234 ", buffer);
/*******************/
sprintf(buffer, "%*d", 10, 1234);
zassert_true((strcmp(buffer, " 1234") == 0),
"sprintf(%%p). Expected '%s', got '%s'",
" 1234", buffer);
/*******************/
sprintf(buffer, "% d", 1234);
zassert_true((strcmp(buffer, " 1234") == 0),
"sprintf(%% d). Expected '%s', got '%s'",
" 1234", buffer);
/*******************/
sprintf(buffer, "%*d", -10, 1234);
zassert_true((strcmp(buffer, "1234 ") == 0),
"sprintf(%%p). Expected '%s', got '%s'",
"1234 ", buffer);
/*******************/
sprintf(buffer, "% d", 1234);
zassert_true((strcmp(buffer, " 1234") == 0),
"sprintf(%% d). Expected '%s', got '%s'",
" 1234", buffer);
}
/*******************/
sprintf(buffer, "%hx", (unsigned short)1234);
@ -572,9 +596,12 @@ void test_sprintf_integer(void)
"sprintf(%%X). Expected %zu bytes written, not %d\n",
strlen(DEADBEEF_UHEX_STR), len);
zassert_true((strcmp(buffer, DEADBEEF_UHEX_STR) == 0),
"sprintf(%%X). Expected '%s', got '%s'\n",
DEADBEEF_UHEX_STR, buffer);
/* no upper-case hex support */
if (!IS_MINIMAL_LIBC_NANO) {
zassert_true((strcmp(buffer, DEADBEEF_UHEX_STR) == 0),
"sprintf(%%X). Expected '%s', got '%s'\n",
DEADBEEF_UHEX_STR, buffer);
}
/*******************/
len = sprintf(buffer, "%u", DEADBEEF);
@ -596,15 +623,11 @@ void test_sprintf_integer(void)
"sprintf(%%d). Expected '%s', got '%s'\n",
DEADBEEF_SIGNED_STR, buffer);
/*******************/
len = sprintf(buffer, "%o", DEADBEEF);
zassert_true((len == strlen(DEADBEEF_OCTAL_STR)),
"sprintf(%%o). Expected %zu bytes written, not %d\n",
strlen(DEADBEEF_OCTAL_STR), len);
zassert_true((strcmp(buffer, DEADBEEF_OCTAL_STR) == 0),
"sprintf(%%o). Expected '%s', got '%s'\n",
DEADBEEF_OCTAL_STR, buffer);
/* MINIMAL_LIBC+NANO doesn't support the following tests */
if (IS_MINIMAL_LIBC_NANO) {
TC_PRINT(" MINIMAL_LIBC+CBPRINTF_NANO skipped tests\n");
return;
}
/*******************/
len = sprintf(buffer, "%#o", DEADBEEF);
@ -616,6 +639,16 @@ void test_sprintf_integer(void)
"sprintf(%%#o). Expected '%s', got '%s'\n",
DEADBEEF_OCTAL_ALT_STR, buffer);
/*******************/
len = sprintf(buffer, "%o", DEADBEEF);
zassert_true((len == strlen(DEADBEEF_OCTAL_STR)),
"sprintf(%%#o). Expected %zu bytes written, not %d\n",
strlen(DEADBEEF_OCTAL_STR), len);
zassert_true((strcmp(buffer, DEADBEEF_OCTAL_STR) == 0),
"sprintf(%%o). Expected '%s', got '%s'\n",
DEADBEEF_OCTAL_STR, buffer);
/*******************/
len = sprintf(buffer, "%#x", DEADBEEF);
zassert_true((len == strlen(DEADBEEF_LHEX_ALT_STR)),