summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/btrfs-util.c14
-rw-r--r--src/basic/calendarspec.c1
-rw-r--r--src/basic/cgroup-util.c1
-rw-r--r--src/basic/clock-util.c5
-rw-r--r--src/basic/conf-files.c15
-rw-r--r--src/basic/copy.c3
-rw-r--r--src/basic/env-util.c3
-rw-r--r--src/basic/fdset.c3
-rw-r--r--src/basic/fileio.c1
-rw-r--r--src/basic/hostname-util.c3
-rw-r--r--src/basic/json.c4
-rw-r--r--src/basic/locale-util.c6
-rw-r--r--src/basic/log.c24
-rw-r--r--src/basic/log.h7
-rw-r--r--src/basic/login-util.c3
-rw-r--r--src/basic/memfd-util.c14
-rw-r--r--src/basic/path-util.c17
-rw-r--r--src/basic/process-util.c1
-rw-r--r--src/basic/rm-rf.c5
-rw-r--r--src/basic/signal-util.c2
-rw-r--r--src/basic/socket-util.c19
-rw-r--r--src/basic/string-util.c767
-rw-r--r--src/basic/string-util.h170
-rw-r--r--src/basic/strv.c5
-rw-r--r--src/basic/terminal-util.c27
-rw-r--r--src/basic/time-util.c7
-rw-r--r--src/basic/unit-name.c7
-rw-r--r--src/basic/util.c744
-rw-r--r--src/basic/util.h139
-rw-r--r--src/basic/verbs.c1
-rw-r--r--src/basic/virt.c7
-rw-r--r--src/basic/xml.c1
32 files changed, 1055 insertions, 971 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index f327c16a80..df7b959c12 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -20,22 +20,22 @@
***/
#include <stdlib.h>
-#include <sys/vfs.h>
#include <sys/stat.h>
-
+#include <sys/vfs.h>
#ifdef HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
+#include "btrfs-ctree.h"
+#include "copy.h"
+#include "fileio.h"
+#include "macro.h"
#include "missing.h"
-#include "util.h"
#include "path-util.h"
-#include "macro.h"
-#include "copy.h"
#include "selinux-util.h"
#include "smack-util.h"
-#include "fileio.h"
-#include "btrfs-ctree.h"
+#include "string-util.h"
+#include "util.h"
#include "btrfs-util.h"
/* WARNING: Be careful with file system ioctls! When we get an fd, we
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index a2296f4709..987ca81910 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
+#include "string-util.h"
#include "calendarspec.h"
#define BITS_WEEKDAYS 127
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index a3ea512165..ce21ef73eb 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -39,6 +39,7 @@
#include "process-util.h"
#include "set.h"
#include "special.h"
+#include "string-util.h"
#include "unit-name.h"
#include "util.h"
#include "cgroup-util.h"
diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c
index e4e03df1e4..03ec5725ae 100644
--- a/src/basic/clock-util.c
+++ b/src/basic/clock-util.c
@@ -20,13 +20,14 @@
***/
#include <errno.h>
-#include <stdio.h>
#include <fcntl.h>
+#include <linux/rtc.h>
+#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/time.h>
-#include <linux/rtc.h>
#include "macro.h"
+#include "string-util.h"
#include "util.h"
#include "clock-util.h"
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index da8745b284..0e44d1bbad 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -19,19 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
+#include <dirent.h>
#include <errno.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "hashmap.h"
+#include "log.h"
#include "macro.h"
-#include "util.h"
#include "missing.h"
-#include "log.h"
-#include "strv.h"
#include "path-util.h"
-#include "hashmap.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
#include "conf-files.h"
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
diff --git a/src/basic/copy.c b/src/basic/copy.c
index b20c178727..7702d906c7 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -22,9 +22,10 @@
#include <sys/sendfile.h>
#include <sys/xattr.h>
-#include "util.h"
#include "btrfs-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "util.h"
#include "copy.h"
#define COPY_BUFFER_SIZE (16*1024)
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index ecb2192c4d..a392af737c 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -22,11 +22,12 @@
#include <limits.h>
#include <unistd.h>
+#include "def.h"
+#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "util.h"
#include "env-util.h"
-#include "def.h"
#define VALID_CHARS_ENV_NAME \
DIGITS LETTERS \
diff --git a/src/basic/fdset.c b/src/basic/fdset.c
index d70fe156a2..2882f515b5 100644
--- a/src/basic/fdset.c
+++ b/src/basic/fdset.c
@@ -23,11 +23,12 @@
#include <dirent.h>
#include <fcntl.h>
+#include "sd-daemon.h"
+
#include "set.h"
#include "util.h"
#include "macro.h"
#include "fdset.h"
-#include "sd-daemon.h"
#define MAKE_SET(s) ((Set*) s)
#define MAKE_FDSET(s) ((FDSet*) s)
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 65a6a6558b..f8ccf79221 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -23,6 +23,7 @@
#include "ctype.h"
#include "escape.h"
+#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "util.h"
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index 1b816fb77a..8d10615682 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/utsname.h>
#include <ctype.h>
+#include <sys/utsname.h>
+#include "string-util.h"
#include "util.h"
#include "hostname-util.h"
diff --git a/src/basic/json.c b/src/basic/json.c
index be40a0d203..2b634aa7f8 100644
--- a/src/basic/json.c
+++ b/src/basic/json.c
@@ -19,9 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <math.h>
+#include <sys/types.h>
+
#include "macro.h"
+#include "string-util.h"
#include "utf8.h"
#include "json.h"
diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c
index 61db9a8125..a44daf8f5e 100644
--- a/src/basic/locale-util.c
+++ b/src/basic/locale-util.c
@@ -22,10 +22,10 @@
#include <sys/mman.h>
#include "set.h"
-#include "util.h"
-#include "utf8.h"
+#include "string-util.h"
#include "strv.h"
-
+#include "utf8.h"
+#include "util.h"
#include "locale-util.h"
static int add_locales_from_archive(Set *locales) {
diff --git a/src/basic/log.c b/src/basic/log.c
index e6d7d15182..acc390b8d3 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -19,26 +19,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdarg.h>
-#include <stdio.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <stddef.h>
-#include <printf.h>
+#include <unistd.h>
#include "sd-messages.h"
-#include "log.h"
-#include "util.h"
-#include "missing.h"
-#include "macro.h"
-#include "socket-util.h"
+
#include "formats-util.h"
+#include "macro.h"
+#include "missing.h"
#include "process-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
+#include "log.h"
#define SNDBUF_SIZE (8*1024*1024)
diff --git a/src/basic/log.h b/src/basic/log.h
index 369d6b1127..cda1e45cc8 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -21,14 +21,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
+#include <errno.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdlib.h>
-#include <syslog.h>
#include <sys/signalfd.h>
-#include <errno.h>
+#include <syslog.h>
#include "sd-id128.h"
+
#include "macro.h"
typedef enum LogTarget{
diff --git a/src/basic/login-util.c b/src/basic/login-util.c
index e25437f0f4..832f477bd2 100644
--- a/src/basic/login-util.c
+++ b/src/basic/login-util.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "login-util.h"
#include "def.h"
+#include "string-util.h"
+#include "login-util.h"
bool session_id_valid(const char *id) {
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index e99a738e1f..4dafd69daf 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -19,19 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-
#ifdef HAVE_LINUX_MEMFD_H
-# include <linux/memfd.h>
+#include <linux/memfd.h>
#endif
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include "missing.h"
+#include "string-util.h"
+#include "utf8.h"
#include "util.h"
#include "memfd-util.h"
-#include "utf8.h"
-#include "missing.h"
int memfd_new(const char *name) {
_cleanup_free_ char *g = NULL;
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 6b05b6edb1..31328807f4 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -19,21 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/statvfs.h>
+#include <unistd.h>
-#include "macro.h"
-#include "util.h"
+#include "fileio.h"
#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "string-util.h"
#include "strv.h"
+#include "util.h"
#include "path-util.h"
-#include "missing.h"
-#include "fileio.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 3199efeafd..bfde17a956 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -32,6 +32,7 @@
#include "fileio.h"
#include "log.h"
#include "signal-util.h"
+#include "string-util.h"
#include "util.h"
#include "process-util.h"
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index 2ef63799d7..5a75090a6d 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "path-util.h"
#include "btrfs-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "util.h"
#include "rm-rf.h"
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index 90abe8af81..730f99e0af 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -19,7 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
#include "util.h"
+
#include "signal-util.h"
int reset_all_signal_handlers(void) {
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 8fd3149276..9ed5feb849 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -19,23 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
#include <arpa/inet.h>
-#include <stdio.h>
+#include <errno.h>
#include <net/if.h>
-#include <sys/types.h>
-#include <stddef.h>
#include <netdb.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "fileio.h"
+#include "formats-util.h"
#include "macro.h"
+#include "missing.h"
#include "path-util.h"
+#include "string-util.h"
#include "util.h"
#include "socket-util.h"
-#include "missing.h"
-#include "fileio.h"
-#include "formats-util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
new file mode 100644
index 0000000000..a7cf4e8520
--- /dev/null
+++ b/src/basic/string-util.c
@@ -0,0 +1,767 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "gunicode.h"
+#include "utf8.h"
+#include "util.h"
+#include "string-util.h"
+
+int strcmp_ptr(const char *a, const char *b) {
+
+ /* Like strcmp(), but tries to make sense of NULL pointers */
+ if (a && b)
+ return strcmp(a, b);
+
+ if (!a && b)
+ return -1;
+
+ if (a && !b)
+ return 1;
+
+ return 0;
+}
+
+char* endswith(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (memcmp(s + sl - pl, postfix, pl) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
+char* endswith_no_case(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcasecmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
+char* first_word(const char *s, const char *word) {
+ size_t sl, wl;
+ const char *p;
+
+ assert(s);
+ assert(word);
+
+ /* Checks if the string starts with the specified word, either
+ * followed by NUL or by whitespace. Returns a pointer to the
+ * NUL or the first character after the whitespace. */
+
+ sl = strlen(s);
+ wl = strlen(word);
+
+ if (sl < wl)
+ return NULL;
+
+ if (wl == 0)
+ return (char*) s;
+
+ if (memcmp(s, word, wl) != 0)
+ return NULL;
+
+ p = s + wl;
+ if (*p == 0)
+ return (char*) p;
+
+ if (!strchr(WHITESPACE, *p))
+ return NULL;
+
+ p += strspn(p, WHITESPACE);
+ return (char*) p;
+}
+
+static size_t strcspn_escaped(const char *s, const char *reject) {
+ bool escaped = false;
+ int n;
+
+ for (n=0; s[n]; n++) {
+ if (escaped)
+ escaped = false;
+ else if (s[n] == '\\')
+ escaped = true;
+ else if (strchr(reject, s[n]))
+ break;
+ }
+
+ /* if s ends in \, return index of previous char */
+ return n - escaped;
+}
+
+/* Split a string into words. */
+const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+ const char *current;
+
+ current = *state;
+
+ if (!*current) {
+ assert(**state == '\0');
+ return NULL;
+ }
+
+ current += strspn(current, separator);
+ if (!*current) {
+ *state = current;
+ return NULL;
+ }
+
+ if (quoted && strchr("\'\"", *current)) {
+ char quotechars[2] = {*current, '\0'};
+
+ *l = strcspn_escaped(current + 1, quotechars);
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+ (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+ /* right quote missing or garbage at the end */
+ *state = current;
+ return NULL;
+ }
+ *state = current++ + *l + 2;
+ } else if (quoted) {
+ *l = strcspn_escaped(current, separator);
+ if (current[*l] && !strchr(separator, current[*l])) {
+ /* unfinished escape */
+ *state = current;
+ return NULL;
+ }
+ *state = current + *l;
+ } else {
+ *l = strcspn(current, separator);
+ *state = current + *l;
+ }
+
+ return current;
+}
+
+char *strnappend(const char *s, const char *suffix, size_t b) {
+ size_t a;
+ char *r;
+
+ if (!s && !suffix)
+ return strdup("");
+
+ if (!s)
+ return strndup(suffix, b);
+
+ if (!suffix)
+ return strdup(s);
+
+ assert(s);
+ assert(suffix);
+
+ a = strlen(s);
+ if (b > ((size_t) -1) - a)
+ return NULL;
+
+ r = new(char, a+b+1);
+ if (!r)
+ return NULL;
+
+ memcpy(r, s, a);
+ memcpy(r+a, suffix, b);
+ r[a+b] = 0;
+
+ return r;
+}
+
+char *strappend(const char *s, const char *suffix) {
+ return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+char *strjoin(const char *x, ...) {
+ va_list ap;
+ size_t l;
+ char *r, *p;
+
+ va_start(ap, x);
+
+ if (x) {
+ l = strlen(x);
+
+ for (;;) {
+ const char *t;
+ size_t n;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ n = strlen(t);
+ if (n > ((size_t) -1) - l) {
+ va_end(ap);
+ return NULL;
+ }
+
+ l += n;
+ }
+ } else
+ l = 0;
+
+ va_end(ap);
+
+ r = new(char, l+1);
+ if (!r)
+ return NULL;
+
+ if (x) {
+ p = stpcpy(r, x);
+
+ va_start(ap, x);
+
+ for (;;) {
+ const char *t;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ p = stpcpy(p, t);
+ }
+
+ va_end(ap);
+ } else
+ r[0] = 0;
+
+ return r;
+}
+
+char *strstrip(char *s) {
+ char *e;
+
+ /* Drops trailing whitespace. Modifies the string in
+ * place. Returns pointer to first non-space character */
+
+ s += strspn(s, WHITESPACE);
+
+ for (e = strchr(s, 0); e > s; e --)
+ if (!strchr(WHITESPACE, e[-1]))
+ break;
+
+ *e = 0;
+
+ return s;
+}
+
+char *delete_chars(char *s, const char *bad) {
+ char *f, *t;
+
+ /* Drops all whitespace, regardless where in the string */
+
+ for (f = s, t = s; *f; f++) {
+ if (strchr(bad, *f))
+ continue;
+
+ *(t++) = *f;
+ }
+
+ *t = 0;
+
+ return s;
+}
+
+char *truncate_nl(char *s) {
+ assert(s);
+
+ s[strcspn(s, NEWLINE)] = 0;
+ return s;
+}
+
+char *ascii_strlower(char *t) {
+ char *p;
+
+ assert(t);
+
+ for (p = t; *p; p++)
+ if (*p >= 'A' && *p <= 'Z')
+ *p = *p - 'A' + 'a';
+
+ return t;
+}
+
+bool chars_intersect(const char *a, const char *b) {
+ const char *p;
+
+ /* Returns true if any of the chars in a are in b. */
+ for (p = a; *p; p++)
+ if (strchr(b, *p))
+ return true;
+
+ return false;
+}
+
+bool string_has_cc(const char *p, const char *ok) {
+ const char *t;
+
+ assert(p);
+
+ /*
+ * Check if a string contains control characters. If 'ok' is
+ * non-NULL it may be a string containing additional CCs to be
+ * considered OK.
+ */
+
+ for (t = p; *t; t++) {
+ if (ok && strchr(ok, *t))
+ continue;
+
+ if (*t > 0 && *t < ' ')
+ return true;
+
+ if (*t == 127)
+ return true;
+ }
+
+ return false;
+}
+
+static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+ size_t x;
+ char *r;
+
+ assert(s);
+ assert(percent <= 100);
+ assert(new_length >= 3);
+
+ if (old_length <= 3 || old_length <= new_length)
+ return strndup(s, old_length);
+
+ r = new0(char, new_length+1);
+ if (!r)
+ return NULL;
+
+ x = (new_length * percent) / 100;
+
+ if (x > new_length - 3)
+ x = new_length - 3;
+
+ memcpy(r, s, x);
+ r[x] = '.';
+ r[x+1] = '.';
+ r[x+2] = '.';
+ memcpy(r + x + 3,
+ s + old_length - (new_length - x - 3),
+ new_length - x - 3);
+
+ return r;
+}
+
+char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+ size_t x;
+ char *e;
+ const char *i, *j;
+ unsigned k, len, len2;
+
+ assert(s);
+ assert(percent <= 100);
+ assert(new_length >= 3);
+
+ /* if no multibyte characters use ascii_ellipsize_mem for speed */
+ if (ascii_is_valid(s))
+ return ascii_ellipsize_mem(s, old_length, new_length, percent);
+
+ if (old_length <= 3 || old_length <= new_length)
+ return strndup(s, old_length);
+
+ x = (new_length * percent) / 100;
+
+ if (x > new_length - 3)
+ x = new_length - 3;
+
+ k = 0;
+ for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
+ int c;
+
+ c = utf8_encoded_to_unichar(i);
+ if (c < 0)
+ return NULL;
+ k += unichar_iswide(c) ? 2 : 1;
+ }
+
+ if (k > x) /* last character was wide and went over quota */
+ x ++;
+
+ for (j = s + old_length; k < new_length && j > i; ) {
+ int c;
+
+ j = utf8_prev_char(j);
+ c = utf8_encoded_to_unichar(j);
+ if (c < 0)
+ return NULL;
+ k += unichar_iswide(c) ? 2 : 1;
+ }
+ assert(i <= j);
+
+ /* we don't actually need to ellipsize */
+ if (i == j)
+ return memdup(s, old_length + 1);
+
+ /* make space for ellipsis */
+ j = utf8_next_char(j);
+
+ len = i - s;
+ len2 = s + old_length - j;
+ e = new(char, len + 3 + len2 + 1);
+ if (!e)
+ return NULL;
+
+ /*
+ printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
+ old_length, new_length, x, len, len2, k);
+ */
+
+ memcpy(e, s, len);
+ e[len] = 0xe2; /* tri-dot ellipsis: … */
+ e[len + 1] = 0x80;
+ e[len + 2] = 0xa6;
+
+ memcpy(e + len + 3, j, len2 + 1);
+
+ return e;
+}
+
+char *ellipsize(const char *s, size_t length, unsigned percent) {
+ return ellipsize_mem(s, strlen(s), length, percent);
+}
+
+bool nulstr_contains(const char*nulstr, const char *needle) {
+ const char *i;
+
+ if (!nulstr)
+ return false;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return true;
+
+ return false;
+}
+
+char* strshorten(char *s, size_t l) {
+ assert(s);
+
+ if (l < strlen(s))
+ s[l] = 0;
+
+ return s;
+}
+
+char *strreplace(const char *text, const char *old_string, const char *new_string) {
+ const char *f;
+ char *t, *r;
+ size_t l, old_len, new_len;
+
+ assert(text);
+ assert(old_string);
+ assert(new_string);
+
+ old_len = strlen(old_string);
+ new_len = strlen(new_string);
+
+ l = strlen(text);
+ r = new(char, l+1);
+ if (!r)
+ return NULL;
+
+ f = text;
+ t = r;
+ while (*f) {
+ char *a;
+ size_t d, nl;
+
+ if (!startswith(f, old_string)) {
+ *(t++) = *(f++);
+ continue;
+ }
+
+ d = t - r;
+ nl = l - old_len + new_len;
+ a = realloc(r, nl + 1);
+ if (!a)
+ goto oom;
+
+ l = nl;
+ r = a;
+ t = r + d;
+
+ t = stpcpy(t, new_string);
+ f += old_len;
+ }
+
+ *t = 0;
+ return r;
+
+oom:
+ free(r);
+ return NULL;
+}
+
+char *strip_tab_ansi(char **ibuf, size_t *_isz) {
+ const char *i, *begin = NULL;
+ enum {
+ STATE_OTHER,
+ STATE_ESCAPE,
+ STATE_BRACKET
+ } state = STATE_OTHER;
+ char *obuf = NULL;
+ size_t osz = 0, isz;
+ FILE *f;
+
+ assert(ibuf);
+ assert(*ibuf);
+
+ /* Strips ANSI color and replaces TABs by 8 spaces */
+
+ isz = _isz ? *_isz : strlen(*ibuf);
+
+ f = open_memstream(&obuf, &osz);
+ if (!f)
+ return NULL;
+
+ for (i = *ibuf; i < *ibuf + isz + 1; i++) {
+
+ switch (state) {
+
+ case STATE_OTHER:
+ if (i >= *ibuf + isz) /* EOT */
+ break;
+ else if (*i == '\x1B')
+ state = STATE_ESCAPE;
+ else if (*i == '\t')
+ fputs(" ", f);
+ else
+ fputc(*i, f);
+ break;
+
+ case STATE_ESCAPE:
+ if (i >= *ibuf + isz) { /* EOT */
+ fputc('\x1B', f);
+ break;
+ } else if (*i == '[') {
+ state = STATE_BRACKET;
+ begin = i + 1;
+ } else {
+ fputc('\x1B', f);
+ fputc(*i, f);
+ state = STATE_OTHER;
+ }
+
+ break;
+
+ case STATE_BRACKET:
+
+ if (i >= *ibuf + isz || /* EOT */
+ (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
+ fputc('\x1B', f);
+ fputc('[', f);
+ state = STATE_OTHER;
+ i = begin-1;
+ } else if (*i == 'm')
+ state = STATE_OTHER;
+ break;
+ }
+ }
+
+ if (ferror(f)) {
+ fclose(f);
+ free(obuf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ free(*ibuf);
+ *ibuf = obuf;
+
+ if (_isz)
+ *_isz = osz;
+
+ return obuf;
+}
+
+char *strextend(char **x, ...) {
+ va_list ap;
+ size_t f, l;
+ char *r, *p;
+
+ assert(x);
+
+ l = f = *x ? strlen(*x) : 0;
+
+ va_start(ap, x);
+ for (;;) {
+ const char *t;
+ size_t n;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ n = strlen(t);
+ if (n > ((size_t) -1) - l) {
+ va_end(ap);
+ return NULL;
+ }
+
+ l += n;
+ }
+ va_end(ap);
+
+ r = realloc(*x, l+1);
+ if (!r)
+ return NULL;
+
+ p = r + f;
+
+ va_start(ap, x);
+ for (;;) {
+ const char *t;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ p = stpcpy(p, t);
+ }
+ va_end(ap);
+
+ *p = 0;
+ *x = r;
+
+ return r + l;
+}
+
+char *strrep(const char *s, unsigned n) {
+ size_t l;
+ char *r, *p;
+ unsigned i;
+
+ assert(s);
+
+ l = strlen(s);
+ p = r = malloc(l * n + 1);
+ if (!r)
+ return NULL;
+
+ for (i = 0; i < n; i++)
+ p = stpcpy(p, s);
+
+ *p = 0;
+ return r;
+}
+
+int split_pair(const char *s, const char *sep, char **l, char **r) {
+ char *x, *a, *b;
+
+ assert(s);
+ assert(sep);
+ assert(l);
+ assert(r);
+
+ if (isempty(sep))
+ return -EINVAL;
+
+ x = strstr(s, sep);
+ if (!x)
+ return -EINVAL;
+
+ a = strndup(s, x - s);
+ if (!a)
+ return -ENOMEM;
+
+ b = strdup(x + strlen(sep));
+ if (!b) {
+ free(a);
+ return -ENOMEM;
+ }
+
+ *l = a;
+ *r = b;
+
+ return 0;
+}
+
+int free_and_strdup(char **p, const char *s) {
+ char *t;
+
+ assert(p);
+
+ /* Replaces a string pointer with an strdup()ed new string,
+ * possibly freeing the old one. */
+
+ if (streq_ptr(*p, s))
+ return 0;
+
+ if (s) {
+ t = strdup(s);
+ if (!t)
+ return -ENOMEM;
+ } else
+ t = NULL;
+
+ free(*p);
+ *p = t;
+
+ return 1;
+}
+
+void string_erase(char *x) {
+
+ if (!x)
+ return;
+
+ /* A delicious drop of snake-oil! To be called on memory where
+ * we stored passphrases or so, after we used them. */
+
+ memory_erase(x, strlen(x));
+}
+
+char *string_free_erase(char *s) {
+ if (!s)
+ return NULL;
+
+ string_erase(s);
+ return mfree(s);
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
new file mode 100644
index 0000000000..7b7c0e5f32
--- /dev/null
+++ b/src/basic/string-util.h
@@ -0,0 +1,170 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "macro.h"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+
+int strcmp_ptr(const char *a, const char *b) _pure_;
+
+static inline bool streq_ptr(const char *a, const char *b) {
+ return strcmp_ptr(a, b) == 0;
+}
+
+static inline const char* strempty(const char *s) {
+ return s ? s : "";
+}
+
+static inline const char* strnull(const char *s) {
+ return s ? s : "(null)";
+}
+
+static inline const char *strna(const char *s) {
+ return s ? s : "n/a";
+}
+
+static inline bool isempty(const char *p) {
+ return !p || !p[0];
+}
+
+static inline char *startswith(const char *s, const char *prefix) {
+ size_t l;
+
+ l = strlen(prefix);
+ if (strncmp(s, prefix, l) == 0)
+ return (char*) s + l;
+
+ return NULL;
+}
+
+static inline char *startswith_no_case(const char *s, const char *prefix) {
+ size_t l;
+
+ l = strlen(prefix);
+ if (strncasecmp(s, prefix, l) == 0)
+ return (char*) s + l;
+
+ return NULL;
+}
+
+char *endswith(const char *s, const char *postfix) _pure_;
+char *endswith_no_case(const char *s, const char *postfix) _pure_;
+
+char *first_word(const char *s, const char *word) _pure_;
+
+const char* split(const char **state, size_t *l, const char *separator, bool quoted);
+
+#define FOREACH_WORD(word, length, s, state) \
+ _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
+ _FOREACH_WORD(word, length, s, separator, false, state)
+
+#define FOREACH_WORD_QUOTED(word, length, s, state) \
+ _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
+
+#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
+ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+
+char *strappend(const char *s, const char *suffix);
+char *strnappend(const char *s, const char *suffix, size_t length);
+
+char *strjoin(const char *x, ...) _sentinel_;
+
+#define strjoina(a, ...) \
+ ({ \
+ const char *_appendees_[] = { a, __VA_ARGS__ }; \
+ char *_d_, *_p_; \
+ int _len_ = 0; \
+ unsigned _i_; \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _len_ += strlen(_appendees_[_i_]); \
+ _p_ = _d_ = alloca(_len_ + 1); \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _p_ = stpcpy(_p_, _appendees_[_i_]); \
+ *_p_ = 0; \
+ _d_; \
+ })
+
+char *strstrip(char *s);
+char *delete_chars(char *s, const char *bad);
+char *truncate_nl(char *s);
+
+char *ascii_strlower(char *path);
+
+bool chars_intersect(const char *a, const char *b) _pure_;
+
+static inline bool _pure_ in_charset(const char *s, const char* charset) {
+ assert(s);
+ assert(charset);
+ return s[strspn(s, charset)] == '\0';
+}
+
+bool string_has_cc(const char *p, const char *ok) _pure_;
+
+char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
+char *ellipsize(const char *s, size_t length, unsigned percent);
+
+bool nulstr_contains(const char*nulstr, const char *needle);
+
+char* strshorten(char *s, size_t l);
+
+char *strreplace(const char *text, const char *old_string, const char *new_string);
+
+char *strip_tab_ansi(char **p, size_t *l);
+
+char *strextend(char **x, ...) _sentinel_;
+
+char *strrep(const char *s, unsigned n);
+
+int split_pair(const char *s, const char *sep, char **l, char **r);
+
+int free_and_strdup(char **p, const char *s);
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+ if (needlelen <= 0)
+ return (void*) haystack;
+
+ if (haystacklen < needlelen)
+ return NULL;
+
+ assert(haystack);
+ assert(needle);
+
+ return memmem(haystack, haystacklen, needle, needlelen);
+}
+
+#define memory_erase(p, l) memset((p), 'x', (l))
+void string_erase(char *x);
+
+char *string_free_erase(char *s);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
+#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
diff --git a/src/basic/strv.c b/src/basic/strv.c
index 446d4a5631..f5df269006 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -19,12 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <errno.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include "escape.h"
+#include "string-util.h"
#include "util.h"
#include "strv.h"
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index ca7554a9fa..4723653566 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -17,26 +17,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <linux/tiocl.h>
+#include <linux/vt.h>
+#include <poll.h>
+#include <signal.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <termios.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
#include <time.h>
-#include <assert.h>
-#include <poll.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <linux/kd.h>
+#include <unistd.h>
-#include "terminal-util.h"
-#include "time-util.h"
-#include "process-util.h"
-#include "util.h"
#include "fileio.h"
#include "path-util.h"
+#include "process-util.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "util.h"
+#include "terminal-util.h"
static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0;
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index d4e0914b27..a516d2807b 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -20,13 +20,14 @@
***/
#include <string.h>
-#include <sys/timex.h>
#include <sys/timerfd.h>
+#include <sys/timex.h>
-#include "util.h"
-#include "time-util.h"
#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "util.h"
+#include "time-util.h"
usec_t now(clockid_t clock_id) {
struct timespec ts;
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index a8b6b6dace..383c4ab871 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -22,12 +22,13 @@
#include <errno.h>
#include <string.h>
-#include "path-util.h"
#include "bus-label.h"
-#include "util.h"
-#include "unit-name.h"
#include "def.h"
+#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "util.h"
+#include "unit-name.h"
#define VALID_CHARS \
DIGITS LETTERS \
diff --git a/src/basic/util.c b/src/basic/util.c
index d6488f8fd6..233a6c2e35 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -94,6 +94,7 @@
#include "random-util.h"
#include "signal-util.h"
#include "sparse-endian.h"
+#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "utf8.h"
@@ -120,101 +121,6 @@ size_t page_size(void) {
return pgsz;
}
-int strcmp_ptr(const char *a, const char *b) {
-
- /* Like strcmp(), but tries to make sense of NULL pointers */
- if (a && b)
- return strcmp(a, b);
-
- if (!a && b)
- return -1;
-
- if (a && !b)
- return 1;
-
- return 0;
-}
-
-bool streq_ptr(const char *a, const char *b) {
- return strcmp_ptr(a, b) == 0;
-}
-
-char* endswith(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (memcmp(s + sl - pl, postfix, pl) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (strcasecmp(s + sl - pl, postfix) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* first_word(const char *s, const char *word) {
- size_t sl, wl;
- const char *p;
-
- assert(s);
- assert(word);
-
- /* Checks if the string starts with the specified word, either
- * followed by NUL or by whitespace. Returns a pointer to the
- * NUL or the first character after the whitespace. */
-
- sl = strlen(s);
- wl = strlen(word);
-
- if (sl < wl)
- return NULL;
-
- if (wl == 0)
- return (char*) s;
-
- if (memcmp(s, word, wl) != 0)
- return NULL;
-
- p = s + wl;
- if (*p == 0)
- return (char*) p;
-
- if (!strchr(WHITESPACE, *p))
- return NULL;
-
- p += strspn(p, WHITESPACE);
- return (char*) p;
-}
-
int close_nointr(int fd) {
assert(fd >= 0);
@@ -553,66 +459,6 @@ int safe_atod(const char *s, double *ret_d) {
return 0;
}
-static size_t strcspn_escaped(const char *s, const char *reject) {
- bool escaped = false;
- int n;
-
- for (n=0; s[n]; n++) {
- if (escaped)
- escaped = false;
- else if (s[n] == '\\')
- escaped = true;
- else if (strchr(reject, s[n]))
- break;
- }
-
- /* if s ends in \, return index of previous char */
- return n - escaped;
-}
-
-/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
- const char *current;
-
- current = *state;
-
- if (!*current) {
- assert(**state == '\0');
- return NULL;
- }
-
- current += strspn(current, separator);
- if (!*current) {
- *state = current;
- return NULL;
- }
-
- if (quoted && strchr("\'\"", *current)) {
- char quotechars[2] = {*current, '\0'};
-
- *l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
- (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
- /* right quote missing or garbage at the end */
- *state = current;
- return NULL;
- }
- *state = current++ + *l + 2;
- } else if (quoted) {
- *l = strcspn_escaped(current, separator);
- if (current[*l] && !strchr(separator, current[*l])) {
- /* unfinished escape */
- *state = current;
- return NULL;
- }
- *state = current + *l;
- } else {
- *l = strcspn(current, separator);
- *state = current + *l;
- }
-
- return current;
-}
int fchmod_umask(int fd, mode_t m) {
mode_t u;
@@ -625,48 +471,6 @@ int fchmod_umask(int fd, mode_t m) {
return r;
}
-char *truncate_nl(char *s) {
- assert(s);
-
- s[strcspn(s, NEWLINE)] = 0;
- return s;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
- size_t a;
- char *r;
-
- if (!s && !suffix)
- return strdup("");
-
- if (!s)
- return strndup(suffix, b);
-
- if (!suffix)
- return strdup(s);
-
- assert(s);
- assert(suffix);
-
- a = strlen(s);
- if (b > ((size_t) -1) - a)
- return NULL;
-
- r = new(char, a+b+1);
- if (!r)
- return NULL;
-
- memcpy(r, s, a);
- memcpy(r+a, suffix, b);
- r[a+b] = 0;
-
- return r;
-}
-
-char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
-}
-
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = 100;
int r;
@@ -769,40 +573,6 @@ int readlink_and_canonicalize(const char *p, char **r) {
return 0;
}
-char *strstrip(char *s) {
- char *e;
-
- /* Drops trailing whitespace. Modifies the string in
- * place. Returns pointer to first non-space character */
-
- s += strspn(s, WHITESPACE);
-
- for (e = strchr(s, 0); e > s; e --)
- if (!strchr(WHITESPACE, e[-1]))
- break;
-
- *e = 0;
-
- return s;
-}
-
-char *delete_chars(char *s, const char *bad) {
- char *f, *t;
-
- /* Drops all whitespace, regardless where in the string */
-
- for (f = s, t = s; *f; f++) {
- if (strchr(bad, *f))
- continue;
-
- *(t++) = *f;
- }
-
- *t = 0;
-
- return s;
-}
-
char *file_in_same_dir(const char *path, const char *filename) {
char *e, *ret;
size_t k;
@@ -1504,18 +1274,6 @@ int undecchar(char c) {
return -EINVAL;
}
-char *ascii_strlower(char *t) {
- char *p;
-
- assert(t);
-
- for (p = t; *p; p++)
- if (*p >= 'A' && *p <= 'Z')
- *p = *p - 'A' + 'a';
-
- return t;
-}
-
_pure_ static bool hidden_file_allow_backup(const char *filename) {
assert(filename);
@@ -1663,17 +1421,6 @@ int close_all_fds(const int except[], unsigned n_except) {
return r;
}
-bool chars_intersect(const char *a, const char *b) {
- const char *p;
-
- /* Returns true if any of the chars in a are in b. */
- for (p = a; *p; p++)
- if (strchr(b, *p))
- return true;
-
- return false;
-}
-
bool fstype_is_network(const char *fstype) {
static const char table[] =
"afs\0"
@@ -2196,115 +1943,6 @@ int running_in_chroot(void) {
return ret == 0;
}
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *r;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- r = new0(char, new_length+1);
- if (!r)
- return NULL;
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- memcpy(r, s, x);
- r[x] = '.';
- r[x+1] = '.';
- r[x+2] = '.';
- memcpy(r + x + 3,
- s + old_length - (new_length - x - 3),
- new_length - x - 3);
-
- return r;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *e;
- const char *i, *j;
- unsigned k, len, len2;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- /* if no multibyte characters use ascii_ellipsize_mem for speed */
- if (ascii_is_valid(s))
- return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- k = 0;
- for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
- int c;
-
- c = utf8_encoded_to_unichar(i);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
-
- if (k > x) /* last character was wide and went over quota */
- x ++;
-
- for (j = s + old_length; k < new_length && j > i; ) {
- int c;
-
- j = utf8_prev_char(j);
- c = utf8_encoded_to_unichar(j);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
- assert(i <= j);
-
- /* we don't actually need to ellipsize */
- if (i == j)
- return memdup(s, old_length + 1);
-
- /* make space for ellipsis */
- j = utf8_next_char(j);
-
- len = i - s;
- len2 = s + old_length - j;
- e = new(char, len + 3 + len2 + 1);
- if (!e)
- return NULL;
-
- /*
- printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
- old_length, new_length, x, len, len2, k);
- */
-
- memcpy(e, s, len);
- e[len] = 0xe2; /* tri-dot ellipsis: … */
- e[len + 1] = 0x80;
- e[len + 2] = 0xa6;
-
- memcpy(e + len + 3, j, len2 + 1);
-
- return e;
-}
-
-char *ellipsize(const char *s, size_t length, unsigned percent) {
- return ellipsize_mem(s, strlen(s), length, percent);
-}
-
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
_cleanup_close_ int fd;
int r;
@@ -2637,32 +2275,10 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
wait_for_terminate_and_warn(name, executor_pid, true);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
- const char *i;
-
- if (!nulstr)
- return false;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return true;
-
- return false;
-}
-
bool plymouth_running(void) {
return access("/run/plymouth/pid", F_OK) >= 0;
}
-char* strshorten(char *s, size_t l) {
- assert(s);
-
- if (l < strlen(s))
- s[l] = 0;
-
- return s;
-}
-
int pipe_eof(int fd) {
struct pollfd pollfd = {
.fd = fd,
@@ -3150,63 +2766,6 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
-char *strjoin(const char *x, ...) {
- va_list ap;
- size_t l;
- char *r, *p;
-
- va_start(ap, x);
-
- if (x) {
- l = strlen(x);
-
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- } else
- l = 0;
-
- va_end(ap);
-
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- if (x) {
- p = stpcpy(r, x);
-
- va_start(ap, x);
-
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
-
- va_end(ap);
- } else
- r[0] = 0;
-
- return r;
-}
-
bool is_main_thread(void) {
static thread_local int cached = 0;
@@ -3832,29 +3391,6 @@ bool string_is_safe(const char *p) {
return true;
}
-/**
- * Check if a string contains control characters. If 'ok' is non-NULL
- * it may be a string containing additional CCs to be considered OK.
- */
-bool string_has_cc(const char *p, const char *ok) {
- const char *t;
-
- assert(p);
-
- for (t = p; *t; t++) {
- if (ok && strchr(ok, *t))
- continue;
-
- if (*t > 0 && *t < ' ')
- return true;
-
- if (*t == 127)
- return true;
- }
-
- return false;
-}
-
bool path_is_safe(const char *p) {
if (isempty(p))
@@ -3976,139 +3512,6 @@ const char *draw_special_char(DrawSpecialChar ch) {
return draw_table[!is_locale_utf8()][ch];
}
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
- const char *f;
- char *t, *r;
- size_t l, old_len, new_len;
-
- assert(text);
- assert(old_string);
- assert(new_string);
-
- old_len = strlen(old_string);
- new_len = strlen(new_string);
-
- l = strlen(text);
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- f = text;
- t = r;
- while (*f) {
- char *a;
- size_t d, nl;
-
- if (!startswith(f, old_string)) {
- *(t++) = *(f++);
- continue;
- }
-
- d = t - r;
- nl = l - old_len + new_len;
- a = realloc(r, nl + 1);
- if (!a)
- goto oom;
-
- l = nl;
- r = a;
- t = r + d;
-
- t = stpcpy(t, new_string);
- f += old_len;
- }
-
- *t = 0;
- return r;
-
-oom:
- free(r);
- return NULL;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
- const char *i, *begin = NULL;
- enum {
- STATE_OTHER,
- STATE_ESCAPE,
- STATE_BRACKET
- } state = STATE_OTHER;
- char *obuf = NULL;
- size_t osz = 0, isz;
- FILE *f;
-
- assert(ibuf);
- assert(*ibuf);
-
- /* Strips ANSI color and replaces TABs by 8 spaces */
-
- isz = _isz ? *_isz : strlen(*ibuf);
-
- f = open_memstream(&obuf, &osz);
- if (!f)
- return NULL;
-
- for (i = *ibuf; i < *ibuf + isz + 1; i++) {
-
- switch (state) {
-
- case STATE_OTHER:
- if (i >= *ibuf + isz) /* EOT */
- break;
- else if (*i == '\x1B')
- state = STATE_ESCAPE;
- else if (*i == '\t')
- fputs(" ", f);
- else
- fputc(*i, f);
- break;
-
- case STATE_ESCAPE:
- if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
- break;
- } else if (*i == '[') {
- state = STATE_BRACKET;
- begin = i + 1;
- } else {
- fputc('\x1B', f);
- fputc(*i, f);
- state = STATE_OTHER;
- }
-
- break;
-
- case STATE_BRACKET:
-
- if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
- state = STATE_OTHER;
- i = begin-1;
- } else if (*i == 'm')
- state = STATE_OTHER;
- break;
- }
- }
-
- if (ferror(f)) {
- fclose(f);
- free(obuf);
- return NULL;
- }
-
- fclose(f);
-
- free(*ibuf);
- *ibuf = obuf;
-
- if (_isz)
- *_isz = osz;
-
- return obuf;
-}
-
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
@@ -4267,77 +3670,6 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
return search_and_fopen_internal(path, mode, root, s, _f);
}
-char *strextend(char **x, ...) {
- va_list ap;
- size_t f, l;
- char *r, *p;
-
- assert(x);
-
- l = f = *x ? strlen(*x) : 0;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- va_end(ap);
-
- r = realloc(*x, l+1);
- if (!r)
- return NULL;
-
- p = r + f;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
- va_end(ap);
-
- *p = 0;
- *x = r;
-
- return r + l;
-}
-
-char *strrep(const char *s, unsigned n) {
- size_t l;
- char *r, *p;
- unsigned i;
-
- assert(s);
-
- l = strlen(s);
- p = r = malloc(l * n + 1);
- if (!r)
- return NULL;
-
- for (i = 0; i < n; i++)
- p = stpcpy(p, s);
-
- *p = 0;
- return r;
-}
-
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
size_t a, newalloc;
void *q;
@@ -4424,37 +3756,6 @@ bool id128_is_valid(const char *s) {
return true;
}
-int split_pair(const char *s, const char *sep, char **l, char **r) {
- char *x, *a, *b;
-
- assert(s);
- assert(sep);
- assert(l);
- assert(r);
-
- if (isempty(sep))
- return -EINVAL;
-
- x = strstr(s, sep);
- if (!x)
- return -EINVAL;
-
- a = strndup(s, x - s);
- if (!a)
- return -ENOMEM;
-
- b = strdup(x + strlen(sep));
- if (!b) {
- free(a);
- return -ENOMEM;
- }
-
- *l = a;
- *r = b;
-
- return 0;
-}
-
int shall_restore_state(void) {
_cleanup_free_ char *value = NULL;
int r;
@@ -5407,30 +4708,6 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
-int free_and_strdup(char **p, const char *s) {
- char *t;
-
- assert(p);
-
- /* Replaces a string pointer with an strdup()ed new string,
- * possibly freeing the old one. */
-
- if (streq_ptr(*p, s))
- return 0;
-
- if (s) {
- t = strdup(s);
- if (!t)
- return -ENOMEM;
- } else
- t = NULL;
-
- free(*p);
- *p = t;
-
- return 1;
-}
-
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
@@ -6080,22 +5357,3 @@ bool fdname_is_valid(const char *s) {
bool oom_score_adjust_is_valid(int oa) {
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
}
-
-void string_erase(char *x) {
-
- if (!x)
- return;
-
- /* A delicious drop of snake-oil! To be called on memory where
- * we stored passphrases or so, after we used them. */
-
- memory_erase(x, strlen(x));
-}
-
-char *string_free_erase(char *s) {
- if (!s)
- return NULL;
-
- string_erase(s);
- return mfree(s);
-}
diff --git a/src/basic/util.h b/src/basic/util.h
index 6674111145..7d1e4e0f62 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -58,14 +58,6 @@
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
-#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
-#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
-
-bool streq_ptr(const char *a, const char *b) _pure_;
-int strcmp_ptr(const char *a, const char *b) _pure_;
-
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
#define new0(t, n) ((t*) calloc((n), sizeof(t)))
@@ -95,47 +87,6 @@ static inline const char* one_zero(bool b) {
return b ? "1" : "0";
}
-static inline const char* strempty(const char *s) {
- return s ? s : "";
-}
-
-static inline const char* strnull(const char *s) {
- return s ? s : "(null)";
-}
-
-static inline const char *strna(const char *s) {
- return s ? s : "n/a";
-}
-
-static inline bool isempty(const char *p) {
- return !p || !p[0];
-}
-
-static inline char *startswith(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-static inline char *startswith_no_case(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncasecmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-char *endswith(const char *s, const char *postfix) _pure_;
-char *endswith_no_case(const char *s, const char *postfix) _pure_;
-
-char *first_word(const char *s, const char *word) _pure_;
-
int close_nointr(int fd);
int safe_close(int fd);
void safe_close_pair(int p[]);
@@ -212,33 +163,12 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
int safe_atou16(const char *s, uint16_t *ret);
int safe_atoi16(const char *s, int16_t *ret);
-const char* split(const char **state, size_t *l, const char *separator, bool quoted);
-
-#define FOREACH_WORD(word, length, s, state) \
- _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
-
-#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
- _FOREACH_WORD(word, length, s, separator, false, state)
-
-#define FOREACH_WORD_QUOTED(word, length, s, state) \
- _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
-
-#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
- for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
-
-char *strappend(const char *s, const char *suffix);
-char *strnappend(const char *s, const char *suffix, size_t length);
-
int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *truncate_nl(char *s);
-
char *file_in_same_dir(const char *path, const char *filename);
int rmdir_parents(const char *path, const char *stop);
@@ -254,15 +184,11 @@ int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
-char *ascii_strlower(char *path);
-
bool dirent_is_file(const struct dirent *de) _pure_;
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
bool hidden_file(const char *filename) _pure_;
-bool chars_intersect(const char *a, const char *b) _pure_;
-
/* For basic lookup tables with strictly enumerated entries */
#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
@@ -373,10 +299,6 @@ int files_same(const char *filea, const char *fileb);
int running_in_chroot(void);
-char *ellipsize(const char *s, size_t length, unsigned percent);
- /* bytes columns */
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);
-
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
@@ -392,12 +314,8 @@ char *fstab_node_to_udev_node(const char *p);
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
-bool nulstr_contains(const char*nulstr, const char *needle);
-
bool plymouth_running(void);
-char* strshorten(char *s, size_t l);
-
int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
@@ -425,16 +343,8 @@ int dirent_ensure_type(DIR *d, struct dirent *de);
int get_files_in_directory(const char *path, char ***list);
-char *strjoin(const char *x, ...) _sentinel_;
-
bool is_main_thread(void);
-static inline bool _pure_ in_charset(const char *s, const char* charset) {
- assert(s);
- assert(charset);
- return s[strspn(s, charset)] == '\0';
-}
-
int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH(i, l) \
@@ -554,7 +464,6 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_
bool filename_is_valid(const char *p) _pure_;
bool path_is_safe(const char *p) _pure_;
bool string_is_safe(const char *p) _pure_;
-bool string_has_cc(const char *p, const char *ok) _pure_;
/**
* Check if a string contains any glob patterns.
@@ -586,10 +495,6 @@ typedef enum DrawSpecialChar {
const char *draw_special_char(DrawSpecialChar ch);
-char *strreplace(const char *text, const char *old_string, const char *new_string);
-
-char *strip_tab_ansi(char **p, size_t *l);
-
int on_ac_power(void);
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
@@ -638,9 +543,6 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *le
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
-char *strextend(char **x, ...) _sentinel_;
-char *strrep(const char *s, unsigned n);
-
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
#define GREEDY_REALLOC(array, allocated, need) \
@@ -755,25 +657,8 @@ int unlink_noerrno(const char *path);
(void*)memset(_new_, 0, _size_); \
})
-#define strjoina(a, ...) \
- ({ \
- const char *_appendees_[] = { a, __VA_ARGS__ }; \
- char *_d_, *_p_; \
- int _len_ = 0; \
- unsigned _i_; \
- for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
- _len_ += strlen(_appendees_[_i_]); \
- _p_ = _d_ = alloca(_len_ + 1); \
- for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
- _p_ = stpcpy(_p_, _appendees_[_i_]); \
- *_p_ = 0; \
- _d_; \
- })
-
bool id128_is_valid(const char *s) _pure_;
-int split_pair(const char *s, const char *sep, char **l, char **r);
-
int shall_restore_state(void);
/**
@@ -788,21 +673,6 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
qsort(base, nmemb, size, compar);
}
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
- if (needlelen <= 0)
- return (void*) haystack;
-
- if (haystacklen < needlelen)
- return NULL;
-
- assert(haystack);
- assert(needle);
-
- return memmem(haystack, haystacklen, needle, needlelen);
-}
-
int proc_cmdline(char **ret);
int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
int get_proc_cmdline_key(const char *parameter, char **value);
@@ -860,8 +730,6 @@ int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
int is_device_node(const char *path);
-int free_and_strdup(char **p, const char *s);
-
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
@@ -923,10 +791,3 @@ int version(void);
bool fdname_is_valid(const char *s);
bool oom_score_adjust_is_valid(int oa);
-
-#define memory_erase(p, l) memset((p), 'x', (l))
-void string_erase(char *x);
-
-char *string_free_erase(char *s);
-DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
-#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
diff --git a/src/basic/verbs.c b/src/basic/verbs.c
index c7beccc2dc..d63062d39e 100644
--- a/src/basic/verbs.c
+++ b/src/basic/verbs.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
#include "util.h"
#include "verbs.h"
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 70543177b6..9267a2730b 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -19,14 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
+#include <string.h>
#include <unistd.h>
-#include "util.h"
+#include "fileio.h"
#include "process-util.h"
+#include "string-util.h"
+#include "util.h"
#include "virt.h"
-#include "fileio.h"
static int detect_vm_cpuid(void) {
diff --git a/src/basic/xml.c b/src/basic/xml.c
index 15c629b188..8126bce212 100644
--- a/src/basic/xml.c
+++ b/src/basic/xml.c
@@ -21,6 +21,7 @@
#include <string.h>
+#include "string-util.h"
#include "util.h"
#include "xml.h"