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