mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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>
This commit is contained in:
@@ -122,6 +122,27 @@ bool abuf_realloc_inc(struct abuf *abuf, size_t inc);
|
||||
*/
|
||||
bool abuf_copy(const struct abuf *old, struct abuf *new);
|
||||
|
||||
/**
|
||||
* abuf_printf() - Format a string and place it in an abuf
|
||||
*
|
||||
* @buf: The buffer to place the result into
|
||||
* @fmt: The format string to use
|
||||
* @...: Arguments for the format string
|
||||
* Return: the number of characters writtenwhich would be
|
||||
* generated for the given input, excluding the trailing null,
|
||||
* as per ISO C99.
|
||||
*
|
||||
* The abuf is expanded as necessary to fit the formated string
|
||||
*
|
||||
* See the vsprintf() documentation for format string extensions over C99.
|
||||
*
|
||||
* Returns: number of characters written (excluding trailing nul) on success,
|
||||
* -E2BIG if the size exceeds 4K, -ENOMEM if out of memory, -EFAULT if there is
|
||||
* an internal bug in the vsnprintf() implementation
|
||||
*/
|
||||
int abuf_printf(struct abuf *buf, const char *fmt, ...)
|
||||
__attribute__ ((format (__printf__, 2, 3)));
|
||||
|
||||
/**
|
||||
* abuf_uninit_move() - Return the allocated contents and uninit the abuf
|
||||
*
|
||||
|
||||
35
lib/abuf.c
35
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 @@ bool abuf_copy(const struct abuf *old, struct abuf *copy)
|
||||
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 */
|
||||
|
||||
@@ -463,3 +463,64 @@ static int lib_test_abuf_init_size(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_abuf_init_size, 0);
|
||||
|
||||
/* Test abuf_printf() */
|
||||
static int lib_test_abuf_printf(struct unit_test_state *uts)
|
||||
{
|
||||
struct abuf buf, fmt;
|
||||
ulong start;
|
||||
char *ptr;
|
||||
|
||||
start = ut_check_free();
|
||||
|
||||
/* start with a fresh buffer */
|
||||
abuf_init(&buf);
|
||||
|
||||
/* check handling of out-of-memory condition */
|
||||
malloc_enable_testing(0);
|
||||
ut_asserteq(-ENOMEM, abuf_printf(&buf, "%s", ""));
|
||||
malloc_enable_testing(1);
|
||||
|
||||
ut_asserteq(0, abuf_printf(&buf, "%s", ""));
|
||||
ut_asserteq(1, buf.size);
|
||||
ut_asserteq(true, buf.alloced);
|
||||
ut_asserteq_str("", buf.data);
|
||||
|
||||
/* check expanding it, initially failing */
|
||||
ut_asserteq(-ENOMEM, abuf_printf(&buf, "%s", "testing"));
|
||||
malloc_disable_testing();
|
||||
|
||||
ut_asserteq(7, abuf_printf(&buf, "%s", "testing"));
|
||||
ut_asserteq(8, buf.size);
|
||||
ut_asserteq_str("testing", buf.data);
|
||||
|
||||
ut_asserteq(11, abuf_printf(&buf, "testing %d", 123));
|
||||
ut_asserteq(12, buf.size);
|
||||
ut_asserteq_str("testing 123", buf.data);
|
||||
|
||||
/* make it smaller; buffer should not shrink */
|
||||
ut_asserteq(9, abuf_printf(&buf, "test %d", 456));
|
||||
ut_asserteq(12, buf.size);
|
||||
ut_asserteq_str("test 456", buf.data);
|
||||
|
||||
/* test the maximum size */
|
||||
abuf_init(&fmt);
|
||||
ut_assert(abuf_realloc(&fmt, 4100));
|
||||
memset(fmt.data, 'x', 4100);
|
||||
ptr = fmt.data;
|
||||
ptr[4096] = '\0';
|
||||
|
||||
/* we are allowed up to 4K including the terminator */
|
||||
ut_asserteq(-E2BIG, abuf_printf(&buf, "%s", ptr));
|
||||
ptr[4095] = '\0';
|
||||
ut_asserteq(4095, abuf_printf(&buf, "%s", ptr));
|
||||
|
||||
abuf_uninit(&fmt);
|
||||
abuf_uninit(&buf);
|
||||
|
||||
/* Check for memory leaks */
|
||||
ut_assertok(ut_check_delta(start));
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIB_TEST(lib_test_abuf_printf, 0);
|
||||
|
||||
Reference in New Issue
Block a user