From 03c6f3cf458c89df17b02557cd232f9cde73ed54 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sat, 6 Aug 2022 00:12:51 +0200
Subject: make snprintf shared; dynamic resolution support

---
 src/shared/mem.h    |  4 ++++
 src/shared/printf.c | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

(limited to 'src/shared')

diff --git a/src/shared/mem.h b/src/shared/mem.h
index 8c83f2f..aac87f5 100644
--- a/src/shared/mem.h
+++ b/src/shared/mem.h
@@ -1,4 +1,5 @@
 #pragma once
+#include <stdarg.h>
 #include <stddef.h>
 
 /* note: (partially) tested in the userland tests */
@@ -11,3 +12,6 @@ void *memset(void *s, int c, size_t n);
 
 int strcmp(const char *s1, const char *s2);
 size_t strlen(const char *s);
+
+int snprintf(char *restrict str, size_t len, const char *restrict fmt, ...);
+int vsnprintf(char *restrict str, size_t len, const char *restrict fmt, va_list ap);
diff --git a/src/shared/printf.c b/src/shared/printf.c
index c1206f3..2dc3048 100644
--- a/src/shared/printf.c
+++ b/src/shared/printf.c
@@ -1,6 +1,7 @@
-#include <stdbool.h>
 #include <shared/mem.h>
 #include <shared/printf.h>
+#include <stdarg.h>
+#include <stdbool.h>
 
 struct out_state {
 	void (*back)(void *, const char *, size_t);
@@ -165,3 +166,31 @@ int __printf_internal(const char *fmt, va_list argp,
 		seg = fmt;
 	}
 }
+
+
+static void vsnprintf_backend(void *arg, const char *buf, size_t len) {
+	char **ptrs = arg;
+	size_t space = ptrs[1] - ptrs[0];
+	if (len > space) len = space;
+
+	memcpy(ptrs[0], buf, len);
+	ptrs[0] += len;
+	/* ptrs[1] is the last byte of the buffer, it must be 0.
+	 * on overflow:
+	 *   ptrs[0] + (ptrs[1] - ptrs[0]) = ptrs[1] */
+	*ptrs[0] = '\0';
+}
+
+int vsnprintf(char *restrict str, size_t len, const char *restrict fmt, va_list ap) {
+	char *ptrs[2] = {str, str + len - 1};
+	return __printf_internal(fmt, ap, vsnprintf_backend, &ptrs);
+}
+
+int snprintf(char *restrict str, size_t len, const char *restrict fmt, ...) {
+	int ret;
+	va_list argp;
+	va_start(argp, fmt);
+	ret = vsnprintf(str, len, fmt, argp);
+	va_end(argp);
+	return ret;
+}
-- 
cgit v1.2.3