udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / basic / nulstr-util.c
blob06fa219bd197552c8be61b07e3e9e789f016ce15
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "nulstr-util.h"
4 #include "string-util.h"
5 #include "strv.h"
7 char** strv_parse_nulstr_full(const char *s, size_t l, bool drop_trailing_nuls) {
8 /* l is the length of the input data, which will be split at NULs into elements of the resulting
9 * strv. Hence, the number of items in the resulting strv will be equal to one plus the number of NUL
10 * bytes in the l bytes starting at s, unless s[l-1] is NUL, in which case the final empty string is
11 * not stored in the resulting strv, and length is equal to the number of NUL bytes.
13 * Note that contrary to a normal nulstr which cannot contain empty strings, because the input data
14 * is terminated by any two consequent NUL bytes, this parser accepts empty strings in s. */
16 _cleanup_strv_free_ char **v = NULL;
17 size_t c = 0, i = 0;
19 assert(s || l <= 0);
21 if (drop_trailing_nuls)
22 while (l > 0 && s[l-1] == '\0')
23 l--;
25 if (l <= 0)
26 return new0(char*, 1);
28 for (const char *p = s; p < s + l; p++)
29 if (*p == 0)
30 c++;
32 if (s[l-1] != 0)
33 c++;
35 v = new0(char*, c+1);
36 if (!v)
37 return NULL;
39 for (const char *p = s; p < s + l; ) {
40 const char *e;
42 e = memchr(p, 0, s + l - p);
44 v[i] = memdup_suffix0(p, e ? e - p : s + l - p);
45 if (!v[i])
46 return NULL;
48 i++;
50 if (!e)
51 break;
53 p = e + 1;
56 assert(i == c);
58 return TAKE_PTR(v);
61 char** strv_split_nulstr(const char *s) {
62 _cleanup_strv_free_ char **l = NULL;
64 /* This parses a nulstr, without specification of size, and stops at an empty string. This cannot
65 * parse nulstrs with embedded empty strings hence, as an empty string is an end marker. Use
66 * strv_parse_nulstr() above to parse a nulstr with embedded empty strings (which however requires a
67 * size to be specified) */
69 NULSTR_FOREACH(i, s)
70 if (strv_extend(&l, i) < 0)
71 return NULL;
73 return l ? TAKE_PTR(l) : strv_new(NULL);
76 int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
77 /* Builds a nulstr and returns it together with the size. An extra NUL byte will be appended (⚠️ but
78 * not included in the size! ⚠️). This is done so that the nulstr can be used both in
79 * strv_parse_nulstr() and in NULSTR_FOREACH()/strv_split_nulstr() contexts, i.e. with and without a
80 * size parameter. In the former case we can include empty strings, in the latter case we cannot (as
81 * that is the end marker).
83 * When NULSTR_FOREACH()/strv_split_nulstr() is used it is often assumed that the nulstr ends in two
84 * NUL bytes (which it will, if not empty). To ensure that this assumption *always* holds, we'll
85 * return a buffer with two NUL bytes in that case, but return a size of zero. */
87 _cleanup_free_ char *m = NULL;
88 size_t n = 0;
90 assert(ret);
92 STRV_FOREACH(i, l) {
93 size_t z;
95 z = strlen(*i);
97 if (!GREEDY_REALLOC(m, n + z + 2))
98 return -ENOMEM;
100 memcpy(m + n, *i, z + 1);
101 n += z + 1;
104 if (!m) {
105 /* return a buffer with an extra NUL, so that the assumption that we always have two trailing NULs holds */
106 m = new0(char, 2);
107 if (!m)
108 return -ENOMEM;
110 n = 0;
111 } else
112 /* Make sure there is a second extra NUL at the end of resulting nulstr (not counted in return size) */
113 m[n] = '\0';
115 *ret = TAKE_PTR(m);
116 if (ret_size)
117 *ret_size = n;
119 return 0;
122 int set_make_nulstr(Set *s, char **ret, size_t *ret_size) {
123 /* Use _cleanup_free_ instead of _cleanup_strv_free_ because we need to clean the strv only, not
124 * the strings owned by the set. */
125 _cleanup_free_ char **strv = NULL;
127 assert(ret);
129 strv = set_get_strv(s);
130 if (!strv)
131 return -ENOMEM;
133 return strv_make_nulstr(strv, ret, ret_size);
136 const char* nulstr_get(const char *nulstr, const char *needle) {
137 if (!nulstr)
138 return NULL;
140 NULSTR_FOREACH(i, nulstr)
141 if (streq(i, needle))
142 return i;
144 return NULL;