# HG changeset patch # User Mike Becker # Date 1712951292 -7200 # Node ID edb9f875b7f9ed4f6aa03c3132c916291614d87d # Parent 6456036bbb37cc3fe3a1cf1382779805662824aa improves interface of cx_sprintf() variants diff -r 6456036bbb37 -r edb9f875b7f9 src/cx/printf.h --- a/src/cx/printf.h Wed Apr 03 21:22:23 2024 +0200 +++ b/src/cx/printf.h Fri Apr 12 21:48:12 2024 +0200 @@ -168,12 +168,12 @@ /** * An \c sprintf like function which reallocates the string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * @param str a pointer to the string buffer - * @param len the current length of the buffer + * @param len a pointer to the length of the buffer * @param fmt the format string * @param ... additional arguments * @return the length of produced string @@ -183,32 +183,32 @@ /** * An \c sprintf like function which reallocates the string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \attention The original buffer MUST have been allocated with the same allocator! * * @param alloc the allocator to use * @param str a pointer to the string buffer - * @param len the current length of the buffer + * @param len a pointer to the length of the buffer * @param fmt the format string * @param ... additional arguments * @return the length of produced string */ -__attribute__((__nonnull__(1, 2, 4), __format__(printf, 4, 5))) -int cx_sprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, ... ); +__attribute__((__nonnull__(1, 2, 3, 4), __format__(printf, 4, 5))) +int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ); /** * An \c sprintf like function which reallocates the string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * @param str a pointer to the string buffer - * @param len the current length of the buffer + * @param len a pointer to the length of the buffer * @param fmt the format string * @param ap argument list * @return the length of produced string @@ -218,38 +218,38 @@ /** * An \c sprintf like function which reallocates the string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \attention The original buffer MUST have been allocated with the same allocator! * * @param alloc the allocator to use * @param str a pointer to the string buffer - * @param len the current length of the buffer + * @param len a pointer to the length of the buffer * @param fmt the format string * @param ap argument list * @return the length of produced string */ __attribute__((__nonnull__)) -int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, va_list ap); +int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap); /** * An \c sprintf like function which allocates a new string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * The location of the resulting string will \em always be stored to \p str. When the buffer * was sufficiently large, \p buf itself will be stored to the location of \p str. * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \remark When a new string needed to be allocated, the contents of \p buf will be * poisoned after the call, because this function tries to produce the string in \p buf, first. * * @param buf a pointer to the buffer - * @param len the length of the buffer + * @param len a pointer to the length of the buffer * @param str a pointer to the location * @param fmt the format string * @param ... additional arguments @@ -260,42 +260,42 @@ /** * An \c sprintf like function which allocates a new string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * The location of the resulting string will \em always be stored to \p str. When the buffer * was sufficiently large, \p buf itself will be stored to the location of \p str. * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \remark When a new string needed to be allocated, the contents of \p buf will be * poisoned after the call, because this function tries to produce the string in \p buf, first. * * @param alloc the allocator to use * @param buf a pointer to the buffer - * @param len the length of the buffer + * @param len a pointer to the length of the buffer * @param str a pointer to the location * @param fmt the format string * @param ... additional arguments * @return the length of produced string */ __attribute__((__nonnull__(1, 2, 4, 5), __format__(printf, 5, 6))) -int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, ... ); +int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ); /** * An \c sprintf like function which allocates a new string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * The location of the resulting string will \em always be stored to \p str. When the buffer * was sufficiently large, \p buf itself will be stored to the location of \p str. * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \remark When a new string needed to be allocated, the contents of \p buf will be * poisoned after the call, because this function tries to produce the string in \p buf, first. * * @param buf a pointer to the buffer - * @param len the length of the buffer + * @param len a pointer to the length of the buffer * @param str a pointer to the location * @param fmt the format string * @param ap argument list @@ -306,26 +306,26 @@ /** * An \c sprintf like function which allocates a new string when the buffer is not large enough. * + * The size of the buffer will be updated in \p len when necessary. + * * The location of the resulting string will \em always be stored to \p str. When the buffer * was sufficiently large, \p buf itself will be stored to the location of \p str. * * \note The resulting string is guaranteed to be zero-terminated. - * That means, when the buffer needed to be reallocated, the new size of the buffer will be - * the length returned by this function plus one. * * \remark When a new string needed to be allocated, the contents of \p buf will be * poisoned after the call, because this function tries to produce the string in \p buf, first. * * @param alloc the allocator to use * @param buf a pointer to the buffer - * @param len the length of the buffer + * @param len a pointer to the length of the buffer * @param str a pointer to the location * @param fmt the format string * @param ap argument list * @return the length of produced string */ __attribute__((__nonnull__)) -int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, va_list ap); +int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap); #ifdef __cplusplus diff -r 6456036bbb37 -r edb9f875b7f9 src/printf.c --- a/src/printf.c Wed Apr 03 21:22:23 2024 +0200 +++ b/src/printf.c Fri Apr 12 21:48:12 2024 +0200 @@ -132,7 +132,7 @@ return s; } -int cx_sprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, ... ) { +int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) { va_list ap; va_start(ap, fmt); int ret = cx_vsprintf_a(alloc, str, len, fmt, ap); @@ -140,11 +140,11 @@ return ret; } -int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, va_list ap) { +int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) { va_list ap2; va_copy(ap2, ap); - int ret = vsnprintf(*str, len, fmt, ap); - if ((unsigned) ret >= len) { + int ret = vsnprintf(*str, *len, fmt, ap); + if ((unsigned) ret >= *len) { unsigned newlen = ret + 1; char *ptr = cxRealloc(alloc, *str, newlen); if (ptr) { @@ -152,6 +152,7 @@ if (newret < 0) { cxFree(alloc, ptr); } else { + *len = newlen; *str = ptr; ret = newret; } @@ -161,7 +162,7 @@ return ret; } -int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, ... ) { +int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) { va_list ap; va_start(ap, fmt); int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap); @@ -169,12 +170,12 @@ return ret; } -int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, va_list ap) { +int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) { va_list ap2; va_copy(ap2, ap); - int ret = vsnprintf(buf, len, fmt, ap); + int ret = vsnprintf(buf, *len, fmt, ap); *str = buf; - if ((unsigned) ret >= len) { + if ((unsigned) ret >= *len) { unsigned newlen = ret + 1; char *ptr = cxMalloc(alloc, newlen); if (ptr) { @@ -182,6 +183,7 @@ if (newret < 0) { cxFree(alloc, ptr); } else { + *len = newlen; *str = ptr; ret = newret; } diff -r 6456036bbb37 -r edb9f875b7f9 tests/test_printf.c --- a/tests/test_printf.c Wed Apr 03 21:22:23 2024 +0200 +++ b/tests/test_printf.c Fri Apr 12 21:48:12 2024 +0200 @@ -301,9 +301,11 @@ CxAllocator *alloc = &talloc.base; CX_TEST_DO { char *oldbuf = buf; - size_t len = cx_sprintf_a(alloc, &buf, 16, "Test %d %s", 47, "string"); + size_t buflen = 16; + size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 47, "string"); CX_TEST_ASSERT(oldbuf == buf); CX_TEST_ASSERT(len == 14); + CX_TEST_ASSERT(buflen == 16); CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15)); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); } @@ -317,8 +319,10 @@ CxAllocator *alloc = &talloc.base; char *buf = cxMalloc(alloc, 8); CX_TEST_DO { - size_t len = cx_sprintf_a(alloc, &buf, 8, "Test %d %s", 47, "foobar"); + size_t buflen = 8; + size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 47, "foobar"); CX_TEST_ASSERT(len == 14); + CX_TEST_ASSERT(buflen == 15); CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 foobar", 15)); cxFree(alloc, buf); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); @@ -333,8 +337,10 @@ // make it so that only the zero-terminator does not fit char *buf = cxMalloc(alloc, 14); CX_TEST_DO { - size_t len = cx_sprintf_a(alloc, &buf, 14, "Test %d %s", 13, "string"); + size_t buflen = 14; + size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 13, "string"); CX_TEST_ASSERT(len == 14); + CX_TEST_ASSERT(buflen == 15); CX_TEST_ASSERT(0 == memcmp(buf, "Test 13 string", 15)); cxFree(alloc, buf); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); @@ -349,8 +355,10 @@ CxAllocator *alloc = &talloc.base; CX_TEST_DO { char *str; - size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Test %d %s", 47, "string"); + size_t buflen = 16; + size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str, "Test %d %s", 47, "string"); CX_TEST_ASSERT(str == buf); + CX_TEST_ASSERT(buflen == 16); CX_TEST_ASSERT(len == 14); CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15)); CX_TEST_ASSERT(0 == memcmp(str, "Test 47 string", 15)); @@ -367,8 +375,10 @@ CxAllocator *alloc = &talloc.base; CX_TEST_DO { char *str; - size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Hello %d %s", 4711, "larger string"); + size_t buflen = 16; + size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str, "Hello %d %s", 4711, "larger string"); CX_TEST_ASSERT(str != buf); + CX_TEST_ASSERT(buflen == 25); CX_TEST_ASSERT(len == 24); CX_TEST_ASSERT(0 == memcmp(str, "Hello 4711 larger string", 25)); cxFree(alloc, str); @@ -385,9 +395,11 @@ CxAllocator *alloc = &talloc.base; CX_TEST_DO { char *str; - size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Hello %d %s", 112, "string"); + size_t buflen = 16; + size_t len = cx_sprintf_sa(alloc, buf,&buflen, &str, "Hello %d %s", 112, "string"); CX_TEST_ASSERT(str != buf); CX_TEST_ASSERT(len == 16); + CX_TEST_ASSERT(buflen == 17); CX_TEST_ASSERT(0 == memcmp(str, "Hello 112 string", 17)); // include terminator cxFree(alloc, str); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));