diff --git a/include/ucore/dstr.h b/include/ucore/dstr.h index 33f7be2..77e462d 100644 --- a/include/ucore/dstr.h +++ b/include/ucore/dstr.h @@ -2,6 +2,7 @@ #define UC_DSTR_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -134,6 +135,12 @@ size_t uc_dstr_replace(struct DStr *str, char f, char r); */ void uc_dstr_trim(struct DStr *str); +/** Append formatted string (just as sprintf)*/ +int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) __attribute__((format(printf,2,3))); + +/** va_list variant */ +int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_)__attribute__((format(printf,2,0))); + #ifdef __cplusplus } #endif diff --git a/src/dstr.c b/src/dstr.c index 101252d..59d4cbc 100644 --- a/src/dstr.c +++ b/src/dstr.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "ucore/dstr.h" #include "ucore/utils.h" @@ -26,7 +28,7 @@ int uc_dstr_ensure(struct DStr *str, size_t len) //allocate a minimum no. of bytes, and one //additional for the common case of nul terminating //the string - size_t new_len = str->len + UC_MAX(7U, len) + 1; + size_t new_len = UC_MAX(7U, len) + 1; char *new_str = realloc(str->str, new_len); if (new_str == NULL) { @@ -204,4 +206,55 @@ void uc_dstr_trim(struct DStr *str) } } +int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = uc_dstr_vsprintf(str, fmt, ap); + va_end(ap); + + return rc; +} + +int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_) +{ + va_list ap; + int rc; + int available; + int needed; + + rc = uc_dstr_ensure(str, str->len + 1); + if (rc != 0) { + return -1; + } + + available = uc_dstr_available(str); + + va_copy(ap, ap_); + needed = vsnprintf(str->str + str->len, available, fmt, ap); + va_end(ap); + + if (needed <= 0) { + return needed; + } + + if (needed >= available) { + rc = uc_dstr_ensure(str, str->len + needed); + if (rc != 0) { + return -1; + } + + available = uc_dstr_available(str); + + va_copy(ap, ap_); + needed = vsnprintf(str->str + str->len, available, fmt, ap); + va_end(ap); + } + + str->len += needed; + + return needed; +} diff --git a/test/test_dstr.c b/test/test_dstr.c index 1d1a9d4..da5b625 100644 --- a/test/test_dstr.c +++ b/test/test_dstr.c @@ -31,7 +31,7 @@ START_TEST (test_dstr_basics) ck_assert_str_eq(uc_dstr_str(&str), ""); uc_dstr_reset(&str); - ck_assert_int_ge(uc_dstr_available(&str), 0); + ck_assert_int_gt(uc_dstr_available(&str), 0); s = uc_dstr_put(&str, 2); fail_if(s == NULL); @@ -123,6 +123,23 @@ START_TEST (test_dstr_filter) END_TEST +START_TEST (test_dstr_sprintf) + struct DStr str; + size_t rc; + + uc_dstr_init(&str); + rc = uc_dstr_sprintf(&str, "%d-%d-%d", 1, 2, 3); + ck_assert_int_gt(rc, 0); + ck_assert_str_eq(uc_dstr_str(&str), "1-2-3"); + + rc = uc_dstr_sprintf(&str, " Another, bigger %s.", "string"); + ck_assert_int_gt(rc, 0); + ck_assert_str_eq(uc_dstr_str(&str), "1-2-3 Another, bigger string."); + + uc_dstr_destroy(&str); + +END_TEST + Suite *dstr_suite(void) { Suite *s = suite_create("dstr"); @@ -132,6 +149,7 @@ Suite *dstr_suite(void) tcase_add_test(tc, test_dstr_trim); tcase_add_test(tc, test_dstr_replace); tcase_add_test(tc, test_dstr_filter); + tcase_add_test(tc, test_dstr_sprintf); suite_add_tcase(s, tc);