From b48d53024c7b17ca0e2facf597a08a6e50f6a18b Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 20 May 2023 17:42:30 +0900 Subject: [PATCH] sds: add cfl_sds_snprintf Signed-off-by: Takahiro Yamashita --- include/cfl/cfl_sds.h | 1 + src/cfl_sds.c | 29 ++++++++++++ tests/sds.c | 101 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/include/cfl/cfl_sds.h b/include/cfl/cfl_sds.h index 3505473..a575ff3 100644 --- a/include/cfl/cfl_sds.h +++ b/include/cfl/cfl_sds.h @@ -61,5 +61,6 @@ cfl_sds_t cfl_sds_create_size(size_t size); void cfl_sds_set_len(cfl_sds_t s, size_t len); void cfl_sds_cat_safe(cfl_sds_t *buf, const char *str, int len); cfl_sds_t cfl_sds_printf(cfl_sds_t *sds, const char *fmt, ...); +int cfl_sds_snprintf(cfl_sds_t *str, size_t size, const char *fmt, ...); #endif diff --git a/src/cfl_sds.c b/src/cfl_sds.c index eff66fe..b025d4f 100644 --- a/src/cfl_sds.c +++ b/src/cfl_sds.c @@ -234,3 +234,32 @@ cfl_sds_t cfl_sds_printf(cfl_sds_t *sds, const char *fmt, ...) return s; } + +/* + * cfl_sds_snprintf is a wrapper of snprintf. + * The difference is that this function can increase the buffer of cfl_sds_t. + */ +int cfl_sds_snprintf(cfl_sds_t *str, size_t size, const char *fmt, ...) +{ + va_list va; + cfl_sds_t tmp; + int ret; + + retry_snprintf: + va_start(va, fmt); + ret = vsnprintf(*str, size, fmt, va); + if (ret > size) { + tmp = cfl_sds_increase(*str, ret-size); + if (tmp == NULL) { + return -1; + } + *str = tmp; + size = ret; + va_end(va); + goto retry_snprintf; + } + va_end(va); + + cfl_sds_len_set(*str, ret); + return ret; +} diff --git a/tests/sds.c b/tests/sds.c index 899725e..b6ea1f1 100644 --- a/tests/sds.c +++ b/tests/sds.c @@ -52,8 +52,109 @@ static void test_sds_printf() cfl_sds_destroy(s); } + +static int sds_twice(size_t sds_size, const char *input, const char* expect) +{ + int ret; + cfl_sds_t s; + cfl_sds_t tmp; + + s = cfl_sds_create_size(sds_size); + ret = cfl_sds_snprintf(&s, cfl_sds_avail(s), "%s%s", input, input); + if (!TEST_CHECK(ret >= 0)) { + TEST_MSG("cfl_sds_snprintf failed. ret=%d", ret); + return -1; + } + + /* check if buffer size is enough */ + if (ret >= cfl_sds_avail(s)) { + tmp = cfl_sds_increase(s, ret - cfl_sds_avail(s) + 1); + if (!TEST_CHECK(tmp != NULL)) { + TEST_MSG("cfl_sds_increase failed"); + cfl_sds_destroy(s); + return -1; + } + s = tmp; + ret = cfl_sds_snprintf(&s, cfl_sds_avail(s), "%s%s", input, input); + if (!TEST_CHECK(ret >= 0)) { + TEST_MSG("cfl_sds_snprintf failed. ret=%d", ret); + cfl_sds_destroy(s); + return -1; + } + else if (!TEST_CHECK(ret < cfl_sds_avail(s))) { + TEST_MSG("buffer is short. avail=%d, ret=%d, sds=%s",cfl_sds_avail(s), ret, s); + cfl_sds_destroy(s); + return -1; + } + } + + if (!TEST_CHECK(strcmp(s, expect) == 0)) { + TEST_MSG("strcmp failed. \ngot =%s\nexpect=%s", s, expect); + } + + cfl_sds_destroy(s); + return 0; +} + +struct sds_snprintf_case { + size_t size; + const char *input; + const char *expect; +}; + +static void test_sds_snprintf_simple() +{ + int ret; + cfl_sds_t buf; + size_t buf_size = 256; + + buf = cfl_sds_create_size(buf_size); + if (!TEST_CHECK(buf != NULL)) { + TEST_MSG("cfl_sds_create_size failed"); + return; + } + + ret = cfl_sds_snprintf(&buf, buf_size, "%d%s%zu", 10, "str", buf_size); + if (!TEST_CHECK(ret >= 0)) { + TEST_MSG("cfl_sds_snprintf failed. ret=%d", ret); + cfl_sds_destroy(buf); + return; + } + else if (!TEST_CHECK(ret < cfl_sds_avail(buf))) { + TEST_MSG("buffer size is short"); + cfl_sds_destroy(buf); + return; + } + + if (!TEST_CHECK(strcmp(buf, "10str256") == 0)) { + TEST_MSG("strcmp failed. \ngot =%s\nexpect=10str256", buf); + } + + cfl_sds_destroy(buf); +} + +static void test_sds_snprintf_cases() +{ + int ret; + int i; + struct sds_snprintf_case cases[] = { + {128, "a", "aa"}, + {10, "0123456789ABCDEF", "0123456789ABCDEF0123456789ABCDEF"}, + {0, NULL} + }; + + for (i=0; cases[i].input != NULL; i++) { + ret = sds_twice(cases[i].size, cases[i].input, cases[i].expect); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("case %d failed", i); + } + } +} + TEST_LIST = { { "sds_usage" , test_sds_usage}, { "sds_printf", test_sds_printf}, + { "sds_snprintf_simple", test_sds_snprintf_simple}, + { "sds_snprintf_cases", test_sds_snprintf_cases}, { 0 } };