/*
 * 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 */