summaryrefslogtreecommitdiff
path: root/src/basic/string-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic/string-util.c')
-rw-r--r--src/basic/string-util.c121
1 files changed, 87 insertions, 34 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 3179fba3ba..7e2f596edc 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -21,6 +22,7 @@
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
@@ -278,6 +280,9 @@ char *strjoin_real(const char *x, ...) {
char *strstrip(char *s) {
char *e;
+ if (!s)
+ return NULL;
+
/* Drops trailing whitespace. Modifies the string in
* place. Returns pointer to first non-space character */
@@ -295,7 +300,13 @@ char *strstrip(char *s) {
char *delete_chars(char *s, const char *bad) {
char *f, *t;
- /* Drops all whitespace, regardless where in the string */
+ /* Drops all specified bad characters, regardless where in the string */
+
+ if (!s)
+ return NULL;
+
+ if (!bad)
+ bad = WHITESPACE;
for (f = s, t = s; *f; f++) {
if (strchr(bad, *f))
@@ -309,6 +320,26 @@ char *delete_chars(char *s, const char *bad) {
return s;
}
+char *delete_trailing_chars(char *s, const char *bad) {
+ char *p, *c = s;
+
+ /* Drops all specified bad characters, at the end of the string */
+
+ if (!s)
+ return NULL;
+
+ if (!bad)
+ bad = WHITESPACE;
+
+ for (p = s; *p; p++)
+ if (!strchr(bad, *p))
+ c = p + 1;
+
+ *c = 0;
+
+ return s;
+}
+
char *truncate_nl(char *s) {
assert(s);
@@ -472,6 +503,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
assert(s);
assert(percent <= 100);
+
+ if (new_length == (size_t) -1)
+ return strndup(s, old_length);
+
assert(new_length >= 3);
/* if no multibyte characters use ascii_ellipsize_mem for speed */
@@ -539,6 +574,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
}
char *ellipsize(const char *s, size_t length, unsigned percent) {
+
+ if (length == (size_t) -1)
+ return strdup(s);
+
return ellipsize_mem(s, strlen(s), length, percent);
}
@@ -565,26 +604,26 @@ char* strshorten(char *s, size_t l) {
}
char *strreplace(const char *text, const char *old_string, const char *new_string) {
+ size_t l, old_len, new_len, allocated = 0;
+ char *t, *ret = NULL;
const char *f;
- char *t, *r;
- size_t l, old_len, new_len;
- assert(text);
assert(old_string);
assert(new_string);
+ if (!text)
+ return NULL;
+
old_len = strlen(old_string);
new_len = strlen(new_string);
l = strlen(text);
- r = new(char, l+1);
- if (!r)
+ if (!GREEDY_REALLOC(ret, allocated, l+1))
return NULL;
f = text;
- t = r;
+ t = ret;
while (*f) {
- char *a;
size_t d, nl;
if (!startswith(f, old_string)) {
@@ -592,25 +631,21 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin
continue;
}
- d = t - r;
+ d = t - ret;
nl = l - old_len + new_len;
- a = realloc(r, nl + 1);
- if (!a)
- goto oom;
+
+ if (!GREEDY_REALLOC(ret, allocated, nl + 1))
+ return mfree(ret);
l = nl;
- r = a;
- t = r + d;
+ t = ret + d;
t = stpcpy(t, new_string);
f += old_len;
}
*t = 0;
- return r;
-
-oom:
- return mfree(r);
+ return ret;
}
char *strip_tab_ansi(char **ibuf, size_t *_isz) {
@@ -635,10 +670,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (!f)
return NULL;
- /* Note we use the _unlocked() stdio variants on f for performance
- * reasons. It's safe to do so since we created f here and it
- * doesn't leave our scope.
- */
+ /* Note we turn off internal locking on f for performance reasons. It's safe to do so since we created f here
+ * and it doesn't leave our scope. */
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
@@ -650,21 +685,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
- fputs_unlocked(" ", f);
+ fputs(" ", f);
else
- fputc_unlocked(*i, f);
+ fputc(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
- fputc_unlocked('\x1B', f);
+ fputc('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
- fputc_unlocked('\x1B', f);
- fputc_unlocked(*i, f);
+ fputc('\x1B', f);
+ fputc(*i, f);
state = STATE_OTHER;
}
@@ -674,8 +709,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (i >= *ibuf + isz || /* EOT */
(!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
- fputc_unlocked('\x1B', f);
- fputc_unlocked('[', f);
+ fputc('\x1B', f);
+ fputc('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
@@ -700,16 +735,20 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
return obuf;
}
-char *strextend(char **x, ...) {
- va_list ap;
- size_t f, l;
+char *strextend_with_separator(char **x, const char *separator, ...) {
+ bool need_separator;
+ size_t f, l, l_separator;
char *r, *p;
+ va_list ap;
assert(x);
l = f = strlen_ptr(*x);
- va_start(ap, x);
+ need_separator = !isempty(*x);
+ l_separator = strlen_ptr(separator);
+
+ va_start(ap, separator);
for (;;) {
const char *t;
size_t n;
@@ -719,22 +758,29 @@ char *strextend(char **x, ...) {
break;
n = strlen(t);
+
+ if (need_separator)
+ n += l_separator;
+
if (n > ((size_t) -1) - l) {
va_end(ap);
return NULL;
}
l += n;
+ need_separator = true;
}
va_end(ap);
+ need_separator = !isempty(*x);
+
r = realloc(*x, l+1);
if (!r)
return NULL;
p = r + f;
- va_start(ap, x);
+ va_start(ap, separator);
for (;;) {
const char *t;
@@ -742,10 +788,17 @@ char *strextend(char **x, ...) {
if (!t)
break;
+ if (need_separator && separator)
+ p = stpcpy(p, separator);
+
p = stpcpy(p, t);
+
+ need_separator = true;
}
va_end(ap);
+ assert(p == r + l);
+
*p = 0;
*x = r;