From 6b13ca8ada41fd2d5bacb90cc4d6979ae628aca4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 20 May 2021 13:56:37 +0900 Subject: [PATCH] string-util: introduce strextendf_with_separator() --- src/basic/string-util.c | 31 ++++++++++++++++++------------- src/basic/string-util.h | 4 ++-- src/test/test-string-util.c | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index fd922b117b..a645958d38 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -790,8 +790,8 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) { return p; } -int strextendf(char **x, const char *format, ...) { - size_t m, a; +int strextendf_with_separator(char **x, const char *separator, const char *format, ...) { + size_t m, a, l_separator; va_list ap; int l; @@ -802,6 +802,8 @@ int strextendf(char **x, const char *format, ...) { assert(x); assert(format); + l_separator = isempty(*x) ? 0 : strlen_ptr(separator); + /* Let's try to use the allocated buffer, if there's room at the end still. Otherwise let's extend by 64 chars. */ if (*x) { m = strlen(*x); @@ -810,13 +812,15 @@ int strextendf(char **x, const char *format, ...) { } else m = a = 0; - if (a - m < 17) { /* if there's less than 16 chars space, then enlarge the buffer first */ + if (a - m < 17 + l_separator) { /* if there's less than 16 chars space, then enlarge the buffer first */ char *n; - if (_unlikely_(m > SIZE_MAX - 64)) /* overflow check */ + if (_unlikely_(l_separator > SIZE_MAX - 64)) /* overflow check #1 */ + return -ENOMEM; + if (_unlikely_(m > SIZE_MAX - 64 - l_separator)) /* overflow check #2 */ return -ENOMEM; - n = realloc(*x, m + 64); + n = realloc(*x, m + 64 + l_separator); if (!n) return -ENOMEM; @@ -825,19 +829,20 @@ int strextendf(char **x, const char *format, ...) { } /* Now, let's try to format the string into it */ + memcpy_safe(*x + m, separator, l_separator); va_start(ap, format); - l = vsnprintf(*x + m, a - m, format, ap); + l = vsnprintf(*x + m + l_separator, a - m - l_separator, format, ap); va_end(ap); assert(l >= 0); - if ((size_t) l < a - m) { + if ((size_t) l < a - m - l_separator) { char *n; /* Nice! This worked. We are done. But first, let's return the extra space we don't * need. This should be a cheap operation, since we only lower the allocation size here, * never increase. */ - n = realloc(*x, m + (size_t) l + 1); + n = realloc(*x, m + (size_t) l + l_separator + 1); if (n) *x = n; } else { @@ -845,22 +850,22 @@ int strextendf(char **x, const char *format, ...) { /* Wasn't enough. Then let's allocate exactly what we need. */ - if (_unlikely_((size_t) l > SIZE_MAX - 1)) /* overflow check #1 */ + if (_unlikely_((size_t) l > SIZE_MAX - (l_separator + 1))) /* overflow check #1 */ goto oom; - if (_unlikely_(m > SIZE_MAX - ((size_t) l + 1))) /* overflow check #2 */ + if (_unlikely_(m > SIZE_MAX - ((size_t) l + l_separator + 1))) /* overflow check #2 */ goto oom; - a = m + (size_t) l + 1; + a = m + (size_t) l + l_separator + 1; n = realloc(*x, a); if (!n) goto oom; *x = n; va_start(ap, format); - l = vsnprintf(*x + m, a - m, format, ap); + l = vsnprintf(*x + m + l_separator, a - m - l_separator, format, ap); va_end(ap); - assert((size_t) l < a - m); + assert((size_t) l < a - m - l_separator); } return 0; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 4ef3254dc5..9155e50ba8 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -156,11 +156,11 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]); char *strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_; - #define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL) #define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL) -int strextendf(char **x, const char *format, ...) _printf_(2,3); +int strextendf_with_separator(char **x, const char *separator, const char *format, ...) _printf_(3,4); +#define strextendf(x, ...) strextendf_with_separator(x, NULL, __VA_ARGS__) char *strrep(const char *s, unsigned n); diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 8174b12837..4d9d0260c9 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -984,6 +984,20 @@ static void test_strextendf(void) { assert_se(strextendf(&p, "<%08x>", 0x1234) >= 0); assert_se(streq(p, "<77><99>< 88><00001234>")); + + p = mfree(p); + + assert_se(strextendf_with_separator(&p, ",", "<%i>", 77) >= 0); + assert_se(streq(p, "<77>")); + + assert_se(strextendf_with_separator(&p, ",", "<%i>", 99) >= 0); + assert_se(streq(p, "<77>,<99>")); + + assert_se(strextendf_with_separator(&p, ",", "<%80i>", 88) >= 0); + assert_se(streq(p, "<77>,<99>,< 88>")); + + assert_se(strextendf_with_separator(&p, ",", "<%08x>", 0x1234) >= 0); + assert_se(streq(p, "<77>,<99>,< 88>,<00001234>")); } int main(int argc, char *argv[]) { -- 2.25.1