summaryrefslogtreecommitdiffstats
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.c129
1 files changed, 62 insertions, 67 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 7329bfa..d0d33a4 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -11,6 +11,7 @@
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
+#include "glyph-util.h"
#include "gunicode.h"
#include "locale-util.h"
#include "macro.h"
@@ -282,16 +283,9 @@ bool string_has_cc(const char *p, const char *ok) {
}
static int write_ellipsis(char *buf, bool unicode) {
- if (unicode || is_locale_utf8()) {
- buf[0] = 0xe2; /* tri-dot ellipsis: … */
- buf[1] = 0x80;
- buf[2] = 0xa6;
- } else {
- buf[0] = '.';
- buf[1] = '.';
- buf[2] = '.';
- }
-
+ const char *s = special_glyph_full(SPECIAL_GLYPH_ELLIPSIS, unicode);
+ assert(strlen(s) == 3);
+ memcpy(buf, s, 3);
return 3;
}
@@ -398,8 +392,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
x = ((new_length - need_space) * percent + 50) / 100;
assert(x <= new_length - need_space);
- memcpy(t, s, x);
- write_ellipsis(t + x, false);
+ write_ellipsis(mempcpy(t, s, x), /* unicode = */ false);
suffix_len = new_length - x - need_space;
memcpy(t + x + 3, s + old_length - suffix_len, suffix_len);
*(t + x + 3 + suffix_len) = '\0';
@@ -520,13 +513,8 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
if (!e)
return NULL;
- /*
- printf("old_length=%zu new_length=%zu x=%zu len=%zu len2=%zu k=%zu\n",
- old_length, new_length, x, len, len2, k);
- */
-
memcpy_safe(e, s, len);
- write_ellipsis(e + len, true);
+ write_ellipsis(e + len, /* unicode = */ true);
char *dst = e + len + 3;
@@ -562,7 +550,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
size_t i = 0, last_char_width[4] = {}, k = 0;
+ assert(buf);
assert(len > 0); /* at least a terminating NUL */
+ assert(s);
for (;;) {
char four[4];
@@ -603,7 +593,7 @@ char *cellescape(char *buf, size_t len, const char *s) {
}
if (i + 4 <= len) /* yay, enough space */
- i += write_ellipsis(buf + i, false);
+ i += write_ellipsis(buf + i, /* unicode = */ false);
else if (i + 3 <= len) { /* only space for ".." */
buf[i++] = '.';
buf[i++] = '.';
@@ -612,7 +602,7 @@ char *cellescape(char *buf, size_t len, const char *s) {
else
assert(i + 1 <= len);
- done:
+done:
buf[i] = '\0';
return buf;
}
@@ -620,6 +610,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
char* strshorten(char *s, size_t l) {
assert(s);
+ if (l >= SIZE_MAX-1) /* Would not change anything */
+ return s;
+
if (strnlen(s, l+1) > l)
s[l] = 0;
@@ -993,7 +986,7 @@ int strextendf_with_separator(char **x, const char *separator, const char *forma
return 0;
oom:
- /* truncate the bytes added after the first vsnprintf() attempt again */
+ /* truncate the bytes added after memcpy_safe() again */
(*x)[m] = 0;
return -ENOMEM;
}
@@ -1123,6 +1116,24 @@ int free_and_strndup(char **p, const char *s, size_t l) {
return 1;
}
+int strdup_to_full(char **ret, const char *src) {
+ if (!src) {
+ if (ret)
+ *ret = NULL;
+
+ return 0;
+ } else {
+ if (ret) {
+ char *t = strdup(src);
+ if (!t)
+ return -ENOMEM;
+ *ret = t;
+ }
+
+ return 1;
+ }
+};
+
bool string_is_safe(const char *p) {
if (!p)
return false;
@@ -1232,54 +1243,31 @@ int string_extract_line(const char *s, size_t i, char **ret) {
return -ENOMEM;
*ret = m;
- return !isempty(q + 1); /* more coming? */
- } else {
- if (p == s)
- *ret = NULL; /* Just use the input string */
- else {
- char *m;
-
- m = strdup(p);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- }
-
- return 0; /* The end */
- }
+ return !isempty(q + 1); /* More coming? */
+ } else
+ /* Tell the caller to use the input string if equal */
+ return strdup_to(ret, p != s ? p : NULL);
}
- if (!q) {
- char *m;
-
+ if (!q)
/* No more lines, return empty line */
-
- m = strdup("");
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0; /* The end */
- }
+ return strdup_to(ret, "");
p = q + 1;
c++;
}
}
-int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word) {
- /* In the default mode with no separators specified, we split on whitespace and
- * don't coalesce separators. */
+int string_contains_word_strv(const char *string, const char *separators, char * const *words, const char **ret_word) {
+ /* In the default mode with no separators specified, we split on whitespace and coalesce separators. */
const ExtractFlags flags = separators ? EXTRACT_DONT_COALESCE_SEPARATORS : 0;
-
const char *found = NULL;
+ int r;
- for (const char *p = string;;) {
+ for (;;) {
_cleanup_free_ char *w = NULL;
- int r;
- r = extract_first_word(&p, &w, separators, flags);
+ r = extract_first_word(&string, &w, separators, flags);
if (r < 0)
return r;
if (r == 0)
@@ -1420,18 +1408,6 @@ char *find_line_startswith(const char *haystack, const char *needle) {
return p + strlen(needle);
}
-char *startswith_strv(const char *string, char **strv) {
- char *found = NULL;
-
- STRV_FOREACH(i, strv) {
- found = startswith(string, *i);
- if (found)
- break;
- }
-
- return found;
-}
-
bool version_is_valid(const char *s) {
if (isempty(s))
return false;
@@ -1519,3 +1495,22 @@ ssize_t strlevenshtein(const char *x, const char *y) {
return t1[yl];
}
+
+char *strrstr(const char *haystack, const char *needle) {
+ /* Like strstr() but returns the last rather than the first occurrence of "needle" in "haystack". */
+
+ if (!haystack || !needle)
+ return NULL;
+
+ /* Special case: for the empty string we return the very last possible occurrence, i.e. *after* the
+ * last char, not before. */
+ if (*needle == 0)
+ return strchr(haystack, 0);
+
+ for (const char *p = strstr(haystack, needle), *q; p; p = q) {
+ q = strstr(p + 1, needle);
+ if (!q)
+ return (char *) p;
+ }
+ return NULL;
+}