]> git.ipfire.org Git - thirdparty/util-linux.git/blame - include/strutils.h
strutils: fix double free in strrealloc() [coverity scan]
[thirdparty/util-linux.git] / include / strutils.h
CommitLineData
8abcf290
DB
1#ifndef UTIL_LINUX_STRUTILS
2#define UTIL_LINUX_STRUTILS
3
23106a29 4#include <stdlib.h>
8abcf290
DB
5#include <inttypes.h>
6#include <string.h>
ce877f2d 7#include <sys/types.h>
675de3f5 8#include <ctype.h>
3e5a5455 9#include <stdio.h>
deb1c903 10#include <errno.h>
8abcf290 11
9c8b9fba
RM
12/* initialize a custom exit code for all *_or_err functions */
13extern void strutils_set_exitcode(int exit_code);
a99c9130 14
23106a29 15extern int parse_size(const char *str, uintmax_t *res, int *power);
8abcf290 16extern int strtosize(const char *str, uintmax_t *res);
551dae40
KZ
17extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
18
19extern int16_t strtos16_or_err(const char *str, const char *errmesg);
20extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
54394eab 21extern uint16_t strtox16_or_err(const char *str, const char *errmesg);
551dae40
KZ
22
23extern int32_t strtos32_or_err(const char *str, const char *errmesg);
24extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
54394eab 25extern uint32_t strtox32_or_err(const char *str, const char *errmesg);
551dae40
KZ
26
27extern int64_t strtos64_or_err(const char *str, const char *errmesg);
28extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
54394eab 29extern uint64_t strtox64_or_err(const char *str, const char *errmesg);
551dae40 30
a9f97001 31extern double strtod_or_err(const char *str, const char *errmesg);
551dae40 32
8abcf290 33extern long strtol_or_err(const char *str, const char *errmesg);
e53bc960 34extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
8abcf290 35
477254da
KZ
36extern void strtotimeval_or_err(const char *str, struct timeval *tv,
37 const char *errmesg);
38
61cbc8a3
KZ
39extern int isdigit_strend(const char *str, const char **end);
40#define isdigit_string(_s) isdigit_strend(_s, NULL)
41
42extern int isxdigit_strend(const char *str, const char **end);
43#define isxdigit_string(_s) isxdigit_strend(_s, NULL)
44
416c43a9 45
30b294c4 46extern int parse_switch(const char *arg, const char *errmesg, ...);
e5cf1476 47
02887b73
DT
48#ifndef HAVE_MEMPCPY
49extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
50#endif
8abcf290
DB
51#ifndef HAVE_STRNLEN
52extern size_t strnlen(const char *s, size_t maxlen);
53#endif
54#ifndef HAVE_STRNDUP
55extern char *strndup(const char *s, size_t n);
56#endif
57#ifndef HAVE_STRNCHR
58extern char *strnchr(const char *s, size_t maxlen, int c);
59#endif
60
61/* caller guarantees n > 0 */
62static inline void xstrncpy(char *dest, const char *src, size_t n)
63{
64 strncpy(dest, src, n-1);
65 dest[n-1] = 0;
66}
ce877f2d 67
a338eb4a
KZ
68/* This is like strncpy(), but based on memcpy(), so compilers and static
69 * analyzers do not complain when sizeof(destination) is the same as 'n' and
70 * result is not terminated by zero.
71 *
72 * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
73 * where string terminator is optional.
74 */
75static inline void *str2memcpy(void *dest, const char *src, size_t n)
76{
77 size_t bytes = strlen(src) + 1;
78
79 if (bytes > n)
80 bytes = n;
81
82 memcpy(dest, src, bytes);
83 return dest;
84}
85
86static inline char *mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
87{
88 if (n + 1 > nmax)
89 n = nmax - 1;
90
91 memcpy(dest, src, n);
92 dest[nmax-1] = '\0';
93 return dest;
94}
95
01aedbec
KZ
96/* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str.
97 * The @str is not modified if reallocation failed (like classic realloc()).
98 */
23afadca
KZ
99static inline char * __attribute__((warn_unused_result))
100strrealloc(char *str, const char *newstr)
101{
102 size_t nsz, osz;
103
104 if (!str)
105 return newstr ? strdup(newstr) : NULL;
01aedbec
KZ
106 if (!newstr)
107 return NULL;
23afadca
KZ
108
109 osz = strlen(str);
110 nsz = strlen(newstr);
111
01aedbec
KZ
112 if (nsz > osz)
113 str = realloc(str, nsz + 1);
114 if (str)
115 memcpy(str, newstr, nsz + 1);
23afadca 116 return str;
23afadca
KZ
117}
118
787226dc 119/* Copy string @str to struct @stru to member addressed by @offset */
deb1c903 120static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
23106a29 121{
deb1c903 122 char **o;
787226dc 123 char *p = NULL;
23106a29 124
deb1c903
KZ
125 if (!stru)
126 return -EINVAL;
127
128 o = (char **) ((char *) stru + offset);
23106a29 129 if (str) {
787226dc
KZ
130 p = strdup(str);
131 if (!p)
deb1c903 132 return -ENOMEM;
23106a29
KZ
133 }
134
135 free(*o);
787226dc 136 *o = p;
deb1c903 137 return 0;
23106a29
KZ
138}
139
787226dc 140/* Copy string __str to struct member _m of the struct _s */
23106a29
KZ
141#define strdup_to_struct_member(_s, _m, _str) \
142 strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
143
787226dc
KZ
144/* Copy string addressed by @offset between two structs */
145static inline int strdup_between_offsets(void *stru_dst, void *stru_src, size_t offset)
146{
147 char **src;
148 char **dst;
149 char *p = NULL;
150
151 if (!stru_src || !stru_dst)
152 return -EINVAL;
153
154 src = (char **) ((char *) stru_src + offset);
155 dst = (char **) ((char *) stru_dst + offset);
156
157 if (*src) {
158 p = strdup(*src);
159 if (!p)
160 return -ENOMEM;
161 }
162
163 free(*dst);
164 *dst = p;
165 return 0;
166}
167
168/* Copy string addressed by struct member between two instances of the same
169 * struct type */
170#define strdup_between_structs(_dst, _src, _m) \
171 strdup_between_offsets((void *)_dst, (void *)_src, offsetof(__typeof__(*(_src)), _m))
172
173
5b82289b 174extern char *xstrmode(mode_t mode, char *str);
5d2a9849
FC
175
176/* Options for size_to_human_string() */
177enum
178{
07b94c9f
KZ
179 SIZE_SUFFIX_1LETTER = 0,
180 SIZE_SUFFIX_3LETTER = (1 << 0),
181 SIZE_SUFFIX_SPACE = (1 << 1),
182 SIZE_DECIMAL_2DIGITS = (1 << 2)
5d2a9849
FC
183};
184
185extern char *size_to_human_string(int options, uint64_t bytes);
ce877f2d 186
c87638ad
KZ
187extern int string_to_idarray(const char *list, int ary[], size_t arysz,
188 int (name2id)(const char *, size_t));
f5077b51 189extern int string_add_to_idarray(const char *list, int ary[],
40b17508 190 size_t arysz, size_t *ary_pos,
f5077b51
MB
191 int (name2id)(const char *, size_t));
192
c87638ad
KZ
193extern int string_to_bitarray(const char *list, char *ary,
194 int (*name2bit)(const char *, size_t));
195
5ef16771
KZ
196extern int string_to_bitmask(const char *list,
197 unsigned long *mask,
198 long (*name2flag)(const char *, size_t));
af7df9ee 199extern int parse_range(const char *str, int *lower, int *upper, int def);
a883c634 200
d4e89dea 201extern int streq_paths(const char *a, const char *b);
b106d052 202
646e159a
KZ
203/*
204 * Match string beginning.
205 */
206static inline const char *startswith(const char *s, const char *prefix)
207{
208 size_t sz = prefix ? strlen(prefix) : 0;
209
210 if (s && sz && strncmp(s, prefix, sz) == 0)
211 return s + sz;
212 return NULL;
213}
214
215/*
216 * Case insensitive match string beginning.
217 */
218static inline const char *startswith_no_case(const char *s, const char *prefix)
219{
220 size_t sz = prefix ? strlen(prefix) : 0;
221
222 if (s && sz && strncasecmp(s, prefix, sz) == 0)
223 return s + sz;
224 return NULL;
225}
226
227/*
228 * Match string ending.
229 */
230static inline const char *endswith(const char *s, const char *postfix)
231{
232 size_t sl = s ? strlen(s) : 0;
233 size_t pl = postfix ? strlen(postfix) : 0;
234
235 if (pl == 0)
8a7aeeda 236 return s + sl;
646e159a
KZ
237 if (sl < pl)
238 return NULL;
239 if (memcmp(s + sl - pl, postfix, pl) != 0)
240 return NULL;
8a7aeeda 241 return s + sl - pl;
646e159a 242}
199e939d 243
675de3f5
OO
244/*
245 * Skip leading white space.
246 */
247static inline const char *skip_space(const char *p)
248{
249 while (isspace(*p))
250 ++p;
251 return p;
252}
253
254static inline const char *skip_blank(const char *p)
255{
256 while (isblank(*p))
257 ++p;
258 return p;
259}
260
22e9e9c8
KZ
261
262/* Removes whitespace from the right-hand side of a string (trailing
263 * whitespace).
264 *
265 * Returns size of the new string (without \0).
266 */
267static inline size_t rtrim_whitespace(unsigned char *str)
268{
0b404f08 269 size_t i;
22e9e9c8 270
0b404f08
SK
271 if (!str)
272 return 0;
273 i = strlen((char *) str);
2f8610ee
SK
274 while (i) {
275 i--;
276 if (!isspace(str[i])) {
277 i++;
22e9e9c8 278 break;
2f8610ee 279 }
22e9e9c8 280 }
2f8610ee 281 str[i] = '\0';
22e9e9c8
KZ
282 return i;
283}
284
285/* Removes whitespace from the left-hand side of a string.
286 *
287 * Returns size of the new string (without \0).
288 */
289static inline size_t ltrim_whitespace(unsigned char *str)
290{
291 size_t len;
292 unsigned char *p;
293
0b404f08
SK
294 if (!str)
295 return 0;
296 for (p = str; *p && isspace(*p); p++);
22e9e9c8
KZ
297
298 len = strlen((char *) p);
299
6c183c28 300 if (p > str)
22e9e9c8
KZ
301 memmove(str, p, len + 1);
302
303 return len;
304}
305
3c4ff2dc
KZ
306static inline void strrep(char *s, int find, int replace)
307{
308 while (s && *s && (s = strchr(s, find)) != NULL)
309 *s++ = replace;
310}
311
312static inline void strrem(char *s, int rem)
313{
314 char *p;
315
d2a1ee4e
SK
316 if (!s)
317 return;
318 for (p = s; *s; s++) {
3c4ff2dc
KZ
319 if (*s != rem)
320 *p++ = *s;
321 }
b94acada 322 *p = '\0';
3c4ff2dc
KZ
323}
324
548b9714
KZ
325extern char *strnappend(const char *s, const char *suffix, size_t b);
326extern char *strappend(const char *s, const char *suffix);
3c201431
KZ
327extern char *strfappend(const char *s, const char *format, ...)
328 __attribute__ ((__format__ (__printf__, 2, 0)));
548b9714
KZ
329extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
330
3e5a5455
SK
331extern int skip_fline(FILE *fp);
332
8abcf290 333#endif