1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-02-09 09:57:26 +03:00

string-util: introduce strextendf_with_separator()

This commit is contained in:
Yu Watanabe 2021-05-20 13:56:37 +09:00
parent 354dadb30f
commit 6b13ca8ada
3 changed files with 34 additions and 15 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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[]) {