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 48static inline bool 49streq(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 57static inline bool 58strneq(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 66static inline void * 67zalloc(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 */ 88static inline char* 89safe_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))) 116static inline int 117xasprintf(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))) 132static inline int 133xvasprintf(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 143static inline bool 144safe_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 169static inline bool 170safe_atoi(const char *str, int *val) 171{ 172 assert(str != NULL); 173 return safe_atoi_base(str, val, 10); 174} 175 176static inline bool 177safe_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 202static inline bool 203safe_atou(const char *str, unsigned int *val) 204{ 205 assert(str != NULL); 206 return safe_atou_base(str, val, 10); 207} 208 209static inline bool 210safe_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 265char **strv_from_argv(int argc, char **argv); 266char **strv_from_string(const char *in, const char *separator, size_t *num_elements); 267char *strv_join(char **strv, const char *joiner); 268 269static inline void 270strv_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 */ 294static inline double * 295double_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 324out: 325 strv_free(strv); 326 free(numv); 327 return result; 328} 329 330struct key_value_str{ 331 char *key; 332 char *value; 333}; 334 335struct key_value_double { 336 double key; 337 double value; 338}; 339 340static inline ssize_t 341kv_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 385error: 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 */ 398static inline char * 399strstrip(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 */ 423static inline bool 424strendswith(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 440static inline bool 441strstartswith(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 451const char * 452safe_basename(const char *filename); 453 454char * 455trunkname(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 */ 461static inline char * 462str_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