]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/string-util.h
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / basic / string-util.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 #include <alloca.h>
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <string.h>
8
9 #include "alloc-util.h"
10 #include "macro.h"
11
12 /* What is interpreted as whitespace? */
13 #define WHITESPACE " \t\n\r"
14 #define NEWLINE "\n\r"
15 #define QUOTES "\"\'"
16 #define COMMENTS "#;"
17 #define GLOB_CHARS "*?["
18 #define DIGITS "0123456789"
19 #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
20 #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21 #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
22 #define ALPHANUMERICAL LETTERS DIGITS
23 #define HEXDIGITS DIGITS "abcdefABCDEF"
24
25 #define streq(a,b) (strcmp((a),(b)) == 0)
26 #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
27 #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
28 #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
29
30 int strcmp_ptr(const char *a, const char *b) _pure_;
31
32 static inline bool streq_ptr(const char *a, const char *b) {
33 return strcmp_ptr(a, b) == 0;
34 }
35
36 static inline const char* strempty(const char *s) {
37 return s ?: "";
38 }
39
40 static inline const char* strnull(const char *s) {
41 return s ?: "(null)";
42 }
43
44 static inline const char *strna(const char *s) {
45 return s ?: "n/a";
46 }
47
48 static inline bool isempty(const char *p) {
49 return !p || !p[0];
50 }
51
52 static inline const char *empty_to_null(const char *p) {
53 return isempty(p) ? NULL : p;
54 }
55
56 static inline const char *empty_to_dash(const char *str) {
57 return isempty(str) ? "-" : str;
58 }
59
60 static inline char *startswith(const char *s, const char *prefix) {
61 size_t l;
62
63 l = strlen(prefix);
64 if (strncmp(s, prefix, l) == 0)
65 return (char*) s + l;
66
67 return NULL;
68 }
69
70 static inline char *startswith_no_case(const char *s, const char *prefix) {
71 size_t l;
72
73 l = strlen(prefix);
74 if (strncasecmp(s, prefix, l) == 0)
75 return (char*) s + l;
76
77 return NULL;
78 }
79
80 char *endswith(const char *s, const char *postfix) _pure_;
81 char *endswith_no_case(const char *s, const char *postfix) _pure_;
82
83 char *first_word(const char *s, const char *word) _pure_;
84
85 typedef enum SplitFlags {
86 SPLIT_QUOTES = 0x01 << 0,
87 SPLIT_RELAX = 0x01 << 1,
88 } SplitFlags;
89
90 const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags);
91
92 #define FOREACH_WORD(word, length, s, state) \
93 _FOREACH_WORD(word, length, s, WHITESPACE, 0, state)
94
95 #define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
96 _FOREACH_WORD(word, length, s, separator, 0, state)
97
98 #define _FOREACH_WORD(word, length, s, separator, flags, state) \
99 for ((state) = (s), (word) = split(&(state), &(length), (separator), (flags)); (word); (word) = split(&(state), &(length), (separator), (flags)))
100
101 char *strappend(const char *s, const char *suffix);
102 char *strnappend(const char *s, const char *suffix, size_t length);
103
104 char *strjoin_real(const char *x, ...) _sentinel_;
105 #define strjoin(a, ...) strjoin_real((a), __VA_ARGS__, NULL)
106
107 #define strjoina(a, ...) \
108 ({ \
109 const char *_appendees_[] = { a, __VA_ARGS__ }; \
110 char *_d_, *_p_; \
111 size_t _len_ = 0; \
112 size_t _i_; \
113 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
114 _len_ += strlen(_appendees_[_i_]); \
115 _p_ = _d_ = newa(char, _len_ + 1); \
116 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
117 _p_ = stpcpy(_p_, _appendees_[_i_]); \
118 *_p_ = 0; \
119 _d_; \
120 })
121
122 char *strstrip(char *s);
123 char *delete_chars(char *s, const char *bad);
124 char *delete_trailing_chars(char *s, const char *bad);
125 char *truncate_nl(char *s);
126
127 static inline char *skip_leading_chars(const char *s, const char *bad) {
128
129 if (!s)
130 return NULL;
131
132 if (!bad)
133 bad = WHITESPACE;
134
135 return (char*) s + strspn(s, bad);
136 }
137
138 char ascii_tolower(char x);
139 char *ascii_strlower(char *s);
140 char *ascii_strlower_n(char *s, size_t n);
141
142 char ascii_toupper(char x);
143 char *ascii_strupper(char *s);
144
145 int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
146 int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
147
148 bool chars_intersect(const char *a, const char *b) _pure_;
149
150 static inline bool _pure_ in_charset(const char *s, const char* charset) {
151 assert(s);
152 assert(charset);
153 return s[strspn(s, charset)] == '\0';
154 }
155
156 bool string_has_cc(const char *p, const char *ok) _pure_;
157
158 char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
159 static inline char *ellipsize(const char *s, size_t length, unsigned percent) {
160 return ellipsize_mem(s, strlen(s), length, percent);
161 }
162
163 char *cellescape(char *buf, size_t len, const char *s);
164
165 /* This limit is arbitrary, enough to give some idea what the string contains */
166 #define CELLESCAPE_DEFAULT_LENGTH 64
167
168 bool nulstr_contains(const char *nulstr, const char *needle);
169
170 char* strshorten(char *s, size_t l);
171
172 char *strreplace(const char *text, const char *old_string, const char *new_string);
173
174 char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
175
176 char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_;
177
178 #define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__)
179
180 char *strrep(const char *s, unsigned n);
181
182 int split_pair(const char *s, const char *sep, char **l, char **r);
183
184 int free_and_strdup(char **p, const char *s);
185 int free_and_strndup(char **p, const char *s, size_t l);
186
187 /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
188 static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
189
190 if (needlelen <= 0)
191 return (void*) haystack;
192
193 if (haystacklen < needlelen)
194 return NULL;
195
196 assert(haystack);
197 assert(needle);
198
199 return memmem(haystack, haystacklen, needle, needlelen);
200 }
201
202 #if HAVE_EXPLICIT_BZERO
203 static inline void* explicit_bzero_safe(void *p, size_t l) {
204 if (l > 0)
205 explicit_bzero(p, l);
206
207 return p;
208 }
209 #else
210 void *explicit_bzero_safe(void *p, size_t l);
211 #endif
212
213 char *string_erase(char *x);
214
215 char *string_free_erase(char *s);
216 DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
217 #define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
218
219 bool string_is_safe(const char *p) _pure_;
220
221 static inline size_t strlen_ptr(const char *s) {
222 if (!s)
223 return 0;
224
225 return strlen(s);
226 }
227
228 /* Like startswith(), but operates on arbitrary memory blocks */
229 static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
230 size_t n;
231
232 assert(token);
233
234 n = strlen(token);
235 if (sz < n)
236 return NULL;
237
238 assert(p);
239
240 if (memcmp(p, token, n) != 0)
241 return NULL;
242
243 return (uint8_t*) p + n;
244 }
245
246 /* Like startswith_no_case(), but operates on arbitrary memory blocks.
247 * It works only for ASCII strings.
248 */
249 static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
250 size_t n, i;
251
252 assert(token);
253
254 n = strlen(token);
255 if (sz < n)
256 return NULL;
257
258 assert(p);
259
260 for (i = 0; i < n; i++) {
261 if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
262 return NULL;
263 }
264
265 return (uint8_t*) p + n;
266 }