diff options
-rw-r--r-- | builtin/stdio.h | 61 | ||||
-rw-r--r-- | builtin/stdlib.c | 68 | ||||
-rw-r--r-- | common/printf.c | 56 | ||||
-rw-r--r-- | include/printf.h | 46 | ||||
-rw-r--r-- | test/printf.c | 10 | ||||
-rw-r--r-- | zephyr/shim/src/console.c | 6 |
6 files changed, 145 insertions, 102 deletions
diff --git a/builtin/stdio.h b/builtin/stdio.h new file mode 100644 index 0000000000..b8b6949c45 --- /dev/null +++ b/builtin/stdio.h @@ -0,0 +1,61 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __CROS_EC_STDIO_H__ +#define __CROS_EC_STDIO_H__ + +#include <stddef.h> +#include <stdarg.h> + +#include "common.h" + +/** + * Print formatted outut to a string. + * + * Guarantees null-termination if size!=0. + * + * @param str Destination string + * @param size Size of destination in bytes + * @param format Format string + * @return EC_SUCCESS, or EC_ERROR_OVERFLOW if the output was truncated. + */ +__attribute__((__format__(__printf__, 3, 4))) +__warn_unused_result __stdlib_compat int +crec_snprintf(char *str, size_t size, const char *format, ...); + +/** + * Print formatted output to a string. + * + * Guarantees null-termination if size!=0. + * + * @param str Destination string + * @param size Size of destination in bytes + * @param format Format string + * @param args Parameters + * @return The string length written to str, or a negative value on error. + * The negative values can be -EC_ERROR_INVAL or -EC_ERROR_OVERFLOW. + */ +__warn_unused_result __stdlib_compat int +crec_vsnprintf(char *str, size_t size, const char *format, va_list args); + +/* + * Create weak aliases to the crec_* printf functions. This lets us call the + * crec_* printf functions in tests that link the C standard library. + */ + +/** + * Alias to crec_snprintf. + */ +__attribute__((__format__(__printf__, 3, 4))) +__warn_unused_result __stdlib_compat int +snprintf(char *str, size_t size, const char *format, ...); + +/** + * Alias to crec_vsnprintf. + */ +__warn_unused_result __stdlib_compat int +vsnprintf(char *str, size_t size, const char *format, va_list args); + +#endif /* __CROS_EC_STDIO_H__ */ diff --git a/builtin/stdlib.c b/builtin/stdlib.c index 1d07b64869..b3229f4f63 100644 --- a/builtin/stdlib.c +++ b/builtin/stdlib.c @@ -7,7 +7,11 @@ #include "common.h" #include "console.h" +#include "printf.h" #include "util.h" + +#include <stdio.h> + /* * The following macros are defined in stdlib.h in the C standard library, which * conflict with the definitions in this file. @@ -19,6 +23,70 @@ #undef isprint #undef tolower +/* Context for snprintf() */ +struct snprintf_context { + char *str; + int size; +}; + +/** + * Add a character to the string context. + * + * @param context Context receiving character + * @param c Character to add + * @return 0 if character added, 1 if character dropped because no space. + */ +static int snprintf_addchar(void *context, int c) +{ + struct snprintf_context *ctx = (struct snprintf_context *)context; + + if (!ctx->size) + return 1; + + *(ctx->str++) = c; + ctx->size--; + return 0; +} + +int crec_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + struct snprintf_context ctx; + int rv; + + if (!str || !format || size <= 0) + return -EC_ERROR_INVAL; + + ctx.str = str; + ctx.size = size - 1; /* Reserve space for terminating '\0' */ + + rv = vfnprintf(snprintf_addchar, &ctx, format, args); + + /* Terminate string */ + *ctx.str = '\0'; + + return (rv == EC_SUCCESS) ? (ctx.str - str) : -rv; +} +#ifndef CONFIG_ZEPHYR +int vsnprintf(char *str, size_t size, const char *format, va_list args) + __attribute__((weak, alias("crec_vsnprintf"))); +#endif /* CONFIG_ZEPHYR */ + +int crec_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list args; + int rv; + + va_start(args, format); + rv = crec_vsnprintf(str, size, format, args); + va_end(args); + + return rv; +} +#ifndef CONFIG_ZEPHYR +int snprintf(char *str, size_t size, const char *format, ...) + __attribute__((weak, alias("crec_snprintf"))); +#endif /* CONFIG_ZEPHYR */ + /* * TODO(b/237712836): Zephyr's libc should provide strcasecmp. For now we'll * use the EC implementation. diff --git a/common/printf.c b/common/printf.c index 9a3e593cba..91e4e722b0 100644 --- a/common/printf.c +++ b/common/printf.c @@ -488,59 +488,3 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, /* If we're still here, we consumed all output */ return EC_SUCCESS; } - -/* Context for snprintf() */ -struct snprintf_context { - char *str; - int size; -}; - -/** - * Add a character to the string context. - * - * @param context Context receiving character - * @param c Character to add - * @return 0 if character added, 1 if character dropped because no space. - */ -static int snprintf_addchar(void *context, int c) -{ - struct snprintf_context *ctx = (struct snprintf_context *)context; - - if (!ctx->size) - return 1; - - *(ctx->str++) = c; - ctx->size--; - return 0; -} - -int crec_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list args; - int rv; - - va_start(args, format); - rv = crec_vsnprintf(str, size, format, args); - va_end(args); - - return rv; -} - -int crec_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - struct snprintf_context ctx; - int rv; - - if (!str || !format || size <= 0) - return -EC_ERROR_INVAL; - - ctx.str = str; - ctx.size = size - 1; /* Reserve space for terminating '\0' */ - - rv = vfnprintf(snprintf_addchar, &ctx, format, args); - - /* Terminate string */ - *ctx.str = '\0'; - - return (rv == EC_SUCCESS) ? (ctx.str - str) : -rv; -} diff --git a/include/printf.h b/include/printf.h index b63208f84d..f6330ff9c3 100644 --- a/include/printf.h +++ b/include/printf.h @@ -11,15 +11,9 @@ #include <stdarg.h> /* For va_list */ #include <stdbool.h> #include <stddef.h> /* For size_t */ -#include "common.h" #include "console.h" - -/* The declaration of snprintf is changed to crec_snprintf for Zephyr, - * so include stdio.h from Zephyr. - */ -#ifdef CONFIG_ZEPHYR #include <stdio.h> -#endif +#include "common.h" /** * Buffer size in bytes large enough to hold the largest possible timestamp. @@ -66,8 +60,6 @@ * - 'p' - pointer */ -#ifndef HIDE_EC_STDLIB - /** * Print formatted output to a function, like vfprintf() * @@ -84,42 +76,6 @@ __stdlib_compat int vfnprintf(int (*addchar)(void *context, int c), void *context, const char *format, va_list args); -#ifndef CONFIG_ZEPHYR -#define snprintf crec_snprintf -#define vsnprintf crec_vsnprintf -#endif - -/** - * Print formatted outut to a string. - * - * Guarantees null-termination if size!=0. - * - * @param str Destination string - * @param size Size of destination in bytes - * @param format Format string - * @return EC_SUCCESS, or EC_ERROR_OVERFLOW if the output was truncated. - */ -__attribute__((__format__(__printf__, 3, 4))) -__warn_unused_result __stdlib_compat int -crec_snprintf(char *str, size_t size, const char *format, ...); - -/** - * Print formatted output to a string. - * - * Guarantees null-termination if size!=0. - * - * @param str Destination string - * @param size Size of destination in bytes - * @param format Format string - * @param args Parameters - * @return The string length written to str, or a negative value on error. - * The negative values can be -EC_ERROR_INVAL or -EC_ERROR_OVERFLOW. - */ -__warn_unused_result __stdlib_compat int -crec_vsnprintf(char *str, size_t size, const char *format, va_list args); - -#endif /* !HIDE_EC_STDLIB */ - #ifdef TEST_BUILD /** * Converts @val to a string written in @buf. The value is converted from diff --git a/test/printf.c b/test/printf.c index 3928185918..69c0d76281 100644 --- a/test/printf.c +++ b/test/printf.c @@ -12,6 +12,13 @@ #include "test_util.h" #include "util.h" +/* + * This file is intended to test the EC printf implementation. We need to + * include the builtin header file directly so that we can call the EC + * version (crec_vsnprintf) when linking with the standard library on the host. + */ +#include "builtin/stdio.h" + #define INIT_VALUE 0x5E #define NO_BYTES_TOUCHED NULL @@ -33,7 +40,8 @@ int run(int expect_ret, const char *expect, bool output_null, size_t size_limit, TEST_ASSERT(expect_size <= size_limit); memset(output, INIT_VALUE, sizeof(output)); - rv = vsnprintf(output_null ? NULL : output, size_limit, format, args); + rv = crec_vsnprintf(output_null ? NULL : output, size_limit, format, + args); ccprintf("received='%.*s' | ret =%d\n", 30, output, rv); TEST_ASSERT_ARRAY_EQ(output, expect, expect_size); diff --git a/zephyr/shim/src/console.c b/zephyr/shim/src/console.c index 8dafaf9803..e9b0c72790 100644 --- a/zephyr/shim/src/console.c +++ b/zephyr/shim/src/console.c @@ -17,6 +17,12 @@ #include <zephyr/zephyr.h> #include <zephyr/logging/log.h> +/* + * TODO(b/238433667): Include EC printf functions + * (crec_vsnprintf/crec_snprintf) until we switch to the standard + * vsnprintf/snprintf. + */ +#include "builtin/stdio.h" #include "console.h" #include "printf.h" #include "task.h" |