abuf: Add a way to printf() into a buffer

It is useful to format a string into a buffer, with the sizing handled
automatically. Add a function for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/lib/abuf.c b/lib/abuf.c
index 28c748a..3a2fd17 100644
--- a/lib/abuf.c
+++ b/lib/abuf.c
@@ -10,8 +10,11 @@
 #include <malloc.h>
 #include <mapmem.h>
 #include <string.h>
+#include <vsprintf.h>
 #endif
 
+#include <errno.h>
+#include <stdarg.h>
 #include <abuf.h>
 
 void abuf_set(struct abuf *abuf, void *data, size_t size)
@@ -142,6 +145,38 @@
 	return true;
 }
 
+int abuf_printf(struct abuf *buf, const char *fmt, ...)
+{
+	int maxlen = buf->size;
+	va_list args;
+	int len;
+
+	va_start(args, fmt);
+	len = vsnprintf(buf->data, buf->size, fmt, args);
+	va_end(args);
+
+	/* add the terminator */
+	len++;
+
+	if (len > 4096)
+		return -E2BIG;
+	if (len > maxlen) {
+		/* make more space and try again */
+		maxlen = len;
+		if (!abuf_realloc(buf, maxlen))
+			return -ENOMEM;
+		va_start(args, fmt);
+		len = vsnprintf(buf->data, maxlen, fmt, args);
+		va_end(args);
+
+		/* check there isn't anything strange going on */
+		if (len > maxlen)
+			return -EFAULT;
+	}
+
+	return len;
+}
+
 void abuf_init_const(struct abuf *abuf, const void *data, size_t size)
 {
 	/* for now there is no flag indicating that the abuf data is constant */