Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/cfl/cfl_sds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
29 changes: 29 additions & 0 deletions src/cfl_sds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
101 changes: 101 additions & 0 deletions tests/sds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};