• 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 #define streq(s1, s2) (strcmp((s1), (s2)) == 0)
47 #define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
48 
49 static inline void *
zalloc(size_t size)50 zalloc(size_t size)
51 {
52 	void *p;
53 
54 	/* We never need to alloc anything more than 1,5 MB so we can assume
55 	 * if we ever get above that something's going wrong */
56 	if (size > 1536 * 1024)
57 		assert(!"bug: internal malloc size limit exceeded");
58 
59 	p = calloc(1, size);
60 	if (!p)
61 		abort();
62 
63 	return p;
64 }
65 
66 /**
67  * strdup guaranteed to succeed. If the input string is NULL, the output
68  * string is NULL. If the input string is a string pointer, we strdup or
69  * abort on failure.
70  */
71 static inline char*
safe_strdup(const char * str)72 safe_strdup(const char *str)
73 {
74 	char *s;
75 
76 	if (!str)
77 		return NULL;
78 
79 	s = strdup(str);
80 	if (!s)
81 		abort();
82 	return s;
83 }
84 
85 /**
86  * Simple wrapper for asprintf that ensures the passed in-pointer is set
87  * to NULL upon error.
88  * The standard asprintf() call does not guarantee the passed in pointer
89  * will be NULL'ed upon failure, whereas this wrapper does.
90  *
91  * @param strp pointer to set to newly allocated string.
92  * This pointer should be passed to free() to release when done.
93  * @param fmt the format string to use for printing.
94  * @return The number of bytes printed (excluding the null byte terminator)
95  * upon success or -1 upon failure. In the case of failure the pointer is set
96  * to NULL.
97  */
98 __attribute__ ((format (printf, 2, 3)))
99 static inline int
xasprintf(char ** strp,const char * fmt,...)100 xasprintf(char **strp, const char *fmt, ...)
101 {
102 	int rc = 0;
103 	va_list args;
104 
105 	va_start(args, fmt);
106 	rc = vasprintf(strp, fmt, args);
107 	va_end(args);
108 	if ((rc == -1) && strp)
109 		*strp = NULL;
110 
111 	return rc;
112 }
113 
114 static inline bool
safe_atoi_base(const char * str,int * val,int base)115 safe_atoi_base(const char *str, int *val, int base)
116 {
117 	char *endptr;
118 	long v;
119 
120 	assert(base == 10 || base == 16 || base == 8);
121 
122 	errno = 0;
123 	v = strtol(str, &endptr, base);
124 	if (errno > 0)
125 		return false;
126 	if (str == endptr)
127 		return false;
128 	if (*str != '\0' && *endptr != '\0')
129 		return false;
130 
131 	if (v > INT_MAX || v < INT_MIN)
132 		return false;
133 
134 	*val = v;
135 	return true;
136 }
137 
138 static inline bool
safe_atoi(const char * str,int * val)139 safe_atoi(const char *str, int *val)
140 {
141 	return safe_atoi_base(str, val, 10);
142 }
143 
144 static inline bool
safe_atou_base(const char * str,unsigned int * val,int base)145 safe_atou_base(const char *str, unsigned int *val, int base)
146 {
147 	char *endptr;
148 	unsigned long v;
149 
150 	assert(base == 10 || base == 16 || base == 8);
151 
152 	errno = 0;
153 	v = strtoul(str, &endptr, base);
154 	if (errno > 0)
155 		return false;
156 	if (str == endptr)
157 		return false;
158 	if (*str != '\0' && *endptr != '\0')
159 		return false;
160 
161 	if ((long)v < 0)
162 		return false;
163 
164 	*val = v;
165 	return true;
166 }
167 
168 static inline bool
safe_atou(const char * str,unsigned int * val)169 safe_atou(const char *str, unsigned int *val)
170 {
171 	return safe_atou_base(str, val, 10);
172 }
173 
174 static inline bool
safe_atod(const char * str,double * val)175 safe_atod(const char *str, double *val)
176 {
177 	char *endptr;
178 	double v;
179 #ifdef HAVE_LOCALE_H
180 	locale_t c_locale;
181 #endif
182 	size_t slen = strlen(str);
183 
184 	/* We don't have a use-case where we want to accept hex for a double
185 	 * or any of the other values strtod can parse */
186 	for (size_t i = 0; i < slen; i++) {
187 		char c = str[i];
188 
189 		if (isdigit(c))
190 		       continue;
191 		switch(c) {
192 		case '+':
193 		case '-':
194 		case '.':
195 			break;
196 		default:
197 			return false;
198 		}
199 	}
200 
201 #ifdef HAVE_LOCALE_H
202 	/* Create a "C" locale to force strtod to use '.' as separator */
203 	c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
204 	if (c_locale == (locale_t)0)
205 		return false;
206 
207 	errno = 0;
208 	v = strtod_l(str, &endptr, c_locale);
209 	freelocale(c_locale);
210 #else
211 	/* No locale support in provided libc, assume it already uses '.' */
212 	errno = 0;
213 	v = strtod(str, &endptr);
214 #endif
215 	if (errno > 0)
216 		return false;
217 	if (str == endptr)
218 		return false;
219 	if (*str != '\0' && *endptr != '\0')
220 		return false;
221 	if (v != 0.0 && !isnormal(v))
222 		return false;
223 
224 	*val = v;
225 	return true;
226 }
227 
228 char **strv_from_string(const char *string, const char *separator);
229 char *strv_join(char **strv, const char *separator);
230 
231 static inline void
strv_free(char ** strv)232 strv_free(char **strv) {
233 	char **s = strv;
234 
235 	if (!strv)
236 		return;
237 
238 	while (*s != NULL) {
239 		free(*s);
240 		*s = (char*)0x1; /* detect use-after-free */
241 		s++;
242 	}
243 
244 	free (strv);
245 }
246 
247 struct key_value_str{
248 	char *key;
249 	char *value;
250 };
251 
252 struct key_value_double {
253 	double key;
254 	double value;
255 };
256 
257 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)258 kv_double_from_string(const char *string,
259 		      const char *pair_separator,
260 		      const char *kv_separator,
261 		      struct key_value_double **result_out)
262 
263 {
264 	char **pairs;
265 	char **pair;
266 	struct key_value_double *result = NULL;
267 	ssize_t npairs = 0;
268 	unsigned int idx = 0;
269 
270 	if (!pair_separator || pair_separator[0] == '\0' ||
271 	    !kv_separator || kv_separator[0] == '\0')
272 		return -1;
273 
274 	pairs = strv_from_string(string, pair_separator);
275 	if (!pairs)
276 		return -1;
277 
278 	for (pair = pairs; *pair; pair++)
279 		npairs++;
280 
281 	if (npairs == 0)
282 		goto error;
283 
284 	result = zalloc(npairs * sizeof *result);
285 
286 	for (pair = pairs; *pair; pair++) {
287 		char **kv = strv_from_string(*pair, kv_separator);
288 		double k, v;
289 
290 		if (!kv || !kv[0] || !kv[1] || kv[2] ||
291 		    !safe_atod(kv[0], &k) ||
292 		    !safe_atod(kv[1], &v)) {
293 			strv_free(kv);
294 			goto error;
295 		}
296 
297 		result[idx].key = k;
298 		result[idx].value = v;
299 		idx++;
300 
301 		strv_free(kv);
302 	}
303 
304 	strv_free(pairs);
305 
306 	*result_out = result;
307 
308 	return npairs;
309 
310 error:
311 	strv_free(pairs);
312 	free(result);
313 	return -1;
314 }
315 
316 /**
317  * Strip any of the characters in what from the beginning and end of the
318  * input string.
319  *
320  * @return a newly allocated string with none of "what" at the beginning or
321  * end of string
322  */
323 static inline char *
strstrip(const char * input,const char * what)324 strstrip(const char *input, const char *what)
325 {
326 	char *str, *last;
327 
328 	str = safe_strdup(&input[strspn(input, what)]);
329 
330 	last = str;
331 
332 	for (char *c = str; *c != '\0'; c++) {
333 		if (!strchr(what, *c))
334 			last = c + 1;
335 	}
336 
337 	*last = '\0';
338 
339 	return str;
340 }
341 
342 /**
343  * Return true if str ends in suffix, false otherwise. If the suffix is the
344  * empty string, strendswith() always returns false.
345  */
346 static inline bool
strendswith(const char * str,const char * suffix)347 strendswith(const char *str, const char *suffix)
348 {
349 	size_t slen = strlen(str);
350 	size_t suffixlen = strlen(suffix);
351 	size_t offset;
352 
353 	if (slen == 0 || suffixlen == 0 || suffixlen > slen)
354 		return false;
355 
356 	offset = slen - suffixlen;
357 	return strneq(&str[offset], suffix, suffixlen);
358 }
359 
360 static inline bool
strstartswith(const char * str,const char * prefix)361 strstartswith(const char *str, const char *prefix)
362 {
363 	size_t prefixlen = strlen(prefix);
364 
365 	return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
366 }
367