|  | /* | 
|  | * Copyright (c) 2020 Nordic Semiconductor ASA | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stddef.h> | 
|  | #include <sys/cbprintf.h> | 
|  |  | 
|  | int cbprintf(cbprintf_cb out, void *ctx, const char *format, ...) | 
|  | { | 
|  | va_list ap; | 
|  | int rc; | 
|  |  | 
|  | va_start(ap, format); | 
|  | rc = cbvprintf(out, ctx, format, ap); | 
|  | va_end(ap); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_CBPRINTF_LIBC_SUBSTS) | 
|  |  | 
|  | #include <stdio.h> | 
|  |  | 
|  | /* Context for sn* variants is the next space in the buffer, and the buffer | 
|  | * end. | 
|  | */ | 
|  | struct str_ctx { | 
|  | char *dp; | 
|  | char *const dpe; | 
|  | }; | 
|  |  | 
|  | static int str_out(int c, | 
|  | void *ctx) | 
|  | { | 
|  | struct str_ctx *scp = ctx; | 
|  |  | 
|  | /* s*printf must return the number of characters that would be | 
|  | * output, even if they don't all fit, so conditionally store | 
|  | * and unconditionally succeed. | 
|  | */ | 
|  | if (scp->dp < scp->dpe) { | 
|  | *(scp->dp++) = c; | 
|  | } | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  | int fprintfcb(FILE *stream, const char *format, ...) | 
|  | { | 
|  | va_list ap; | 
|  | int rc; | 
|  |  | 
|  | va_start(ap, format); | 
|  | rc = vfprintfcb(stream, format, ap); | 
|  | va_end(ap); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | int vfprintfcb(FILE *stream, const char *format, va_list ap) | 
|  | { | 
|  | return cbvprintf(fputc, stream, format, ap); | 
|  | } | 
|  |  | 
|  | int printfcb(const char *format, ...) | 
|  | { | 
|  | va_list ap; | 
|  | int rc; | 
|  |  | 
|  | va_start(ap, format); | 
|  | rc = vprintfcb(format, ap); | 
|  | va_end(ap); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | int vprintfcb(const char *format, va_list ap) | 
|  | { | 
|  | return cbvprintf(fputc, stdout, format, ap); | 
|  | } | 
|  |  | 
|  | int snprintfcb(char *str, size_t size, const char *format, ...) | 
|  | { | 
|  | va_list ap; | 
|  | int rc; | 
|  |  | 
|  | va_start(ap, format); | 
|  | rc = vsnprintfcb(str, size, format, ap); | 
|  | va_end(ap); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | int vsnprintfcb(char *str, size_t size, const char *format, va_list ap) | 
|  | { | 
|  | struct str_ctx ctx = { | 
|  | .dp = str, | 
|  | .dpe = str + size, | 
|  | }; | 
|  | int rv = cbvprintf(str_out, &ctx, format, ap); | 
|  |  | 
|  | if (ctx.dp < ctx.dpe) { | 
|  | ctx.dp[0] = 0; | 
|  | } else { | 
|  | ctx.dp[-1] = 0; | 
|  | } | 
|  |  | 
|  | return rv; | 
|  | } | 
|  |  | 
|  | #endif /* CONFIG_CBPRINTF_LIBC_SUBSTS */ |