• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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