#include "hashmap.h"
#include "log.h"
#include "macro.h"
+#include "nulstr-util.h"
#include "path-util.h"
#include "set.h"
#include "sort-util.h"
#include "log.h"
#include "macro.h"
#include "mkdir.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "socket-util.h"
#include "nulstr-util.h"
#include "string-util.h"
+#include "strv.h"
+
+char** strv_parse_nulstr(const char *s, size_t l) {
+ /* l is the length of the input data, which will be split at NULs into
+ * elements of the resulting strv. Hence, the number of items in the resulting strv
+ * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
+ * unless s[l-1] is NUL, in which case the final empty string is not stored in
+ * the resulting strv, and length is equal to the number of NUL bytes.
+ *
+ * Note that contrary to a normal nulstr which cannot contain empty strings, because
+ * the input data is terminated by any two consequent NUL bytes, this parser accepts
+ * empty strings in s.
+ */
+
+ size_t c = 0, i = 0;
+ char **v;
+
+ assert(s || l <= 0);
+
+ if (l <= 0)
+ return new0(char*, 1);
+
+ for (const char *p = s; p < s + l; p++)
+ if (*p == 0)
+ c++;
+
+ if (s[l-1] != 0)
+ c++;
+
+ v = new0(char*, c+1);
+ if (!v)
+ return NULL;
+
+ for (const char *p = s; p < s + l; ) {
+ const char *e;
+
+ e = memchr(p, 0, s + l - p);
+
+ v[i] = strndup(p, e ? e - p : s + l - p);
+ if (!v[i]) {
+ strv_free(v);
+ return NULL;
+ }
+
+ i++;
+
+ if (!e)
+ break;
+
+ p = e + 1;
+ }
+
+ assert(i == c);
+
+ return v;
+}
+
+char** strv_split_nulstr(const char *s) {
+ char **r = NULL;
+
+ NULSTR_FOREACH(i, s)
+ if (strv_extend(&r, i) < 0) {
+ strv_free(r);
+ return NULL;
+ }
+
+ if (!r)
+ return strv_new(NULL);
+
+ return r;
+}
+
+int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
+ /* A valid nulstr with two NULs at the end will be created, but
+ * q will be the length without the two trailing NULs. Thus the output
+ * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
+ * and can also be parsed by strv_parse_nulstr as long as the length
+ * is provided separately.
+ */
+
+ _cleanup_free_ char *m = NULL;
+ size_t n = 0;
+
+ assert(ret);
+ assert(ret_size);
+
+ STRV_FOREACH(i, l) {
+ size_t z;
+
+ z = strlen(*i);
+
+ if (!GREEDY_REALLOC(m, n + z + 2))
+ return -ENOMEM;
+
+ memcpy(m + n, *i, z + 1);
+ n += z + 1;
+ }
+
+ if (!m) {
+ m = new0(char, 2);
+ if (!m)
+ return -ENOMEM;
+ n = 1;
+ } else
+ /* make sure there is a second extra NUL at the end of resulting nulstr */
+ m[n] = '\0';
+
+ assert(n > 0);
+ *ret = TAKE_PTR(m);
+ *ret_size = n - 1;
+
+ return 0;
+}
const char* nulstr_get(const char *nulstr, const char *needle) {
if (!nulstr)
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <errno.h>
#include <stdbool.h>
#include <string.h>
static inline bool nulstr_contains(const char *nulstr, const char *needle) {
return nulstr_get(nulstr, needle);
}
+
+char** strv_parse_nulstr(const char *s, size_t l);
+char** strv_split_nulstr(const char *s);
+int strv_make_nulstr(char * const *l, char **p, size_t *n);
+
+static inline int strv_from_nulstr(char ***a, const char *nulstr) {
+ char **t;
+
+ t = strv_split_nulstr(nulstr);
+ if (!t)
+ return -ENOMEM;
+ *a = t;
+ return 0;
+}
#include "missing_sched.h"
#include "missing_syscall.h"
#include "namespace-util.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
return l;
}
-char** strv_parse_nulstr(const char *s, size_t l) {
- /* l is the length of the input data, which will be split at NULs into
- * elements of the resulting strv. Hence, the number of items in the resulting strv
- * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
- * unless s[l-1] is NUL, in which case the final empty string is not stored in
- * the resulting strv, and length is equal to the number of NUL bytes.
- *
- * Note that contrary to a normal nulstr which cannot contain empty strings, because
- * the input data is terminated by any two consequent NUL bytes, this parser accepts
- * empty strings in s.
- */
-
- size_t c = 0, i = 0;
- char **v;
-
- assert(s || l <= 0);
-
- if (l <= 0)
- return new0(char*, 1);
-
- for (const char *p = s; p < s + l; p++)
- if (*p == 0)
- c++;
-
- if (s[l-1] != 0)
- c++;
-
- v = new0(char*, c+1);
- if (!v)
- return NULL;
-
- for (const char *p = s; p < s + l; ) {
- const char *e;
-
- e = memchr(p, 0, s + l - p);
-
- v[i] = strndup(p, e ? e - p : s + l - p);
- if (!v[i]) {
- strv_free(v);
- return NULL;
- }
-
- i++;
-
- if (!e)
- break;
-
- p = e + 1;
- }
-
- assert(i == c);
-
- return v;
-}
-
-char** strv_split_nulstr(const char *s) {
- char **r = NULL;
-
- NULSTR_FOREACH(i, s)
- if (strv_extend(&r, i) < 0) {
- strv_free(r);
- return NULL;
- }
-
- if (!r)
- return strv_new(NULL);
-
- return r;
-}
-
-int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
- /* A valid nulstr with two NULs at the end will be created, but
- * q will be the length without the two trailing NULs. Thus the output
- * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
- * and can also be parsed by strv_parse_nulstr as long as the length
- * is provided separately.
- */
-
- _cleanup_free_ char *m = NULL;
- size_t n = 0;
-
- assert(ret);
- assert(ret_size);
-
- STRV_FOREACH(i, l) {
- size_t z;
-
- z = strlen(*i);
-
- if (!GREEDY_REALLOC(m, n + z + 2))
- return -ENOMEM;
-
- memcpy(m + n, *i, z + 1);
- n += z + 1;
- }
-
- if (!m) {
- m = new0(char, 2);
- if (!m)
- return -ENOMEM;
- n = 1;
- } else
- /* make sure there is a second extra NUL at the end of resulting nulstr */
- m[n] = '\0';
-
- assert(n > 0);
- *ret = TAKE_PTR(m);
- *ret_size = n - 1;
-
- return 0;
-}
-
bool strv_overlap(char * const *a, char * const *b) {
STRV_FOREACH(i, a)
if (strv_contains(b, *i))
return strv_join_full(l, separator, NULL, false);
}
-char** strv_parse_nulstr(const char *s, size_t l);
-char** strv_split_nulstr(const char *s);
-int strv_make_nulstr(char * const *l, char **p, size_t *n);
-
-static inline int strv_from_nulstr(char ***a, const char *nulstr) {
- char **t;
-
- t = strv_split_nulstr(nulstr);
- if (!t)
- return -ENOMEM;
- *a = t;
- return 0;
-}
-
bool strv_overlap(char * const *a, char * const *b) _pure_;
#define _STRV_FOREACH_BACKWARDS(s, l, h, i) \
#include "fileio.h"
#include "format-util.h"
#include "hexdecoct.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "process-util.h"
#include "string-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "nulstr-util.h"
#include "path-lookup.h"
#include "path-util.h"
#include "string-util.h"
#include "memory-util.h"
#include "missing_syscall.h"
#include "mkdir-label.h"
+#include "nulstr-util.h"
#include "process-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "fs-util.h"
#include "glob-util.h"
#include "hostname-util.h"
-#include "initrd-util.h"
#include "ima-util.h"
+#include "initrd-util.h"
#include "limits-util.h"
#include "list.h"
#include "macro.h"
#include "mountpoint-util.h"
+#include "nulstr-util.h"
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "fuzz.h"
+#include "nulstr-util.h"
#include "selinux-util.h"
#include "static-destruct.h"
#include "stdio-util.h"
[files('test-strv.c')],
+ [files('test-nulstr-util.c')],
+
[files('test-path-util.c')],
[files('test-rm-rf.c')],
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "nulstr-util.h"
+#include "strv.h"
+#include "tests.h"
+
+TEST(strv_split_nulstr) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char nulstr[] = "str0\0str1\0str2\0str3\0";
+
+ l = strv_split_nulstr(nulstr);
+ assert_se(l);
+
+ assert_se(streq(l[0], "str0"));
+ assert_se(streq(l[1], "str1"));
+ assert_se(streq(l[2], "str2"));
+ assert_se(streq(l[3], "str3"));
+}
+
+TEST(strv_parse_nulstr) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
+
+ l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+ assert_se(l);
+ puts("Parse nulstr:");
+ strv_print(l);
+
+ assert_se(streq(l[0], "hoge"));
+ assert_se(streq(l[1], "hoge2"));
+ assert_se(streq(l[2], "hoge3"));
+ assert_se(streq(l[3], ""));
+ assert_se(streq(l[4], "hoge5"));
+ assert_se(streq(l[5], ""));
+ assert_se(streq(l[6], "xxx"));
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
#include <stdlib.h>
+#include "nulstr-util.h"
#include "strbuf.h"
#include "string-util.h"
#include "strv.h"
#include "alloc-util.h"
#include "escape.h"
-#include "nulstr-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
assert_se(strv_equal(l, (char**) input_table_retain_escape));
}
-TEST(strv_split_nulstr) {
- _cleanup_strv_free_ char **l = NULL;
- const char nulstr[] = "str0\0str1\0str2\0str3\0";
-
- l = strv_split_nulstr (nulstr);
- assert_se(l);
-
- assert_se(streq(l[0], "str0"));
- assert_se(streq(l[1], "str1"));
- assert_se(streq(l[2], "str2"));
- assert_se(streq(l[3], "str3"));
-}
-
-TEST(strv_parse_nulstr) {
- _cleanup_strv_free_ char **l = NULL;
- const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
-
- l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
- assert_se(l);
- puts("Parse nulstr:");
- strv_print(l);
-
- assert_se(streq(l[0], "hoge"));
- assert_se(streq(l[1], "hoge2"));
- assert_se(streq(l[2], "hoge3"));
- assert_se(streq(l[3], ""));
- assert_se(streq(l[4], "hoge5"));
- assert_se(streq(l[5], ""));
- assert_se(streq(l[6], "xxx"));
-}
-
TEST(strv_overlap) {
const char * const input_table[] = {
"one",
assert_se(v[1] == NULL);
}
-static void test_strv_make_nulstr_one(char **l) {
- _cleanup_free_ char *b = NULL, *c = NULL;
- _cleanup_strv_free_ char **q = NULL;
- size_t n, m;
- unsigned i = 0;
-
- log_info("/* %s */", __func__);
-
- assert_se(strv_make_nulstr(l, &b, &n) >= 0);
- assert_se(q = strv_parse_nulstr(b, n));
- assert_se(strv_equal(l, q));
-
- assert_se(strv_make_nulstr(q, &c, &m) >= 0);
- assert_se(m == n);
- assert_se(memcmp(b, c, m) == 0);
-
- NULSTR_FOREACH(s, b)
- assert_se(streq(s, l[i++]));
- assert_se(i == strv_length(l));
-}
-
-TEST(strv_make_nulstr) {
- test_strv_make_nulstr_one(NULL);
- test_strv_make_nulstr_one(STRV_MAKE(NULL));
- test_strv_make_nulstr_one(STRV_MAKE("foo"));
- test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
- test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
-}
-
TEST(foreach_string) {
const char * const t[] = {
"foo",
#include "mkdir-label.h"
#include "mount-util.h"
#include "mountpoint-util.h"
+#include "nulstr-util.h"
#include "offline-passwd.h"
#include "pager.h"
#include "parse-argument.h"