Coverage Report

Created: 2026-10-17 07:11

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