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
 
- 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(char **list, size_t *len, const char *word,
     
 704                          const char *separator)
 705 {
 706     size_t orig_len, new_len;
 707 
 708     CRM_ASSERT(list != NULL);
 709 
 710     if (pcmk__str_empty(word)) {
 711         return;
 712     }
 713 
 714     
 715     orig_len = (len != NULL)? *len : ((*list == NULL)? 0 : strlen(*list));
 716 
 717     
 718     if (orig_len == 0) {
 719         separator = "";
 720 
 721     
 722     } else if (separator == NULL) {
 723         separator = " ";
 724     }
 725 
 726     new_len = orig_len + strlen(separator) + strlen(word);
 727     if (len != NULL) {
 728         *len = new_len;
 729     }
 730 
 731     
 732     *list = pcmk__realloc(*list, new_len + 1);
 733     sprintf(*list + orig_len, "%s%s", separator, word);
 734 }
 735 
 736 
 737 
 738 
 739 
 740 
 741 
 742 
 743 
 744 
 745 
 746 
 747 
 748 int
 749 pcmk__compress(const char *data, unsigned int length, unsigned int max,
     
 750                char **result, unsigned int *result_len)
 751 {
 752     int rc;
 753     char *compressed = NULL;
 754     char *uncompressed = strdup(data);
 755 #ifdef CLOCK_MONOTONIC
 756     struct timespec after_t;
 757     struct timespec before_t;
 758 #endif
 759 
 760     if (max == 0) {
 761         max = (length * 1.01) + 601; 
 762     }
 763 
 764 #ifdef CLOCK_MONOTONIC
 765     clock_gettime(CLOCK_MONOTONIC, &before_t);
 766 #endif
 767 
 768     compressed = calloc((size_t) max, sizeof(char));
 769     CRM_ASSERT(compressed);
 770 
 771     *result_len = max;
 772     rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
 773                                   CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
 774     free(uncompressed);
 775     if (rc != BZ_OK) {
 776         crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
 777                 length, bz2_strerror(rc), rc);
 778         free(compressed);
 779         return pcmk_rc_error;
 780     }
 781 
 782 #ifdef CLOCK_MONOTONIC
 783     clock_gettime(CLOCK_MONOTONIC, &after_t);
 784 
 785     crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
 786              length, *result_len, length / (*result_len),
 787              (after_t.tv_sec - before_t.tv_sec) * 1000 +
 788              (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
 789 #else
 790     crm_trace("Compressed %d bytes into %d (ratio %d:1)",
 791              length, *result_len, length / (*result_len));
 792 #endif
 793 
 794     *result = compressed;
 795     return pcmk_rc_ok;
 796 }
 797 
 798 char *
 799 crm_strdup_printf(char const *format, ...)
     
 800 {
 801     va_list ap;
 802     int len = 0;
 803     char *string = NULL;
 804 
 805     va_start(ap, format);
 806     len = vasprintf (&string, format, ap);
 807     CRM_ASSERT(len > 0);
 808     va_end(ap);
 809     return string;
 810 }
 811 
 812 int
 813 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
     
 814 {
 815     char *remainder = NULL;
 816 
 817     CRM_ASSERT(start != NULL && end != NULL);
 818 
 819     *start = PCMK__PARSE_INT_DEFAULT;
 820     *end = PCMK__PARSE_INT_DEFAULT;
 821 
 822     crm_trace("Attempting to decode: [%s]", srcstring);
 823     if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
 824         return pcmk_rc_unknown_format;
 825     }
 826 
 827     
 828 
 829 
 830     if (*srcstring == '-') {
 831         int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
 832 
 833         if (rc != pcmk_rc_ok || *remainder != '\0') {
 834             return pcmk_rc_unknown_format;
 835         } else {
 836             return pcmk_rc_ok;
 837         }
 838     }
 839 
 840     if (scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT,
 841                 &remainder) != pcmk_rc_ok) {
 842         return pcmk_rc_unknown_format;
 843     }
 844 
 845     if (*remainder && *remainder == '-') {
 846         if (*(remainder+1)) {
 847             char *more_remainder = NULL;
 848             int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
 849                              &more_remainder);
 850 
 851             if (rc != pcmk_rc_ok || *more_remainder != '\0') {
 852                 return pcmk_rc_unknown_format;
 853             }
 854         }
 855     } else if (*remainder && *remainder != '-') {
 856         *start = PCMK__PARSE_INT_DEFAULT;
 857         return pcmk_rc_unknown_format;
 858     } else {
 859         
 860 
 861 
 862 
 863         *end = *start;
 864     }
 865 
 866     return pcmk_rc_ok;
 867 }
 868 
 869 
 870 
 871 
 872 
 873 
 874 
 875 
 876 
 877 
 878 
 879 
 880 
 881 
 882 
 883 
 884 
 885 gboolean
 886 pcmk__str_in_list(const gchar *s, GList *lst, uint32_t flags)
     
 887 {
 888     for (GList *ele = lst; ele != NULL; ele = ele->next) {
 889         if (pcmk__str_eq(s, ele->data, flags)) {
 890             return TRUE;
 891         }
 892     }
 893 
 894     return FALSE;
 895 }
 896 
 897 static bool
 898 str_any_of(const char *s, va_list args, uint32_t flags)
     
 899 {
 900     if (s == NULL) {
 901         return pcmk_is_set(flags, pcmk__str_null_matches);
 902     }
 903 
 904     while (1) {
 905         const char *ele = va_arg(args, const char *);
 906 
 907         if (ele == NULL) {
 908             break;
 909         } else if (pcmk__str_eq(s, ele, flags)) {
 910             return true;
 911         }
 912     }
 913 
 914     return false;
 915 }
 916 
 917 
 918 
 919 
 920 
 921 
 922 
 923 
 924 
 925 
 926 
 927 
 928 
 929 
 930 bool
 931 pcmk__strcase_any_of(const char *s, ...)
     
 932 {
 933     va_list ap;
 934     bool rc;
 935 
 936     va_start(ap, s);
 937     rc = str_any_of(s, ap, pcmk__str_casei);
 938     va_end(ap);
 939     return rc;
 940 }
 941 
 942 
 943 
 944 
 945 
 946 
 947 
 948 
 949 
 950 
 951 
 952 
 953 
 954 bool
 955 pcmk__str_any_of(const char *s, ...)
     
 956 {
 957     va_list ap;
 958     bool rc;
 959 
 960     va_start(ap, s);
 961     rc = str_any_of(s, ap, pcmk__str_none);
 962     va_end(ap);
 963     return rc;
 964 }
 965 
 966 
 967 
 968 
 969 
 970 
 971 
 972 
 973 
 974 
 975 
 976 
 977 bool
 978 pcmk__char_in_any_str(int ch, ...)
     
 979 {
 980     bool rc = false;
 981     va_list ap;
 982 
 983     
 984 
 985 
 986 
 987     va_start(ap, ch);
 988 
 989     while (1) {
 990         const char *ele = va_arg(ap, const char *);
 991 
 992         if (ele == NULL) {
 993             break;
 994         } else if (strchr(ele, ch) != NULL) {
 995             rc = true;
 996             break;
 997         }
 998     }
 999 
1000     va_end(ap);
1001     return rc;
1002 }
1003 
1004 
1005 
1006 
1007 
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 
1017 
1018 
1019 
1020 int
1021 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
     
1022 {
1023     while (*s1 && *s2) {
1024         if (isdigit(*s1) && isdigit(*s2)) {
1025             
1026 
1027             char *end1 = NULL;
1028             char *end2 = NULL;
1029             long num1 = strtol(s1, &end1, 10);
1030             long num2 = strtol(s2, &end2, 10);
1031 
1032             
1033             size_t len1 = end1 - s1;
1034             size_t len2 = end2 - s2;
1035 
1036             if (num1 < num2) {
1037                 return -1;
1038             } else if (num1 > num2) {
1039                 return 1;
1040             } else if (len1 < len2) {
1041                 return -1;
1042             } else if (len1 > len2) {
1043                 return 1;
1044             }
1045             s1 = end1;
1046             s2 = end2;
1047         } else {
1048             
1049             int lower1 = tolower(*s1);
1050             int lower2 = tolower(*s2);
1051 
1052             if (lower1 < lower2) {
1053                 return -1;
1054             } else if (lower1 > lower2) {
1055                 return 1;
1056             }
1057             ++s1;
1058             ++s2;
1059         }
1060     }
1061     if (!*s1 && *s2) {
1062         return -1;
1063     } else if (*s1 && !*s2) {
1064         return 1;
1065     }
1066     return 0;
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 int
1101 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
     
1102 {
1103     
1104     if (pcmk_is_set(flags, pcmk__str_regex)) {
1105         regex_t r_patt;
1106         int reg_flags = REG_EXTENDED | REG_NOSUB;
1107         int regcomp_rc = 0;
1108         int rc = 0;
1109 
1110         if (s1 == NULL || s2 == NULL) {
1111             return 1;
1112         }
1113 
1114         if (pcmk_is_set(flags, pcmk__str_casei)) {
1115             reg_flags |= REG_ICASE;
1116         }
1117         regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1118         if (regcomp_rc != 0) {
1119             rc = 1;
1120             crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1121         } else {
1122             rc = regexec(&r_patt, s1, 0, NULL, 0);
1123 
1124             if (rc != 0) {
1125                 rc = 1;
1126             }
1127         }
1128 
1129         regfree(&r_patt);
1130         return rc;
1131     }
1132 
1133     
1134     if (s1 == s2) {
1135         return 0;
1136     }
1137 
1138     
1139 
1140 
1141 
1142     if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1143         if (s1 == NULL || s2 == NULL) {
1144             return 0;
1145         }
1146     }
1147 
1148     
1149 
1150 
1151     if (s1 == NULL) {
1152         return -1;
1153     } else if (s2 == NULL) {
1154         return 1;
1155     }
1156 
1157     
1158 
1159 
1160 
1161     if (pcmk_is_set(flags, pcmk__str_star_matches)) {
1162         if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1163             return 0;
1164         }
1165     }
1166 
1167     if (pcmk_is_set(flags, pcmk__str_casei)) {
1168         return strcasecmp(s1, s2);
1169     } else {
1170         return strcmp(s1, s2);
1171     }
1172 }
1173 
1174 
1175 
1176 
1177 
1178 
1179 
1180 
1181 
1182 
1183 
1184 
1185 
1186 
1187 void
1188 pcmk__str_update(char **str, const char *value)
     
1189 {
1190     if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1191         free(*str);
1192         if (value == NULL) {
1193             *str = NULL;
1194         } else {
1195             *str = strdup(value);
1196             CRM_ASSERT(*str != NULL);
1197         }
1198     }
1199 }
1200 
1201 
1202 
1203 
1204 #include <crm/common/util_compat.h>
1205 
1206 gboolean
1207 safe_str_neq(const char *a, const char *b)
     
1208 {
1209     if (a == b) {
1210         return FALSE;
1211 
1212     } else if (a == NULL || b == NULL) {
1213         return TRUE;
1214 
1215     } else if (strcasecmp(a, b) == 0) {
1216         return FALSE;
1217     }
1218     return TRUE;
1219 }
1220 
1221 gboolean
1222 crm_str_eq(const char *a, const char *b, gboolean use_case)
     
1223 {
1224     if (use_case) {
1225         return g_strcmp0(a, b) == 0;
1226 
1227         
1228     } else if (a == b) {
1229         return TRUE;
1230 
1231     } else if (a == NULL || b == NULL) {
1232         
1233         return FALSE;
1234 
1235     } else if (strcasecmp(a, b) == 0) {
1236         return TRUE;
1237     }
1238     return FALSE;
1239 }
1240 
1241 char *
1242 crm_itoa_stack(int an_int, char *buffer, size_t len)
     
1243 {
1244     if (buffer != NULL) {
1245         snprintf(buffer, len, "%d", an_int);
1246     }
1247     return buffer;
1248 }
1249 
1250 guint
1251 g_str_hash_traditional(gconstpointer v)
     
1252 {
1253     return pcmk__str_hash(v);
1254 }
1255 
1256 gboolean
1257 crm_strcase_equal(gconstpointer a, gconstpointer b)
     
1258 {
1259     return pcmk__strcase_equal(a, b);
1260 }
1261 
1262 guint
1263 crm_strcase_hash(gconstpointer v)
     
1264 {
1265     return pcmk__strcase_hash(v);
1266 }
1267 
1268 GHashTable *
1269 crm_str_table_dup(GHashTable *old_table)
     
1270 {
1271     return pcmk__str_table_dup(old_table);
1272 }
1273 
1274 long long
1275 crm_parse_ll(const char *text, const char *default_text)
     
1276 {
1277     long long result;
1278 
1279     if (text == NULL) {
1280         text = default_text;
1281         if (text == NULL) {
1282             crm_err("No default conversion value supplied");
1283             errno = EINVAL;
1284             return PCMK__PARSE_INT_DEFAULT;
1285         }
1286     }
1287     scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1288     return result;
1289 }
1290 
1291 int
1292 crm_parse_int(const char *text, const char *default_text)
     
1293 {
1294     long long result = crm_parse_ll(text, default_text);
1295 
1296     if (result < INT_MIN) {
1297         
1298         if (errno != ERANGE) {
1299             crm_err("Conversion of %s was clipped: %lld", text, result);
1300             errno = ERANGE;
1301         }
1302         return INT_MIN;
1303 
1304     } else if (result > INT_MAX) {
1305         
1306         if (errno != ERANGE) {
1307             crm_err("Conversion of %s was clipped: %lld", text, result);
1308             errno = ERANGE;
1309         }
1310         return INT_MAX;
1311     }
1312 
1313     return (int) result;
1314 }
1315 
1316 char *
1317 crm_strip_trailing_newline(char *str)
     
1318 {
1319     return pcmk__trim(str);
1320 }
1321 
1322 int
1323 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
     
1324 {
1325     return pcmk__numeric_strcasecmp(s1, s2);
1326 }
1327 
1328 
1329