1 /*
2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2013-2015 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #pragma once
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <math.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdbool.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #ifdef HAVE_LOCALE_H
40 #include <locale.h>
41 #endif
42 #ifdef HAVE_XLOCALE_H
43 #include <xlocale.h>
44 #endif
45
46 #include "util-macros.h"
47
48 static inline bool
streq(const char * str1,const char * str2)49 streq(const char *str1, const char *str2)
50 {
51 /* one NULL, one not NULL is always false */
52 if (str1 && str2)
53 return strcmp(str1, str2) == 0;
54 return str1 == str2;
55 }
56
57 static inline bool
strneq(const char * str1,const char * str2,int n)58 strneq(const char *str1, const char *str2, int n)
59 {
60 /* one NULL, one not NULL is always false */
61 if (str1 && str2)
62 return strncmp(str1, str2, n) == 0;
63 return str1 == str2;
64 }
65
66 static inline void *
zalloc(size_t size)67 zalloc(size_t size)
68 {
69 void *p;
70
71 /* We never need to alloc anything more than 1,5 MB so we can assume
72 * if we ever get above that something's going wrong */
73 if (size > 1536 * 1024)
74 assert(!"bug: internal malloc size limit exceeded");
75
76 p = calloc(1, size);
77 if (!p)
78 abort();
79
80 return p;
81 }
82
83 /**
84 * strdup guaranteed to succeed. If the input string is NULL, the output
85 * string is NULL. If the input string is a string pointer, we strdup or
86 * abort on failure.
87 */
88 static inline char*
safe_strdup(const char * str)89 safe_strdup(const char *str)
90 {
91 char *s;
92
93 if (!str)
94 return NULL;
95
96 s = strdup(str);
97 if (!s)
98 abort();
99 return s;
100 }
101
102 /**
103 * Simple wrapper for asprintf that ensures the passed in-pointer is set
104 * to NULL upon error.
105 * The standard asprintf() call does not guarantee the passed in pointer
106 * will be NULL'ed upon failure, whereas this wrapper does.
107 *
108 * @param strp pointer to set to newly allocated string.
109 * This pointer should be passed to free() to release when done.
110 * @param fmt the format string to use for printing.
111 * @return The number of bytes printed (excluding the null byte terminator)
112 * upon success or -1 upon failure. In the case of failure the pointer is set
113 * to NULL.
114 */
115 __attribute__ ((format (printf, 2, 3)))
116 static inline int
xasprintf(char ** strp,const char * fmt,...)117 xasprintf(char **strp, const char *fmt, ...)
118 {
119 int rc = 0;
120 va_list args;
121
122 va_start(args, fmt);
123 rc = vasprintf(strp, fmt, args);
124 va_end(args);
125 if ((rc == -1) && strp)
126 *strp = NULL;
127
128 return rc;
129 }
130
131 __attribute__ ((format (printf, 2, 0)))
132 static inline int
xvasprintf(char ** strp,const char * fmt,va_list args)133 xvasprintf(char **strp, const char *fmt, va_list args)
134 {
135 int rc = 0;
136 rc = vasprintf(strp, fmt, args);
137 if ((rc == -1) && strp)
138 *strp = NULL;
139
140 return rc;
141 }
142
143 static inline bool
safe_atoi_base(const char * str,int * val,int base)144 safe_atoi_base(const char *str, int *val, int base)
145 {
146 assert(str != NULL);
147
148 char *endptr;
149 long v;
150
151 assert(base == 10 || base == 16 || base == 8);
152
153 errno = 0;
154 v = strtol(str, &endptr, base);
155 if (errno > 0)
156 return false;
157 if (str == endptr)
158 return false;
159 if (*str != '\0' && *endptr != '\0')
160 return false;
161
162 if (v > INT_MAX || v < INT_MIN)
163 return false;
164
165 *val = v;
166 return true;
167 }
168
169 static inline bool
safe_atoi(const char * str,int * val)170 safe_atoi(const char *str, int *val)
171 {
172 assert(str != NULL);
173 return safe_atoi_base(str, val, 10);
174 }
175
176 static inline bool
safe_atou_base(const char * str,unsigned int * val,int base)177 safe_atou_base(const char *str, unsigned int *val, int base)
178 {
179 assert(str != NULL);
180
181 char *endptr;
182 unsigned long v;
183
184 assert(base == 10 || base == 16 || base == 8);
185
186 errno = 0;
187 v = strtoul(str, &endptr, base);
188 if (errno > 0)
189 return false;
190 if (str == endptr)
191 return false;
192 if (*str != '\0' && *endptr != '\0')
193 return false;
194
195 if ((long)v < 0)
196 return false;
197
198 *val = v;
199 return true;
200 }
201
202 static inline bool
safe_atou(const char * str,unsigned int * val)203 safe_atou(const char *str, unsigned int *val)
204 {
205 assert(str != NULL);
206 return safe_atou_base(str, val, 10);
207 }
208
209 static inline bool
safe_atod(const char * str,double * val)210 safe_atod(const char *str, double *val)
211 {
212 assert(str != NULL);
213
214 char *endptr;
215 double v;
216 #ifdef HAVE_LOCALE_H
217 locale_t c_locale;
218 #endif
219 size_t slen = strlen(str);
220
221 /* We don't have a use-case where we want to accept hex for a double
222 * or any of the other values strtod can parse */
223 for (size_t i = 0; i < slen; i++) {
224 char c = str[i];
225
226 if (isdigit(c))
227 continue;
228 switch(c) {
229 case '+':
230 case '-':
231 case '.':
232 break;
233 default:
234 return false;
235 }
236 }
237
238 #ifdef HAVE_LOCALE_H
239 /* Create a "C" locale to force strtod to use '.' as separator */
240 c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
241 if (c_locale == (locale_t)0)
242 return false;
243
244 errno = 0;
245 v = strtod_l(str, &endptr, c_locale);
246 freelocale(c_locale);
247 #else
248 /* No locale support in provided libc, assume it already uses '.' */
249 errno = 0;
250 v = strtod(str, &endptr);
251 #endif
252 if (errno > 0)
253 return false;
254 if (str == endptr)
255 return false;
256 if (*str != '\0' && *endptr != '\0')
257 return false;
258 if (v != 0.0 && !isnormal(v))
259 return false;
260
261 *val = v;
262 return true;
263 }
264
265 char **strv_from_argv(int argc, char **argv);
266 char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
267 char *strv_join(char **strv, const char *joiner);
268
269 static inline void
strv_free(char ** strv)270 strv_free(char **strv) {
271 char **s = strv;
272
273 if (!strv)
274 return;
275
276 while (*s != NULL) {
277 free(*s);
278 *s = (char*)0x1; /* detect use-after-free */
279 s++;
280 }
281
282 free (strv);
283 }
284
285 /**
286 * parse a string containing a list of doubles into a double array.
287 *
288 * @param in string to parse
289 * @param separator string used to separate double in list e.g. ","
290 * @param result double array
291 * @param length length of double array
292 * @return true when parsed successfully otherwise false
293 */
294 static inline double *
double_array_from_string(const char * in,const char * separator,size_t * length)295 double_array_from_string(const char *in,
296 const char *separator,
297 size_t *length)
298 {
299 assert(in != NULL);
300 assert(separator != NULL);
301 assert(length != NULL);
302
303 double *result = NULL;
304 *length = 0;
305
306 size_t nelem;
307 char **strv = strv_from_string(in, separator, &nelem);
308 if (!strv)
309 return result;
310
311 double *numv = zalloc(sizeof(double) * nelem);
312 for (size_t idx = 0; idx < nelem; idx++) {
313 double val;
314 if (!safe_atod(strv[idx], &val))
315 goto out;
316
317 numv[idx] = val;
318 }
319
320 result = numv;
321 numv = NULL;
322 *length = nelem;
323
324 out:
325 strv_free(strv);
326 free(numv);
327 return result;
328 }
329
330 struct key_value_str{
331 char *key;
332 char *value;
333 };
334
335 struct key_value_double {
336 double key;
337 double value;
338 };
339
340 static inline ssize_t
kv_double_from_string(const char * string,const char * pair_separator,const char * kv_separator,struct key_value_double ** result_out)341 kv_double_from_string(const char *string,
342 const char *pair_separator,
343 const char *kv_separator,
344 struct key_value_double **result_out)
345
346 {
347 struct key_value_double *result = NULL;
348
349 if (!pair_separator || pair_separator[0] == '\0' ||
350 !kv_separator || kv_separator[0] == '\0')
351 return -1;
352
353 size_t npairs;
354 char **pairs = strv_from_string(string, pair_separator, &npairs);
355 if (!pairs || npairs == 0)
356 goto error;
357
358 result = zalloc(npairs * sizeof *result);
359
360 for (size_t idx = 0; idx < npairs; idx++) {
361 char *pair = pairs[idx];
362 size_t nelem;
363 char **kv = strv_from_string(pair, kv_separator, &nelem);
364 double k, v;
365
366 if (!kv || nelem != 2 ||
367 !safe_atod(kv[0], &k) ||
368 !safe_atod(kv[1], &v)) {
369 strv_free(kv);
370 goto error;
371 }
372
373 result[idx].key = k;
374 result[idx].value = v;
375
376 strv_free(kv);
377 }
378
379 strv_free(pairs);
380
381 *result_out = result;
382
383 return npairs;
384
385 error:
386 strv_free(pairs);
387 free(result);
388 return -1;
389 }
390
391 /**
392 * Strip any of the characters in what from the beginning and end of the
393 * input string.
394 *
395 * @return a newly allocated string with none of "what" at the beginning or
396 * end of string
397 */
398 static inline char *
strstrip(const char * input,const char * what)399 strstrip(const char *input, const char *what)
400 {
401 assert(input != NULL);
402
403 char *str, *last;
404
405 str = safe_strdup(&input[strspn(input, what)]);
406
407 last = str;
408
409 for (char *c = str; *c != '\0'; c++) {
410 if (!strchr(what, *c))
411 last = c + 1;
412 }
413
414 *last = '\0';
415
416 return str;
417 }
418
419 /**
420 * Return true if str ends in suffix, false otherwise. If the suffix is the
421 * empty string, strendswith() always returns false.
422 */
423 static inline bool
strendswith(const char * str,const char * suffix)424 strendswith(const char *str, const char *suffix)
425 {
426 if (str == NULL)
427 return false;
428
429 size_t slen = strlen(str);
430 size_t suffixlen = strlen(suffix);
431 size_t offset;
432
433 if (slen == 0 || suffixlen == 0 || suffixlen > slen)
434 return false;
435
436 offset = slen - suffixlen;
437 return strneq(&str[offset], suffix, suffixlen);
438 }
439
440 static inline bool
strstartswith(const char * str,const char * prefix)441 strstartswith(const char *str, const char *prefix)
442 {
443 if (str == NULL)
444 return false;
445
446 size_t prefixlen = strlen(prefix);
447
448 return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
449 }
450
451 const char *
452 safe_basename(const char *filename);
453
454 char *
455 trunkname(const char *filename);
456
457 /**
458 * Return a copy of str with all % converted to %% to make the string
459 * acceptable as printf format.
460 */
461 static inline char *
str_sanitize(const char * str)462 str_sanitize(const char *str)
463 {
464 if (!str)
465 return NULL;
466
467 if (!strchr(str, '%'))
468 return strdup(str);
469
470 size_t slen = min(strlen(str), 512);
471 char *sanitized = zalloc(2 * slen + 1);
472 const char *src = str;
473 char *dst = sanitized;
474
475 for (size_t i = 0; i < slen; i++) {
476 if (*src == '%')
477 *dst++ = '%';
478 *dst++ = *src++;
479 }
480 *dst = '\0';
481
482 return sanitized;
483 }
484