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