]> git.ipfire.org Git - thirdparty/util-linux.git/blame - include/strutils.h
Merge branch 'ci/meson-werror' of https://github.com/t-8ch/util-linux
[thirdparty/util-linux.git] / include / strutils.h
CommitLineData
faeb1b64
KZ
1/*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 */
8abcf290
DB
5#ifndef UTIL_LINUX_STRUTILS
6#define UTIL_LINUX_STRUTILS
7
23106a29 8#include <stdlib.h>
8abcf290
DB
9#include <inttypes.h>
10#include <string.h>
ce877f2d 11#include <sys/types.h>
675de3f5 12#include <ctype.h>
3e5a5455 13#include <stdio.h>
deb1c903 14#include <errno.h>
35c84bf7 15#include <time.h>
8abcf290 16
ad265938
KZ
17#include "c.h"
18
9c8b9fba
RM
19/* initialize a custom exit code for all *_or_err functions */
20extern void strutils_set_exitcode(int exit_code);
a99c9130 21
23106a29 22extern int parse_size(const char *str, uintmax_t *res, int *power);
8abcf290 23extern int strtosize(const char *str, uintmax_t *res);
551dae40
KZ
24extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
25
84825b16
KZ
26extern int ul_strtos64(const char *str, int64_t *num, int base);
27extern int ul_strtou64(const char *str, uint64_t *num, int base);
9fc0f69c
KZ
28extern int ul_strtos32(const char *str, int32_t *num, int base);
29extern int ul_strtou32(const char *str, uint32_t *num, int base);
a57de0ef 30extern int ul_strtold(const char *str, long double *num);
84825b16 31
9fc0f69c
KZ
32extern int64_t str2num_or_err(const char *str, int base, const char *errmesg, int64_t low, int64_t up);
33extern uint64_t str2unum_or_err(const char *str, int base, const char *errmesg, uint64_t up);
551dae40 34
9fc0f69c
KZ
35#define strtos64_or_err(_s, _e) str2num_or_err(_s, 10, _e, 0, 0)
36#define strtou64_or_err(_s, _e) str2unum_or_err(_s, 10, _e, 0)
37#define strtox64_or_err(_s, _e) str2unum_or_err(_s, 16, _e, 0)
551dae40 38
9fc0f69c
KZ
39#define strtos32_or_err(_s, _e) (int32_t) str2num_or_err(_s, 10, _e, INT32_MIN, INT32_MAX)
40#define strtou32_or_err(_s, _e) (uint32_t) str2unum_or_err(_s, 10, _e, UINT32_MAX)
41#define strtox32_or_err(_s, _e) (uint32_t) str2unum_or_err(_s, 16, _e, UINT32_MAX)
42
43#define strtos16_or_err(_s, _e) (int16_t) str2num_or_err(_s, 10, _e, INT16_MIN, INT16_MAX)
44#define strtou16_or_err(_s, _e) (uint16_t) str2unum_or_err(_s, 10, _e, UINT16_MAX)
45#define strtox16_or_err(_s, _e) (uint16_t) str2unum_or_err(_s, 16, _e, UINT16_MAX)
551dae40 46
a9f97001 47extern double strtod_or_err(const char *str, const char *errmesg);
35c84bf7 48extern long double strtold_or_err(const char *str, const char *errmesg);
551dae40 49
3b888573 50#define strtol_or_err(_s, _e) (long) str2num_or_err(_s, 10, _e, LONG_MIN, LONG_MAX)
550d32c4 51#define strtopid_or_err(_s, _e) (pid_t) str2num_or_err(_s, 10, _e, 1, SINT_MAX(pid_t))
3b888573 52#define strtoul_or_err(_s, _e) (unsigned long) str2unum_or_err(_s, 10, _e, ULONG_MAX)
8abcf290 53
477254da
KZ
54extern void strtotimeval_or_err(const char *str, struct timeval *tv,
55 const char *errmesg);
937cd872
TW
56extern void strtotimespec_or_err(const char *str, struct timespec *ts,
57 const char *errmesg);
35c84bf7 58extern time_t strtotime_or_err(const char *str, const char *errmesg);
477254da 59
61cbc8a3
KZ
60extern int isdigit_strend(const char *str, const char **end);
61#define isdigit_string(_s) isdigit_strend(_s, NULL)
62
63extern int isxdigit_strend(const char *str, const char **end);
64#define isxdigit_string(_s) isxdigit_strend(_s, NULL)
65
416c43a9 66
30b294c4 67extern int parse_switch(const char *arg, const char *errmesg, ...);
e5cf1476 68
02887b73
DT
69#ifndef HAVE_MEMPCPY
70extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
71#endif
8abcf290
DB
72#ifndef HAVE_STRNLEN
73extern size_t strnlen(const char *s, size_t maxlen);
74#endif
75#ifndef HAVE_STRNDUP
76extern char *strndup(const char *s, size_t n);
77#endif
78#ifndef HAVE_STRNCHR
79extern char *strnchr(const char *s, size_t maxlen, int c);
80#endif
81
82/* caller guarantees n > 0 */
83static inline void xstrncpy(char *dest, const char *src, size_t n)
84{
ad265938
KZ
85 size_t len = src ? strlen(src) : 0;
86
87 if (!len)
88 return;
89 len = min(len, n - 1);
90 memcpy(dest, src, len);
91 dest[len] = 0;
8abcf290 92}
ce877f2d 93
a338eb4a
KZ
94/* This is like strncpy(), but based on memcpy(), so compilers and static
95 * analyzers do not complain when sizeof(destination) is the same as 'n' and
96 * result is not terminated by zero.
97 *
98 * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
99 * where string terminator is optional.
100 */
d57672e2
KZ
101static inline void * __attribute__((nonnull (1)))
102str2memcpy(void *dest, const char *src, size_t n)
a338eb4a
KZ
103{
104 size_t bytes = strlen(src) + 1;
105
106 if (bytes > n)
107 bytes = n;
108
109 memcpy(dest, src, bytes);
110 return dest;
111}
112
d57672e2
KZ
113static inline char * __attribute__((nonnull (1)))
114mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
a338eb4a
KZ
115{
116 if (n + 1 > nmax)
117 n = nmax - 1;
118
9c05f4b6 119 memset(dest, '\0', nmax);
a338eb4a 120 memcpy(dest, src, n);
a338eb4a
KZ
121 return dest;
122}
123
01aedbec
KZ
124/* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str.
125 * The @str is not modified if reallocation failed (like classic realloc()).
126 */
23afadca
KZ
127static inline char * __attribute__((warn_unused_result))
128strrealloc(char *str, const char *newstr)
129{
130 size_t nsz, osz;
131
132 if (!str)
133 return newstr ? strdup(newstr) : NULL;
01aedbec
KZ
134 if (!newstr)
135 return NULL;
23afadca
KZ
136
137 osz = strlen(str);
138 nsz = strlen(newstr);
139
01aedbec
KZ
140 if (nsz > osz)
141 str = realloc(str, nsz + 1);
142 if (str)
143 memcpy(str, newstr, nsz + 1);
23afadca 144 return str;
23afadca
KZ
145}
146
787226dc 147/* Copy string @str to struct @stru to member addressed by @offset */
deb1c903 148static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
23106a29 149{
deb1c903 150 char **o;
787226dc 151 char *p = NULL;
23106a29 152
deb1c903
KZ
153 if (!stru)
154 return -EINVAL;
155
156 o = (char **) ((char *) stru + offset);
23106a29 157 if (str) {
787226dc
KZ
158 p = strdup(str);
159 if (!p)
deb1c903 160 return -ENOMEM;
23106a29
KZ
161 }
162
163 free(*o);
787226dc 164 *o = p;
deb1c903 165 return 0;
23106a29
KZ
166}
167
787226dc 168/* Copy string __str to struct member _m of the struct _s */
23106a29
KZ
169#define strdup_to_struct_member(_s, _m, _str) \
170 strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
171
787226dc
KZ
172/* Copy string addressed by @offset between two structs */
173static inline int strdup_between_offsets(void *stru_dst, void *stru_src, size_t offset)
174{
175 char **src;
176 char **dst;
177 char *p = NULL;
178
179 if (!stru_src || !stru_dst)
180 return -EINVAL;
181
182 src = (char **) ((char *) stru_src + offset);
183 dst = (char **) ((char *) stru_dst + offset);
184
185 if (*src) {
186 p = strdup(*src);
187 if (!p)
188 return -ENOMEM;
189 }
190
191 free(*dst);
192 *dst = p;
193 return 0;
194}
195
196/* Copy string addressed by struct member between two instances of the same
197 * struct type */
198#define strdup_between_structs(_dst, _src, _m) \
199 strdup_between_offsets((void *)_dst, (void *)_src, offsetof(__typeof__(*(_src)), _m))
200
201
5b82289b 202extern char *xstrmode(mode_t mode, char *str);
5d2a9849
FC
203
204/* Options for size_to_human_string() */
205enum
206{
07b94c9f
KZ
207 SIZE_SUFFIX_1LETTER = 0,
208 SIZE_SUFFIX_3LETTER = (1 << 0),
209 SIZE_SUFFIX_SPACE = (1 << 1),
210 SIZE_DECIMAL_2DIGITS = (1 << 2)
5d2a9849
FC
211};
212
213extern char *size_to_human_string(int options, uint64_t bytes);
ce877f2d 214
c87638ad
KZ
215extern int string_to_idarray(const char *list, int ary[], size_t arysz,
216 int (name2id)(const char *, size_t));
f5077b51 217extern int string_add_to_idarray(const char *list, int ary[],
40b17508 218 size_t arysz, size_t *ary_pos,
f5077b51
MB
219 int (name2id)(const char *, size_t));
220
c87638ad 221extern int string_to_bitarray(const char *list, char *ary,
73a96af6
TW
222 int (*name2bit)(const char *, size_t),
223 size_t allow_range);
c87638ad 224
5ef16771
KZ
225extern int string_to_bitmask(const char *list,
226 unsigned long *mask,
227 long (*name2flag)(const char *, size_t));
af7df9ee 228extern int parse_range(const char *str, int *lower, int *upper, int def);
a883c634 229
d4e89dea 230extern int streq_paths(const char *a, const char *b);
b106d052 231
646e159a
KZ
232/*
233 * Match string beginning.
234 */
235static inline const char *startswith(const char *s, const char *prefix)
236{
237 size_t sz = prefix ? strlen(prefix) : 0;
238
239 if (s && sz && strncmp(s, prefix, sz) == 0)
240 return s + sz;
241 return NULL;
242}
243
244/*
245 * Case insensitive match string beginning.
246 */
247static inline const char *startswith_no_case(const char *s, const char *prefix)
248{
249 size_t sz = prefix ? strlen(prefix) : 0;
250
251 if (s && sz && strncasecmp(s, prefix, sz) == 0)
252 return s + sz;
253 return NULL;
254}
255
256/*
257 * Match string ending.
258 */
259static inline const char *endswith(const char *s, const char *postfix)
260{
261 size_t sl = s ? strlen(s) : 0;
262 size_t pl = postfix ? strlen(postfix) : 0;
263
264 if (pl == 0)
8a7aeeda 265 return s + sl;
646e159a
KZ
266 if (sl < pl)
267 return NULL;
268 if (memcmp(s + sl - pl, postfix, pl) != 0)
269 return NULL;
8a7aeeda 270 return s + sl - pl;
646e159a 271}
199e939d 272
675de3f5
OO
273/*
274 * Skip leading white space.
275 */
276static inline const char *skip_space(const char *p)
277{
278 while (isspace(*p))
279 ++p;
280 return p;
281}
282
283static inline const char *skip_blank(const char *p)
284{
285 while (isblank(*p))
286 ++p;
287 return p;
288}
289
22e9e9c8
KZ
290
291/* Removes whitespace from the right-hand side of a string (trailing
292 * whitespace).
293 *
294 * Returns size of the new string (without \0).
295 */
296static inline size_t rtrim_whitespace(unsigned char *str)
297{
0b404f08 298 size_t i;
22e9e9c8 299
0b404f08
SK
300 if (!str)
301 return 0;
302 i = strlen((char *) str);
2f8610ee
SK
303 while (i) {
304 i--;
305 if (!isspace(str[i])) {
306 i++;
22e9e9c8 307 break;
2f8610ee 308 }
22e9e9c8 309 }
2f8610ee 310 str[i] = '\0';
22e9e9c8
KZ
311 return i;
312}
313
314/* Removes whitespace from the left-hand side of a string.
315 *
316 * Returns size of the new string (without \0).
317 */
318static inline size_t ltrim_whitespace(unsigned char *str)
319{
320 size_t len;
321 unsigned char *p;
322
0b404f08
SK
323 if (!str)
324 return 0;
325 for (p = str; *p && isspace(*p); p++);
22e9e9c8
KZ
326
327 len = strlen((char *) p);
328
6c183c28 329 if (p > str)
22e9e9c8
KZ
330 memmove(str, p, len + 1);
331
332 return len;
333}
334
5d68f974
KZ
335/* Removes left-hand, right-hand and repeating whitespaces.
336 */
c862d0e1
KZ
337static inline size_t __normalize_whitespace(
338 const unsigned char *src,
339 size_t sz,
340 unsigned char *dst,
341 size_t len)
5d68f974 342{
c862d0e1 343 size_t i, x = 0;
5d68f974
KZ
344 int nsp = 0, intext = 0;
345
346 if (!sz)
c862d0e1 347 goto done;
5d68f974 348
c862d0e1
KZ
349 for (i = 0, x = 0; i < sz && x < len - 1; ) {
350 if (isspace(src[i]))
5d68f974
KZ
351 nsp++;
352 else
353 nsp = 0, intext = 1;
354
355 if (nsp > 1 || (nsp && !intext))
356 i++;
357 else
c862d0e1 358 dst[x++] = src[i++];
5d68f974 359 }
c862d0e1 360 if (nsp && x > 0) /* tailing space */
5d68f974 361 x--;
c862d0e1
KZ
362done:
363 dst[x] = '\0';
5d68f974
KZ
364 return x;
365}
366
c862d0e1
KZ
367static inline size_t normalize_whitespace(unsigned char *str)
368{
369 size_t sz = strlen((char *) str);
370 return __normalize_whitespace(str, sz, str, sz + 1);
371}
372
3c4ff2dc
KZ
373static inline void strrep(char *s, int find, int replace)
374{
375 while (s && *s && (s = strchr(s, find)) != NULL)
376 *s++ = replace;
377}
378
379static inline void strrem(char *s, int rem)
380{
381 char *p;
382
d2a1ee4e
SK
383 if (!s)
384 return;
385 for (p = s; *s; s++) {
3c4ff2dc
KZ
386 if (*s != rem)
387 *p++ = *s;
388 }
b94acada 389 *p = '\0';
3c4ff2dc
KZ
390}
391
357e6a0e
KZ
392/* returns next string after \0 if before @end */
393static inline char *ul_next_string(char *p, char *end)
394{
395 char *last;
396
397 if (!p || !end || p >= end)
398 return NULL;
399
400 for (last = p; p < end; p++) {
401 if (*last == '\0' && p != last)
402 return p;
403 last = p;
404 }
405
406 return NULL;
407}
408
8420463b
KZ
409extern char *strnconcat(const char *s, const char *suffix, size_t b);
410extern char *strconcat(const char *s, const char *suffix);
411extern char *strfconcat(const char *s, const char *format, ...)
40b55f5a 412 __attribute__ ((__format__ (__printf__, 2, 3)));
2e03758d
KZ
413
414extern int strappend(char **a, const char *b);
25a5cff8
MY
415extern int strfappend(char **a, const char *format, ...)
416 __attribute__ ((__format__ (__printf__, 2, 3)));
417extern int strvfappend(char **a, const char *format, va_list ap)
418 __attribute__ ((__format__ (__printf__, 2, 0)));
2e03758d 419
548b9714
KZ
420extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
421
63bb0450
KZ
422extern char *ul_strchr_escaped(const char *s, int c);
423
3e5a5455 424extern int skip_fline(FILE *fp);
27e6b3a9 425extern int ul_stralnumcmp(const char *p1, const char *p2);
3e5a5455 426
6c513f3c
KZ
427extern int ul_optstr_next(char **optstr, char **name, size_t *namesz, char **value, size_t *valsz);
428
8abcf290 429#endif