This source file includes following definitions.
- scan_ll
 
- pcmk__scan_ll
 
- pcmk__scan_min_int
 
- pcmk__scan_port
 
- pcmk__scan_double
 
- pcmk__guint_from_hash
 
- crm_get_msec
 
- crm_is_true
 
- crm_str_to_boolean
 
- pcmk__trim
 
- pcmk__starts_with
 
- ends_with
 
- pcmk__ends_with
 
- pcmk__ends_with_ext
 
- pcmk__str_hash
 
- pcmk__strkey_table
 
- pcmk__strcase_equal
 
- pcmk__strcase_hash
 
- pcmk__strikey_table
 
- copy_str_table_entry
 
- pcmk__str_table_dup
 
- pcmk__add_separated_word
 
- pcmk__compress
 
- crm_strdup_printf
 
- pcmk__parse_ll_range
 
- pcmk__str_in_list
 
- str_any_of
 
- pcmk__strcase_any_of
 
- pcmk__str_any_of
 
- pcmk__char_in_any_str
 
- pcmk__numeric_strcasecmp
 
- pcmk__strcmp
 
- pcmk__str_update
 
- pcmk__g_strcat
 
- safe_str_neq
 
- crm_str_eq
 
- crm_itoa_stack
 
- g_str_hash_traditional
 
- crm_strcase_equal
 
- crm_strcase_hash
 
- crm_str_table_dup
 
- crm_parse_ll
 
- crm_parse_int
 
- crm_strip_trailing_newline
 
- pcmk_numeric_strcasecmp
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <regex.h>
  17 #include <stdio.h>
  18 #include <string.h>
  19 #include <stdlib.h>
  20 #include <ctype.h>
  21 #include <float.h>  
  22 #include <limits.h>
  23 #include <math.h>   
  24 #include <bzlib.h>
  25 #include <sys/types.h>
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 static int
  43 scan_ll(const char *text, long long *result, long long default_value,
     
  44         char **end_text)
  45 {
  46     long long local_result = default_value;
  47     char *local_end_text = NULL;
  48     int rc = pcmk_rc_ok;
  49 
  50     errno = 0;
  51     if (text != NULL) {
  52         local_result = strtoll(text, &local_end_text, 10);
  53         if (errno == ERANGE) {
  54             rc = EOVERFLOW;
  55             crm_warn("Integer parsed from '%s' was clipped to %lld",
  56                      text, local_result);
  57 
  58         } else if (errno != 0) {
  59             rc = errno;
  60             local_result = default_value;
  61             crm_warn("Could not parse integer from '%s' (using %lld instead): "
  62                      "%s", text, default_value, pcmk_rc_str(rc));
  63 
  64         } else if (local_end_text == text) {
  65             rc = EINVAL;
  66             local_result = default_value;
  67             crm_warn("Could not parse integer from '%s' (using %lld instead): "
  68                     "No digits found", text, default_value);
  69         }
  70 
  71         if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
  72             crm_warn("Characters left over after parsing '%s': '%s'",
  73                      text, local_end_text);
  74         }
  75         errno = rc;
  76     }
  77     if (end_text != NULL) {
  78         *end_text = local_end_text;
  79     }
  80     if (result != NULL) {
  81         *result = local_result;
  82     }
  83     return rc;
  84 }
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 
  93 
  94 
  95 
  96 int
  97 pcmk__scan_ll(const char *text, long long *result, long long default_value)
     
  98 {
  99     long long local_result = default_value;
 100     int rc = pcmk_rc_ok;
 101 
 102     if (text != NULL) {
 103         rc = scan_ll(text, &local_result, default_value, NULL);
 104         if (rc != pcmk_rc_ok) {
 105             local_result = default_value;
 106         }
 107     }
 108     if (result != NULL) {
 109         *result = local_result;
 110     }
 111     return rc;
 112 }
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 int
 127 pcmk__scan_min_int(const char *text, int *result, int minimum)
     
 128 {
 129     int rc;
 130     long long result_ll;
 131 
 132     rc = pcmk__scan_ll(text, &result_ll, (long long) minimum);
 133 
 134     if (result_ll < (long long) minimum) {
 135         crm_warn("Clipped '%s' to minimum acceptable value %d", text, minimum);
 136         result_ll = (long long) minimum;
 137 
 138     } else if (result_ll > INT_MAX) {
 139         crm_warn("Clipped '%s' to maximum integer %d", text, INT_MAX);
 140         result_ll = (long long) INT_MAX;
 141         rc = EOVERFLOW;
 142     }
 143 
 144     if (result != NULL) {
 145         *result = (int) result_ll;
 146     }
 147     return rc;
 148 }
 149 
 150 
 151 
 152 
 153 
 154 
 155 
 156 
 157 
 158 
 159 
 160 int
 161 pcmk__scan_port(const char *text, int *port)
     
 162 {
 163     long long port_ll;
 164     int rc = pcmk__scan_ll(text, &port_ll, -1LL);
 165 
 166     if ((text != NULL) && (rc == pcmk_rc_ok) 
 167         && ((port_ll < 0LL) || (port_ll > 65535LL))) {
 168         crm_warn("Ignoring port specification '%s' "
 169                  "not in valid range (0-65535)", text);
 170         rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range;
 171         port_ll = -1LL;
 172     }
 173     if (port != NULL) {
 174         *port = (int) port_ll;
 175     }
 176     return rc;
 177 }
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 int
 199 pcmk__scan_double(const char *text, double *result, const char *default_text,
     
 200                   char **end_text)
 201 {
 202     int rc = pcmk_rc_ok;
 203     char *local_end_text = NULL;
 204 
 205     CRM_ASSERT(result != NULL);
 206     *result = PCMK__PARSE_DBL_DEFAULT;
 207 
 208     text = (text != NULL) ? text : default_text;
 209 
 210     if (text == NULL) {
 211         rc = EINVAL;
 212         crm_debug("No text and no default conversion value supplied");
 213 
 214     } else {
 215         errno = 0;
 216         *result = strtod(text, &local_end_text);
 217 
 218         if (errno == ERANGE) {
 219             
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228             const char *over_under;
 229 
 230             if (fabs(*result) > DBL_MIN) {
 231                 rc = EOVERFLOW;
 232                 over_under = "over";
 233             } else {
 234                 rc = pcmk_rc_underflow;
 235                 over_under = "under";
 236             }
 237 
 238             crm_debug("Floating-point value parsed from '%s' would %sflow "
 239                       "(using %g instead)", text, over_under, *result);
 240 
 241         } else if (errno != 0) {
 242             rc = errno;
 243             
 244             *result = PCMK__PARSE_DBL_DEFAULT;
 245 
 246             crm_debug("Could not parse floating-point value from '%s' (using "
 247                       "%.1f instead): %s", text, PCMK__PARSE_DBL_DEFAULT,
 248                       pcmk_rc_str(rc));
 249 
 250         } else if (local_end_text == text) {
 251             
 252             rc = EINVAL;
 253             *result = PCMK__PARSE_DBL_DEFAULT;
 254 
 255             crm_debug("Could not parse floating-point value from '%s' (using "
 256                       "%.1f instead): No digits found", text,
 257                       PCMK__PARSE_DBL_DEFAULT);
 258 
 259         } else if (fabs(*result) <= DBL_MIN) {
 260             
 261 
 262 
 263 
 264 
 265 
 266 
 267 
 268 
 269 
 270 
 271 
 272             for (const char *p = text; p != local_end_text; p++) {
 273                 if (strchr("0.eE", *p) == NULL) {
 274                     rc = pcmk_rc_underflow;
 275                     crm_debug("Floating-point value parsed from '%s' would "
 276                               "underflow (using %g instead)", text, *result);
 277                     break;
 278                 }
 279             }
 280 
 281         } else {
 282             crm_trace("Floating-point value parsed successfully from "
 283                       "'%s': %g", text, *result);
 284         }
 285 
 286         if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
 287             crm_debug("Characters left over after parsing '%s': '%s'",
 288                       text, local_end_text);
 289         }
 290     }
 291 
 292     if (end_text != NULL) {
 293         *end_text = local_end_text;
 294     }
 295 
 296     return rc;
 297 }
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 
 310 int
 311 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
     
 312                       guint *result)
 313 {
 314     const char *value;
 315     long long value_ll;
 316     int rc = pcmk_rc_ok;
 317 
 318     CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
 319 
 320     if (result != NULL) {
 321         *result = default_val;
 322     }
 323 
 324     value = g_hash_table_lookup(table, key);
 325     if (value == NULL) {
 326         return pcmk_rc_ok;
 327     }
 328 
 329     rc = pcmk__scan_ll(value, &value_ll, 0LL);
 330     if (rc != pcmk_rc_ok) {
 331         return rc;
 332     }
 333 
 334     if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
 335         crm_warn("Could not parse non-negative integer from %s", value);
 336         return ERANGE;
 337     }
 338 
 339     if (result != NULL) {
 340         *result = (guint) value_ll;
 341     }
 342     return pcmk_rc_ok;
 343 }
 344 
 345 #ifndef NUMCHARS
 346 #  define       NUMCHARS        "0123456789."
 347 #endif
 348 
 349 #ifndef WHITESPACE
 350 #  define       WHITESPACE      " \t\n\r\f"
 351 #endif
 352 
 353 
 354 
 355 
 356 
 357 
 358 
 359 
 360 
 361 
 362 
 363 long long
 364 crm_get_msec(const char *input)
     
 365 {
 366     const char *num_start = NULL;
 367     const char *units;
 368     long long multiplier = 1000;
 369     long long divisor = 1;
 370     long long msec = PCMK__PARSE_INT_DEFAULT;
 371     size_t num_len = 0;
 372     char *end_text = NULL;
 373 
 374     if (input == NULL) {
 375         return PCMK__PARSE_INT_DEFAULT;
 376     }
 377 
 378     num_start = input + strspn(input, WHITESPACE);
 379     num_len = strspn(num_start, NUMCHARS);
 380     if (num_len < 1) {
 381         return PCMK__PARSE_INT_DEFAULT;
 382     }
 383     units = num_start + num_len;
 384     units += strspn(units, WHITESPACE);
 385 
 386     if (!strncasecmp(units, "ms", 2) || !strncasecmp(units, "msec", 4)) {
 387         multiplier = 1;
 388         divisor = 1;
 389     } else if (!strncasecmp(units, "us", 2) || !strncasecmp(units, "usec", 4)) {
 390         multiplier = 1;
 391         divisor = 1000;
 392     } else if (!strncasecmp(units, "s", 1) || !strncasecmp(units, "sec", 3)) {
 393         multiplier = 1000;
 394         divisor = 1;
 395     } else if (!strncasecmp(units, "m", 1) || !strncasecmp(units, "min", 3)) {
 396         multiplier = 60 * 1000;
 397         divisor = 1;
 398     } else if (!strncasecmp(units, "h", 1) || !strncasecmp(units, "hr", 2)) {
 399         multiplier = 60 * 60 * 1000;
 400         divisor = 1;
 401     } else if ((*units != '\0') && (*units != '\n') && (*units != '\r')) {
 402         return PCMK__PARSE_INT_DEFAULT;
 403     }
 404 
 405     scan_ll(num_start, &msec, PCMK__PARSE_INT_DEFAULT, &end_text);
 406     if (msec > (LLONG_MAX / multiplier)) {
 407         
 408         return LLONG_MAX;
 409     }
 410     msec *= multiplier;
 411     msec /= divisor;
 412     return msec;
 413 }
 414 
 415 gboolean
 416 crm_is_true(const char *s)
     
 417 {
 418     gboolean ret = FALSE;
 419 
 420     if (s != NULL) {
 421         crm_str_to_boolean(s, &ret);
 422     }
 423     return ret;
 424 }
 425 
 426 int
 427 crm_str_to_boolean(const char *s, int *ret)
     
 428 {
 429     if (s == NULL) {
 430         return -1;
 431 
 432     } else if (strcasecmp(s, "true") == 0
 433                || strcasecmp(s, "on") == 0
 434                || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
 435         *ret = TRUE;
 436         return 1;
 437 
 438     } else if (strcasecmp(s, "false") == 0
 439                || strcasecmp(s, "off") == 0
 440                || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
 441         *ret = FALSE;
 442         return 1;
 443     }
 444     return -1;
 445 }
 446 
 447 
 448 
 449 
 450 
 451 
 452 
 453 
 454 
 455 char *
 456 pcmk__trim(char *str)
     
 457 {
 458     int len;
 459 
 460     if (str == NULL) {
 461         return str;
 462     }
 463 
 464     for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
 465         str[len] = '\0';
 466     }
 467 
 468     return str;
 469 }
 470 
 471 
 472 
 473 
 474 
 475 
 476 
 477 
 478 
 479 
 480 
 481 
 482 
 483 bool
 484 pcmk__starts_with(const char *str, const char *prefix)
     
 485 {
 486     const char *s = str;
 487     const char *p = prefix;
 488 
 489     if (!s || !p) {
 490         return false;
 491     }
 492     while (*s && *p) {
 493         if (*s++ != *p++) {
 494             return false;
 495         }
 496     }
 497     return (*p == 0);
 498 }
 499 
 500 static inline bool
 501 ends_with(const char *s, const char *match, bool as_extension)
     
 502 {
 503     if (pcmk__str_empty(match)) {
 504         return true;
 505     } else if (s == NULL) {
 506         return false;
 507     } else {
 508         size_t slen, mlen;
 509 
 510         
 511 
 512 
 513         if (as_extension) {
 514             s = strrchr(s, match[0]);
 515             return (s == NULL)? false : !strcmp(s, match);
 516         }
 517 
 518         mlen = strlen(match);
 519         slen = strlen(s);
 520         return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
 521     }
 522 }
 523 
 524 
 525 
 526 
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534 
 535 bool
 536 pcmk__ends_with(const char *s, const char *match)
     
 537 {
 538     return ends_with(s, match, false);
 539 }
 540 
 541 
 542 
 543 
 544 
 545 
 546 
 547 
 548 
 549 
 550 
 551 
 552 
 553 
 554 
 555 
 556 
 557 
 558 
 559 
 560 
 561 
 562 bool
 563 pcmk__ends_with_ext(const char *s, const char *match)
     
 564 {
 565     return ends_with(s, match, true);
 566 }
 567 
 568 
 569 
 570 
 571 
 572 
 573 
 574 
 575 
 576 
 577 
 578 
 579 
 580 
 581 
 582 
 583 
 584 
 585 
 586 
 587 static guint
 588 pcmk__str_hash(gconstpointer v)
     
 589 {
 590     const signed char *p;
 591     guint32 h = 0;
 592 
 593     for (p = v; *p != '\0'; p++)
 594         h = (h << 5) - h + *p;
 595 
 596     return h;
 597 }
 598 
 599 
 600 
 601 
 602 
 603 
 604 
 605 
 606 
 607 
 608 
 609 
 610 GHashTable *
 611 pcmk__strkey_table(GDestroyNotify key_destroy_func,
     
 612                    GDestroyNotify value_destroy_func)
 613 {
 614     return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
 615                                  key_destroy_func, value_destroy_func);
 616 }
 617 
 618 
 619 static gboolean
 620 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
     
 621 {
 622     return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
 623 }
 624 
 625 static guint
 626 pcmk__strcase_hash(gconstpointer v)
     
 627 {
 628     const signed char *p;
 629     guint32 h = 0;
 630 
 631     for (p = v; *p != '\0'; p++)
 632         h = (h << 5) - h + g_ascii_tolower(*p);
 633 
 634     return h;
 635 }
 636 
 637 
 638 
 639 
 640 
 641 
 642 
 643 
 644 
 645 
 646 
 647 
 648 GHashTable *
 649 pcmk__strikey_table(GDestroyNotify key_destroy_func,
     
 650                     GDestroyNotify value_destroy_func)
 651 {
 652     return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
 653                                  key_destroy_func, value_destroy_func);
 654 }
 655 
 656 static void
 657 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
     
 658 {
 659     if (key && value && user_data) {
 660         g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
 661     }
 662 }
 663 
 664 
 665 
 666 
 667 
 668 
 669 
 670 
 671 
 672 
 673 
 674 GHashTable *
 675 pcmk__str_table_dup(GHashTable *old_table)
     
 676 {
 677     GHashTable *new_table = NULL;
 678 
 679     if (old_table) {
 680         new_table = pcmk__strkey_table(free, free);
 681         g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
 682     }
 683     return new_table;
 684 }
 685 
 686 
 687 
 688 
 689 
 690 
 691 
 692 
 693 
 694 
 695 
 696 
 697 
 698 
 699 
 700 
 701 
 702 void
 703 pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
     
 704                          const char *separator)
 705 {
 706     CRM_ASSERT(list != NULL);
 707 
 708     if (pcmk__str_empty(word)) {
 709         return;
 710     }
 711 
 712     if (*list == NULL) {
 713         if (init_size > 0) {
 714             *list = g_string_sized_new(init_size);
 715         } else {
 716             *list = g_string_new(NULL);
 717         }
 718     }
 719 
 720     if ((*list)->len == 0) {
 721         
 722         separator = "";
 723 
 724     } else if (separator == NULL) {
 725         
 726         separator = " ";
 727     }
 728 
 729     g_string_append(*list, separator);
 730     g_string_append(*list, word);
 731 }
 732 
 733 
 734 
 735 
 736 
 737 
 738 
 739 
 740 
 741 
 742 
 743 
 744 
 745 int
 746 pcmk__compress(const char *data, unsigned int length, unsigned int max,
     
 747                char **result, unsigned int *result_len)
 748 {
 749     int rc;
 750     char *compressed = NULL;
 751     char *uncompressed = strdup(data);
 752 #ifdef CLOCK_MONOTONIC
 753     struct timespec after_t;
 754     struct timespec before_t;
 755 #endif
 756 
 757     if (max == 0) {
 758         max = (length * 1.01) + 601; 
 759     }
 760 
 761 #ifdef CLOCK_MONOTONIC
 762     clock_gettime(CLOCK_MONOTONIC, &before_t);
 763 #endif
 764 
 765     compressed = calloc((size_t) max, sizeof(char));
 766     CRM_ASSERT(compressed);
 767 
 768     *result_len = max;
 769     rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
 770                                   CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
 771     free(uncompressed);
 772     if (rc != BZ_OK) {
 773         crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
 774                 length, bz2_strerror(rc), rc);
 775         free(compressed);
 776         return pcmk_rc_error;
 777     }
 778 
 779 #ifdef CLOCK_MONOTONIC
 780     clock_gettime(CLOCK_MONOTONIC, &after_t);
 781 
 782     crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
 783              length, *result_len, length / (*result_len),
 784              (after_t.tv_sec - before_t.tv_sec) * 1000 +
 785              (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
 786 #else
 787     crm_trace("Compressed %d bytes into %d (ratio %d:1)",
 788              length, *result_len, length / (*result_len));
 789 #endif
 790 
 791     *result = compressed;
 792     return pcmk_rc_ok;
 793 }
 794 
 795 char *
 796 crm_strdup_printf(char const *format, ...)
     
 797 {
 798     va_list ap;
 799     int len = 0;
 800     char *string = NULL;
 801 
 802     va_start(ap, format);
 803     len = vasprintf (&string, format, ap);
 804     CRM_ASSERT(len > 0);
 805     va_end(ap);
 806     return string;
 807 }
 808 
 809 int
 810 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
     
 811 {
 812     char *remainder = NULL;
 813 
 814     CRM_ASSERT(start != NULL && end != NULL);
 815 
 816     *start = PCMK__PARSE_INT_DEFAULT;
 817     *end = PCMK__PARSE_INT_DEFAULT;
 818 
 819     crm_trace("Attempting to decode: [%s]", srcstring);
 820     if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
 821         return pcmk_rc_unknown_format;
 822     }
 823 
 824     
 825 
 826 
 827     if (*srcstring == '-') {
 828         int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
 829 
 830         if (rc != pcmk_rc_ok || *remainder != '\0') {
 831             return pcmk_rc_unknown_format;
 832         } else {
 833             return pcmk_rc_ok;
 834         }
 835     }
 836 
 837     if (scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT,
 838                 &remainder) != pcmk_rc_ok) {
 839         return pcmk_rc_unknown_format;
 840     }
 841 
 842     if (*remainder && *remainder == '-') {
 843         if (*(remainder+1)) {
 844             char *more_remainder = NULL;
 845             int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
 846                              &more_remainder);
 847 
 848             if (rc != pcmk_rc_ok || *more_remainder != '\0') {
 849                 return pcmk_rc_unknown_format;
 850             }
 851         }
 852     } else if (*remainder && *remainder != '-') {
 853         *start = PCMK__PARSE_INT_DEFAULT;
 854         return pcmk_rc_unknown_format;
 855     } else {
 856         
 857 
 858 
 859 
 860         *end = *start;
 861     }
 862 
 863     return pcmk_rc_ok;
 864 }
 865 
 866 
 867 
 868 
 869 
 870 
 871 
 872 
 873 
 874 
 875 
 876 
 877 
 878 
 879 
 880 
 881 
 882 gboolean
 883 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
     
 884 {
 885     for (const GList *ele = lst; ele != NULL; ele = ele->next) {
 886         if (pcmk__str_eq(s, ele->data, flags)) {
 887             return TRUE;
 888         }
 889     }
 890 
 891     return FALSE;
 892 }
 893 
 894 static bool
 895 str_any_of(const char *s, va_list args, uint32_t flags)
     
 896 {
 897     if (s == NULL) {
 898         return pcmk_is_set(flags, pcmk__str_null_matches);
 899     }
 900 
 901     while (1) {
 902         const char *ele = va_arg(args, const char *);
 903 
 904         if (ele == NULL) {
 905             break;
 906         } else if (pcmk__str_eq(s, ele, flags)) {
 907             return true;
 908         }
 909     }
 910 
 911     return false;
 912 }
 913 
 914 
 915 
 916 
 917 
 918 
 919 
 920 
 921 
 922 
 923 
 924 
 925 
 926 
 927 bool
 928 pcmk__strcase_any_of(const char *s, ...)
     
 929 {
 930     va_list ap;
 931     bool rc;
 932 
 933     va_start(ap, s);
 934     rc = str_any_of(s, ap, pcmk__str_casei);
 935     va_end(ap);
 936     return rc;
 937 }
 938 
 939 
 940 
 941 
 942 
 943 
 944 
 945 
 946 
 947 
 948 
 949 
 950 
 951 bool
 952 pcmk__str_any_of(const char *s, ...)
     
 953 {
 954     va_list ap;
 955     bool rc;
 956 
 957     va_start(ap, s);
 958     rc = str_any_of(s, ap, pcmk__str_none);
 959     va_end(ap);
 960     return rc;
 961 }
 962 
 963 
 964 
 965 
 966 
 967 
 968 
 969 
 970 
 971 
 972 
 973 
 974 bool
 975 pcmk__char_in_any_str(int ch, ...)
     
 976 {
 977     bool rc = false;
 978     va_list ap;
 979 
 980     
 981 
 982 
 983 
 984     va_start(ap, ch);
 985 
 986     while (1) {
 987         const char *ele = va_arg(ap, const char *);
 988 
 989         if (ele == NULL) {
 990             break;
 991         } else if (strchr(ele, ch) != NULL) {
 992             rc = true;
 993             break;
 994         }
 995     }
 996 
 997     va_end(ap);
 998     return rc;
 999 }
1000 
1001 
1002 
1003 
1004 
1005 
1006 
1007 
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 
1017 int
1018 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
     
1019 {
1020     CRM_ASSERT((s1 != NULL) && (s2 != NULL));
1021 
1022     while (*s1 && *s2) {
1023         if (isdigit(*s1) && isdigit(*s2)) {
1024             
1025 
1026             char *end1 = NULL;
1027             char *end2 = NULL;
1028             long num1 = strtol(s1, &end1, 10);
1029             long num2 = strtol(s2, &end2, 10);
1030 
1031             
1032             size_t len1 = end1 - s1;
1033             size_t len2 = end2 - s2;
1034 
1035             if (num1 < num2) {
1036                 return -1;
1037             } else if (num1 > num2) {
1038                 return 1;
1039             } else if (len1 < len2) {
1040                 return -1;
1041             } else if (len1 > len2) {
1042                 return 1;
1043             }
1044             s1 = end1;
1045             s2 = end2;
1046         } else {
1047             
1048             int lower1 = tolower(*s1);
1049             int lower2 = tolower(*s2);
1050 
1051             if (lower1 < lower2) {
1052                 return -1;
1053             } else if (lower1 > lower2) {
1054                 return 1;
1055             }
1056             ++s1;
1057             ++s2;
1058         }
1059     }
1060     if (!*s1 && *s2) {
1061         return -1;
1062     } else if (*s1 && !*s2) {
1063         return 1;
1064     }
1065     return 0;
1066 }
1067 
1068 
1069 
1070 
1071 
1072 
1073 
1074 
1075 
1076 
1077 
1078 
1079 
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 
1088 
1089 
1090 
1091 
1092 
1093 
1094 
1095 
1096 
1097 
1098 
1099 
1100 
1101 
1102 int
1103 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
     
1104 {
1105     
1106     if (pcmk_is_set(flags, pcmk__str_regex)) {
1107         regex_t r_patt;
1108         int reg_flags = REG_EXTENDED | REG_NOSUB;
1109         int regcomp_rc = 0;
1110         int rc = 0;
1111 
1112         if (s1 == NULL || s2 == NULL) {
1113             return 1;
1114         }
1115 
1116         if (pcmk_is_set(flags, pcmk__str_casei)) {
1117             reg_flags |= REG_ICASE;
1118         }
1119         regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1120         if (regcomp_rc != 0) {
1121             rc = 1;
1122             crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1123         } else {
1124             rc = regexec(&r_patt, s1, 0, NULL, 0);
1125 
1126             if (rc != 0) {
1127                 rc = 1;
1128             }
1129         }
1130 
1131         regfree(&r_patt);
1132         return rc;
1133     }
1134 
1135     
1136     if (s1 == s2) {
1137         return 0;
1138     }
1139 
1140     
1141 
1142 
1143 
1144     if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1145         if (s1 == NULL || s2 == NULL) {
1146             return 0;
1147         }
1148     }
1149 
1150     
1151 
1152 
1153     if (s1 == NULL) {
1154         return -1;
1155     } else if (s2 == NULL) {
1156         return 1;
1157     }
1158 
1159     
1160 
1161 
1162 
1163     if (pcmk_is_set(flags, pcmk__str_star_matches)) {
1164         if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1165             return 0;
1166         }
1167     }
1168 
1169     if (pcmk_is_set(flags, pcmk__str_casei)) {
1170         return strcasecmp(s1, s2);
1171     } else {
1172         return strcmp(s1, s2);
1173     }
1174 }
1175 
1176 
1177 
1178 
1179 
1180 
1181 
1182 
1183 
1184 
1185 
1186 
1187 
1188 
1189 void
1190 pcmk__str_update(char **str, const char *value)
     
1191 {
1192     if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1193         free(*str);
1194         if (value == NULL) {
1195             *str = NULL;
1196         } else {
1197             *str = strdup(value);
1198             CRM_ASSERT(*str != NULL);
1199         }
1200     }
1201 }
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1209 
1210 
1211 
1212 
1213 void
1214 pcmk__g_strcat(GString *buffer, ...)
     
1215 {
1216     va_list ap;
1217 
1218     CRM_ASSERT(buffer != NULL);
1219     va_start(ap, buffer);
1220 
1221     while (true) {
1222         const char *ele = va_arg(ap, const char *);
1223 
1224         if (ele == NULL) {
1225             break;
1226         }
1227         g_string_append(buffer, ele);
1228     }
1229     va_end(ap);
1230 }
1231 
1232 
1233 
1234 
1235 #include <crm/common/util_compat.h>
1236 
1237 gboolean
1238 safe_str_neq(const char *a, const char *b)
     
1239 {
1240     if (a == b) {
1241         return FALSE;
1242 
1243     } else if (a == NULL || b == NULL) {
1244         return TRUE;
1245 
1246     } else if (strcasecmp(a, b) == 0) {
1247         return FALSE;
1248     }
1249     return TRUE;
1250 }
1251 
1252 gboolean
1253 crm_str_eq(const char *a, const char *b, gboolean use_case)
     
1254 {
1255     if (use_case) {
1256         return g_strcmp0(a, b) == 0;
1257 
1258         
1259     } else if (a == b) {
1260         return TRUE;
1261 
1262     } else if (a == NULL || b == NULL) {
1263         
1264         return FALSE;
1265 
1266     } else if (strcasecmp(a, b) == 0) {
1267         return TRUE;
1268     }
1269     return FALSE;
1270 }
1271 
1272 char *
1273 crm_itoa_stack(int an_int, char *buffer, size_t len)
     
1274 {
1275     if (buffer != NULL) {
1276         snprintf(buffer, len, "%d", an_int);
1277     }
1278     return buffer;
1279 }
1280 
1281 guint
1282 g_str_hash_traditional(gconstpointer v)
     
1283 {
1284     return pcmk__str_hash(v);
1285 }
1286 
1287 gboolean
1288 crm_strcase_equal(gconstpointer a, gconstpointer b)
     
1289 {
1290     return pcmk__strcase_equal(a, b);
1291 }
1292 
1293 guint
1294 crm_strcase_hash(gconstpointer v)
     
1295 {
1296     return pcmk__strcase_hash(v);
1297 }
1298 
1299 GHashTable *
1300 crm_str_table_dup(GHashTable *old_table)
     
1301 {
1302     return pcmk__str_table_dup(old_table);
1303 }
1304 
1305 long long
1306 crm_parse_ll(const char *text, const char *default_text)
     
1307 {
1308     long long result;
1309 
1310     if (text == NULL) {
1311         text = default_text;
1312         if (text == NULL) {
1313             crm_err("No default conversion value supplied");
1314             errno = EINVAL;
1315             return PCMK__PARSE_INT_DEFAULT;
1316         }
1317     }
1318     scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1319     return result;
1320 }
1321 
1322 int
1323 crm_parse_int(const char *text, const char *default_text)
     
1324 {
1325     long long result = crm_parse_ll(text, default_text);
1326 
1327     if (result < INT_MIN) {
1328         
1329         if (errno != ERANGE) {
1330             crm_err("Conversion of %s was clipped: %lld", text, result);
1331             errno = ERANGE;
1332         }
1333         return INT_MIN;
1334 
1335     } else if (result > INT_MAX) {
1336         
1337         if (errno != ERANGE) {
1338             crm_err("Conversion of %s was clipped: %lld", text, result);
1339             errno = ERANGE;
1340         }
1341         return INT_MAX;
1342     }
1343 
1344     return (int) result;
1345 }
1346 
1347 char *
1348 crm_strip_trailing_newline(char *str)
     
1349 {
1350     return pcmk__trim(str);
1351 }
1352 
1353 int
1354 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
     
1355 {
1356     return pcmk__numeric_strcasecmp(s1, s2);
1357 }
1358 
1359 
1360