From 21cc24baa135c1a2b882ba67c1e0b2cf9e64edfc Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 21 Dec 2025 19:19:37 -0500 Subject: usr: sdk: Add vsnprintf() family helpers Signed-off-by: Ian Moffett --- usr/sdk/common/string/vsnprintf.c | 120 ++++++++++++++++++++++++++++++++++++++ usr/sdk/inc/sdk/string.h | 22 ++++++- 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 usr/sdk/common/string/vsnprintf.c diff --git a/usr/sdk/common/string/vsnprintf.c b/usr/sdk/common/string/vsnprintf.c new file mode 100644 index 0000000..8d78989 --- /dev/null +++ b/usr/sdk/common/string/vsnprintf.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Ian Moffett. + * Provided under the BSD-3 clause. + */ + +#include +#include +#include + +static inline void +printc(char *buf, USIZE size, USIZE *off, char c) +{ + if (*off < size - 1) { + buf[(*off)++] = c; + } + buf[*off] = 0; +} + +static void +printstr(char *buf, USIZE size, USIZE *off, const char *s) +{ + while (*off < size - 1 && *s != '\0') { + buf[(*off)++] = *(s)++; + } + buf[*off] = 0; +} + +int +snprintf(char *s, USIZE size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(s, size, fmt, ap); + va_end(ap); + return ret; +} + +int +vsnprintf(char *s, USIZE size, const char *fmt, va_list ap) +{ + USIZE tmp_len, num_len, off = 0; + USIZE num = 0; + char c, c1, num_buf[256] = {0}; + const char *tmp_str; + BYTE pad_width = 0; + + while (off < (size - 1)) { + while (*fmt && *fmt != '%') { + printc(s, size, &off, *fmt++); + } + if (*(fmt)++ == '\0' || off == size - 1) { + return off; + } + + /* + * Handle a case where we have "%0N". For example: + * "%04d" + */ + if (*fmt == '0') { + ++fmt; + while (*fmt >= '0' && *fmt <= '9') { + pad_width = pad_width * 10 + (*fmt - '0'); + ++fmt; + } + } + + c = *fmt++; + switch (c) { + case 'c': + c1 = (char )va_arg(ap, int); + printc(s, size, &off, c1); + break; + case '%': + printc(s, size, &off, c); + break; + case 'd': + num = va_arg(ap, QUAD); + itoa(num, num_buf, 10); + + if (pad_width > 0) { + num_len = strlen(num_buf); + for (USIZE i = num_len; i < pad_width; ++i) + printc(s, size, &off, '0'); + pad_width = 0; + } + printstr(s, size, &off, num_buf); + break; + case 'p': + num = va_arg(ap, UQUAD); + itoa(num, num_buf, 16); + tmp_len = strlen(num_buf); + + /* Add '0x' prefix */ + printc(s, size, &off, '0'); + printc(s, size, &off, 'x'); + + /* XXX: Assumes 64-bit */ + for (USIZE i = 0; i < 18 - tmp_len; ++i) { + printc(s, size, &off, '0'); + } + + printstr(s, size, &off, num_buf + 2); + break; + case 'x': + num = va_arg(ap, UQUAD); + itoa(num, num_buf, 16); + tmp_len = strlen(num_buf); + printstr(s, size, &off, num_buf + 2); + break; + case 's': + tmp_str = va_arg(ap, const char *); + printstr(s, size, &off, tmp_str); + break; + } + } + + return 0; +} diff --git a/usr/sdk/inc/sdk/string.h b/usr/sdk/inc/sdk/string.h index 0f7ff27..965f66a 100644 --- a/usr/sdk/inc/sdk/string.h +++ b/usr/sdk/inc/sdk/string.h @@ -6,7 +6,8 @@ #ifndef _SDK_STRING_H_ #define _SDK_STRING_H_ 1 - #include +#include +#include /* * Returns the length of a string @@ -39,4 +40,23 @@ void *memcpy(void *dest, const void *src, USIZE count); */ char *itoa(QUAD value, char *buf, int base); +/* + * Write a formatted string to a buffer + * + * @s: Target buffer + * @size: Maximum buffer size + * @fmt: Format string + * @<...>: Args + */ +int snprintf(char *s, USIZE size, const char *fmt, ...); + +/* + * Write a formatted string to a buffer using a va_list + * + * @s: Target buffer + * @size: Maximum buffer size + * @ap: Args pointer + */ +int vsnprintf(char *s, USIZE size, const char *fmt, va_list ap); + #endif /* !_SDK_STRING_H_ */ -- cgit v1.2.3