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