root/lib/common/strings.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scan_ll
  2. pcmk__scan_ll
  3. pcmk__scan_min_int
  4. pcmk__scan_port
  5. pcmk__scan_double
  6. pcmk__guint_from_hash
  7. crm_get_msec
  8. pcmk_parse_interval_spec
  9. crm_is_true
  10. crm_str_to_boolean
  11. pcmk__trim
  12. pcmk__starts_with
  13. ends_with
  14. pcmk__ends_with
  15. pcmk__ends_with_ext
  16. pcmk__str_hash
  17. pcmk__strkey_table
  18. pcmk__insert_dup
  19. pcmk__strcase_equal
  20. pcmk__strcase_hash
  21. pcmk__strikey_table
  22. copy_str_table_entry
  23. pcmk__str_table_dup
  24. pcmk__add_separated_word
  25. pcmk__compress
  26. crm_strdup_printf
  27. pcmk__parse_ll_range
  28. pcmk__str_in_list
  29. str_any_of
  30. pcmk__strcase_any_of
  31. pcmk__str_any_of
  32. pcmk__numeric_strcasecmp
  33. pcmk__strcmp
  34. pcmk__str_copy_as
  35. pcmk__str_update
  36. pcmk__g_strcat
  37. safe_str_neq
  38. crm_str_eq
  39. crm_itoa_stack
  40. g_str_hash_traditional
  41. crm_strcase_equal
  42. crm_strcase_hash
  43. crm_str_table_dup
  44. crm_parse_ll
  45. crm_parse_int
  46. crm_strip_trailing_newline
  47. pcmk_numeric_strcasecmp

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include "crm/common/results.h"
  11 #include <crm_internal.h>
  12 
  13 #ifndef _GNU_SOURCE
  14 #  define _GNU_SOURCE
  15 #endif
  16 
  17 #include <regex.h>
  18 #include <stdio.h>
  19 #include <string.h>
  20 #include <stdlib.h>
  21 #include <ctype.h>
  22 #include <float.h>  // DBL_MIN
  23 #include <limits.h>
  24 #include <bzlib.h>
  25 #include <sys/types.h>
  26 
  27 /*!
  28  * \internal
  29  * \brief Scan a long long integer from a string
  30  *
  31  * \param[in]  text           String to scan
  32  * \param[out] result         If not NULL, where to store scanned value
  33  * \param[in]  default_value  Value to use if text is NULL or invalid
  34  * \param[out] end_text       If not NULL, where to store pointer to first
  35  *                            non-integer character
  36  *
  37  * \return Standard Pacemaker return code (\c pcmk_rc_ok on success,
  38  *         \c EINVAL on failed string conversion due to invalid input,
  39  *         or \c EOVERFLOW on arithmetic overflow)
  40  * \note Sets \c errno on error
  41  */
  42 static int
  43 scan_ll(const char *text, long long *result, long long default_value,
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * \internal
  88  * \brief Scan a long long integer value from a string
  89  *
  90  * \param[in]  text           The string to scan (may be NULL)
  91  * \param[out] result         Where to store result (or NULL to ignore)
  92  * \param[in]  default_value  Value to use if text is NULL or invalid
  93  *
  94  * \return Standard Pacemaker return code
  95  */
  96 int
  97 pcmk__scan_ll(const char *text, long long *result, long long default_value)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * \internal
 116  * \brief Scan an integer value from a string, constrained to a minimum
 117  *
 118  * \param[in]  text           The string to scan (may be NULL)
 119  * \param[out] result         Where to store result (or NULL to ignore)
 120  * \param[in]  minimum        Value to use as default and minimum
 121  *
 122  * \return Standard Pacemaker return code
 123  * \note If the value is larger than the maximum integer, EOVERFLOW will be
 124  *       returned and \p result will be set to the maximum integer.
 125  */
 126 int
 127 pcmk__scan_min_int(const char *text, int *result, int minimum)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * \internal
 152  * \brief Scan a TCP port number from a string
 153  *
 154  * \param[in]  text  The string to scan
 155  * \param[out] port  Where to store result (or NULL to ignore)
 156  *
 157  * \return Standard Pacemaker return code
 158  * \note \p port will be -1 if \p text is NULL or invalid
 159  */
 160 int
 161 pcmk__scan_port(const char *text, int *port)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) // wasn't default or invalid
 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  * \internal
 181  * \brief Scan a double-precision floating-point value from a string
 182  *
 183  * \param[in]      text         The string to parse
 184  * \param[out]     result       Parsed value on success, or
 185  *                              \c PCMK__PARSE_DBL_DEFAULT on error
 186  * \param[in]      default_text Default string to parse if \p text is
 187  *                              \c NULL
 188  * \param[out]     end_text     If not \c NULL, where to store a pointer
 189  *                              to the position immediately after the
 190  *                              value
 191  *
 192  * \return Standard Pacemaker return code (\c pcmk_rc_ok on success,
 193  *         \c EINVAL on failed string conversion due to invalid input,
 194  *         \c EOVERFLOW on arithmetic overflow, \c pcmk_rc_underflow
 195  *         on arithmetic underflow, or \c errno from \c strtod() on
 196  *         other parse errors)
 197  */
 198 int
 199 pcmk__scan_double(const char *text, double *result, const char *default_text,
     /* [previous][next][first][last][top][bottom][index][help] */
 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              * Overflow: strtod() returns +/- HUGE_VAL and sets errno to
 221              *           ERANGE
 222              *
 223              * Underflow: strtod() returns "a value whose magnitude is
 224              *            no greater than the smallest normalized
 225              *            positive" double. Whether ERANGE is set is
 226              *            implementation-defined.
 227              */
 228             const char *over_under;
 229 
 230             if (QB_ABS(*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             // strtod() set *result = 0 on parse failure
 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             // errno == 0, but nothing was parsed
 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 (QB_ABS(*result) <= DBL_MIN) {
 260             /*
 261              * errno == 0 and text was parsed, but value might have
 262              * underflowed.
 263              *
 264              * ERANGE might not be set for underflow. Check magnitude
 265              * of *result, but also make sure the input number is not
 266              * actually zero (0 <= DBL_MIN is not underflow).
 267              *
 268              * This check must come last. A parse failure in strtod()
 269              * also sets *result == 0, so a parse failure would match
 270              * this test condition prematurely.
 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  * \internal
 301  * \brief Parse a guint from a string stored in a hash table
 302  *
 303  * \param[in]     table        Hash table to search
 304  * \param[in]     key          Hash table key to use to retrieve string
 305  * \param[in]     default_val  What to use if key has no entry in table
 306  * \param[out]    result       If not NULL, where to store parsed integer
 307  *
 308  * \return Standard Pacemaker return code
 309  */
 310 int
 311 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /*!
 346  * \brief Parse a time+units string and return milliseconds equivalent
 347  *
 348  * \param[in] input  String with a nonnegative number and optional unit
 349  *                   (optionally with whitespace before and/or after the
 350  *                   number). If missing, the unit defaults to seconds.
 351  *
 352  * \return Milliseconds corresponding to string expression, or
 353  *         \c PCMK__PARSE_INT_DEFAULT on error
 354  */
 355 long long
 356 crm_get_msec(const char *input)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358     char *units = NULL; // Do not free; will point to part of input
 359     long long multiplier = 1000;
 360     long long divisor = 1;
 361     long long msec = PCMK__PARSE_INT_DEFAULT;
 362 
 363     if (input == NULL) {
 364         return PCMK__PARSE_INT_DEFAULT;
 365     }
 366 
 367     // Skip initial whitespace
 368     while (isspace(*input)) {
 369         input++;
 370     }
 371 
 372     // Reject negative and unparsable inputs
 373     scan_ll(input, &msec, -1, &units);
 374     if (msec < 0) {
 375         return PCMK__PARSE_INT_DEFAULT;
 376     }
 377 
 378     /* If the number is a decimal, scan_ll() reads only the integer part. Skip
 379      * any remaining digits or decimal characters.
 380      *
 381      * @COMPAT Well-formed and malformed decimals are both accepted inputs. For
 382      * example, "3.14 ms" and "3.1.4 ms" are treated the same as "3ms" and
 383      * parsed successfully. At a compatibility break, decide if this is still
 384      * desired.
 385      */
 386     while (isdigit(*units) || (*units == '.')) {
 387         units++;
 388     }
 389 
 390     // Skip any additional whitespace after the number
 391     while (isspace(*units)) {
 392         units++;
 393     }
 394 
 395     /* @COMPAT Use exact comparisons. Currently, we match too liberally, and the
 396      * second strncasecmp() in each case is redundant.
 397      */
 398     if ((*units == '\0')
 399         || (strncasecmp(units, "s", 1) == 0)
 400         || (strncasecmp(units, "sec", 3) == 0)) {
 401         multiplier = 1000;
 402         divisor = 1;
 403 
 404     } else if ((strncasecmp(units, "ms", 2) == 0)
 405                || (strncasecmp(units, "msec", 4) == 0)) {
 406         multiplier = 1;
 407         divisor = 1;
 408 
 409     } else if ((strncasecmp(units, "us", 2) == 0)
 410                || (strncasecmp(units, "usec", 4) == 0)) {
 411         multiplier = 1;
 412         divisor = 1000;
 413 
 414     } else if ((strncasecmp(units, "m", 1) == 0)
 415                || (strncasecmp(units, "min", 3) == 0)) {
 416         multiplier = 60 * 1000;
 417         divisor = 1;
 418 
 419     } else if ((strncasecmp(units, "h", 1) == 0)
 420                || (strncasecmp(units, "hr", 2) == 0)) {
 421         multiplier = 60 * 60 * 1000;
 422         divisor = 1;
 423 
 424     } else {
 425         // Invalid units
 426         return PCMK__PARSE_INT_DEFAULT;
 427     }
 428 
 429     // Apply units, capping at LLONG_MAX
 430     if (msec > (LLONG_MAX / multiplier)) {
 431         return LLONG_MAX;
 432     }
 433     return (msec * multiplier) / divisor;
 434 }
 435 
 436 /*!
 437  * \brief Parse milliseconds from a Pacemaker interval specification
 438  *
 439  * \param[in]  input      Pacemaker time interval specification (a bare number
 440  *                        of seconds; a number with a unit, optionally with
 441  *                        whitespace before and/or after the number; or an ISO
 442  *                        8601 duration)
 443  * \param[out] result_ms  Where to store milliseconds equivalent of \p input on
 444  *                        success (limited to the range of an unsigned integer),
 445  *                        or 0 if \p input is \c NULL or invalid
 446  *
 447  * \return Standard Pacemaker return code (specifically, \c pcmk_rc_ok if
 448  *         \p input is valid or \c NULL, and \c EINVAL otherwise)
 449  */
 450 int
 451 pcmk_parse_interval_spec(const char *input, guint *result_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453     long long msec = PCMK__PARSE_INT_DEFAULT;
 454     int rc = pcmk_rc_ok;
 455 
 456     if (input == NULL) {
 457         msec = 0;
 458         goto done;
 459     }
 460 
 461     if (input[0] == 'P') {
 462         crm_time_t *period_s = crm_time_parse_duration(input);
 463 
 464         if (period_s != NULL) {
 465             msec = 1000 * crm_time_get_seconds(period_s);
 466             crm_time_free(period_s);
 467         }
 468 
 469     } else {
 470         msec = crm_get_msec(input);
 471     }
 472 
 473     if (msec == PCMK__PARSE_INT_DEFAULT) {
 474         crm_warn("Using 0 instead of invalid interval specification '%s'",
 475                  input);
 476         msec = 0;
 477         rc = EINVAL;
 478     }
 479 
 480 done:
 481     if (result_ms != NULL) {
 482         *result_ms = (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
 483     }
 484     return rc;
 485 }
 486 
 487 gboolean
 488 crm_is_true(const char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490     gboolean ret = FALSE;
 491 
 492     return (crm_str_to_boolean(s, &ret) < 0)? FALSE : ret;
 493 }
 494 
 495 int
 496 crm_str_to_boolean(const char *s, int *ret)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498     if (s == NULL) {
 499         return -1;
 500     }
 501 
 502     if (pcmk__strcase_any_of(s, PCMK_VALUE_TRUE, "on", "yes", "y", "1", NULL)) {
 503         if (ret != NULL) {
 504             *ret = TRUE;
 505         }
 506         return 1;
 507     }
 508 
 509     if (pcmk__strcase_any_of(s, PCMK_VALUE_FALSE, "off", "no", "n", "0",
 510                              NULL)) {
 511         if (ret != NULL) {
 512             *ret = FALSE;
 513         }
 514         return 1;
 515     }
 516     return -1;
 517 }
 518 
 519 /*!
 520  * \internal
 521  * \brief Replace any trailing newlines in a string with \0's
 522  *
 523  * \param[in,out] str  String to trim
 524  *
 525  * \return \p str
 526  */
 527 char *
 528 pcmk__trim(char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530     int len;
 531 
 532     if (str == NULL) {
 533         return str;
 534     }
 535 
 536     for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
 537         str[len] = '\0';
 538     }
 539 
 540     return str;
 541 }
 542 
 543 /*!
 544  * \brief Check whether a string starts with a certain sequence
 545  *
 546  * \param[in] str    String to check
 547  * \param[in] prefix Sequence to match against beginning of \p str
 548  *
 549  * \return \c true if \p str begins with match, \c false otherwise
 550  * \note This is equivalent to !strncmp(s, prefix, strlen(prefix))
 551  *       but is likely less efficient when prefix is a string literal
 552  *       if the compiler optimizes away the strlen() at compile time,
 553  *       and more efficient otherwise.
 554  */
 555 bool
 556 pcmk__starts_with(const char *str, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558     const char *s = str;
 559     const char *p = prefix;
 560 
 561     if (!s || !p) {
 562         return false;
 563     }
 564     while (*s && *p) {
 565         if (*s++ != *p++) {
 566             return false;
 567         }
 568     }
 569     return (*p == 0);
 570 }
 571 
 572 static inline bool
 573 ends_with(const char *s, const char *match, bool as_extension)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575     if (pcmk__str_empty(match)) {
 576         return true;
 577     } else if (s == NULL) {
 578         return false;
 579     } else {
 580         size_t slen, mlen;
 581 
 582         /* Besides as_extension, we could also check
 583            !strchr(&match[1], match[0]) but that would be inefficient.
 584          */
 585         if (as_extension) {
 586             s = strrchr(s, match[0]);
 587             return (s == NULL)? false : !strcmp(s, match);
 588         }
 589 
 590         mlen = strlen(match);
 591         slen = strlen(s);
 592         return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
 593     }
 594 }
 595 
 596 /*!
 597  * \internal
 598  * \brief Check whether a string ends with a certain sequence
 599  *
 600  * \param[in] s      String to check
 601  * \param[in] match  Sequence to match against end of \p s
 602  *
 603  * \return \c true if \p s ends case-sensitively with match, \c false otherwise
 604  * \note pcmk__ends_with_ext() can be used if the first character of match
 605  *       does not recur in match.
 606  */
 607 bool
 608 pcmk__ends_with(const char *s, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
 609 {
 610     return ends_with(s, match, false);
 611 }
 612 
 613 /*!
 614  * \internal
 615  * \brief Check whether a string ends with a certain "extension"
 616  *
 617  * \param[in] s      String to check
 618  * \param[in] match  Extension to match against end of \p s, that is,
 619  *                   its first character must not occur anywhere
 620  *                   in the rest of that very sequence (example: file
 621  *                   extension where the last dot is its delimiter,
 622  *                   e.g., ".html"); incorrect results may be
 623  *                   returned otherwise.
 624  *
 625  * \return \c true if \p s ends (verbatim, i.e., case sensitively)
 626  *         with "extension" designated as \p match (including empty
 627  *         string), \c false otherwise
 628  *
 629  * \note Main incentive to prefer this function over \c pcmk__ends_with()
 630  *       where possible is the efficiency (at the cost of added
 631  *       restriction on \p match as stated; the complexity class
 632  *       remains the same, though: BigO(M+N) vs. BigO(M+2N)).
 633  */
 634 bool
 635 pcmk__ends_with_ext(const char *s, const char *match)
     /* [previous][next][first][last][top][bottom][index][help] */
 636 {
 637     return ends_with(s, match, true);
 638 }
 639 
 640 /*!
 641  * \internal
 642  * \brief Create a hash of a string suitable for use with GHashTable
 643  *
 644  * \param[in] v  String to hash
 645  *
 646  * \return A hash of \p v compatible with g_str_hash() before glib 2.28
 647  * \note glib changed their hash implementation:
 648  *
 649  * https://gitlab.gnome.org/GNOME/glib/commit/354d655ba8a54b754cb5a3efb42767327775696c
 650  *
 651  * Note that the new g_str_hash is presumably a *better* hash (it's actually
 652  * a correct implementation of DJB's hash), but we need to preserve existing
 653  * behaviour, because the hash key ultimately determines the "sort" order
 654  * when iterating through GHashTables, which affects allocation of scores to
 655  * clone instances when iterating through rsc->allowed_nodes.  It (somehow)
 656  * also appears to have some minor impact on the ordering of a few
 657  * pseudo_event IDs in the transition graph.
 658  */
 659 static guint
 660 pcmk__str_hash(gconstpointer v)
     /* [previous][next][first][last][top][bottom][index][help] */
 661 {
 662     const signed char *p;
 663     guint32 h = 0;
 664 
 665     for (p = v; *p != '\0'; p++)
 666         h = (h << 5) - h + *p;
 667 
 668     return h;
 669 }
 670 
 671 /*!
 672  * \internal
 673  * \brief Create a hash table with case-sensitive strings as keys
 674  *
 675  * \param[in] key_destroy_func    Function to free a key
 676  * \param[in] value_destroy_func  Function to free a value
 677  *
 678  * \return Newly allocated hash table
 679  * \note It is the caller's responsibility to free the result, using
 680  *       g_hash_table_destroy().
 681  */
 682 GHashTable *
 683 pcmk__strkey_table(GDestroyNotify key_destroy_func,
     /* [previous][next][first][last][top][bottom][index][help] */
 684                    GDestroyNotify value_destroy_func)
 685 {
 686     return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
 687                                  key_destroy_func, value_destroy_func);
 688 }
 689 
 690 /*!
 691  * \internal
 692  * \brief Insert string copies into a hash table as key and value
 693  *
 694  * \param[in,out] table  Hash table to add to
 695  * \param[in]     name   String to add a copy of as key
 696  * \param[in]     value  String to add a copy of as value
 697  *
 698  * \note This asserts on invalid arguments or memory allocation failure.
 699  */
 700 void
 701 pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 702 {
 703     CRM_ASSERT((table != NULL) && (name != NULL));
 704 
 705     g_hash_table_insert(table, pcmk__str_copy(name), pcmk__str_copy(value));
 706 }
 707 
 708 /* used with hash tables where case does not matter */
 709 static gboolean
 710 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 711 {
 712     return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
 713 }
 714 
 715 static guint
 716 pcmk__strcase_hash(gconstpointer v)
     /* [previous][next][first][last][top][bottom][index][help] */
 717 {
 718     const signed char *p;
 719     guint32 h = 0;
 720 
 721     for (p = v; *p != '\0'; p++)
 722         h = (h << 5) - h + g_ascii_tolower(*p);
 723 
 724     return h;
 725 }
 726 
 727 /*!
 728  * \internal
 729  * \brief Create a hash table with case-insensitive strings as keys
 730  *
 731  * \param[in] key_destroy_func    Function to free a key
 732  * \param[in] value_destroy_func  Function to free a value
 733  *
 734  * \return Newly allocated hash table
 735  * \note It is the caller's responsibility to free the result, using
 736  *       g_hash_table_destroy().
 737  */
 738 GHashTable *
 739 pcmk__strikey_table(GDestroyNotify key_destroy_func,
     /* [previous][next][first][last][top][bottom][index][help] */
 740                     GDestroyNotify value_destroy_func)
 741 {
 742     return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
 743                                  key_destroy_func, value_destroy_func);
 744 }
 745 
 746 static void
 747 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 748 {
 749     if (key && value && user_data) {
 750         pcmk__insert_dup((GHashTable *) user_data,
 751                          (const char *) key, (const char *) value);
 752     }
 753 }
 754 
 755 /*!
 756  * \internal
 757  * \brief Copy a hash table that uses dynamically allocated strings
 758  *
 759  * \param[in,out] old_table  Hash table to duplicate
 760  *
 761  * \return New hash table with copies of everything in \p old_table
 762  * \note This assumes the hash table uses dynamically allocated strings -- that
 763  *       is, both the key and value free functions are free().
 764  */
 765 GHashTable *
 766 pcmk__str_table_dup(GHashTable *old_table)
     /* [previous][next][first][last][top][bottom][index][help] */
 767 {
 768     GHashTable *new_table = NULL;
 769 
 770     if (old_table) {
 771         new_table = pcmk__strkey_table(free, free);
 772         g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
 773     }
 774     return new_table;
 775 }
 776 
 777 /*!
 778  * \internal
 779  * \brief Add a word to a string list of words
 780  *
 781  * \param[in,out] list       Pointer to current string list (may not be \p NULL)
 782  * \param[in]     init_size  \p list will be initialized to at least this size,
 783  *                           if it needs initialization (if 0, use GLib's default
 784  *                           initial string size)
 785  * \param[in]     word       String to add to \p list (\p list will be
 786  *                           unchanged if this is \p NULL or the empty string)
 787  * \param[in]     separator  String to separate words in \p list
 788  *                           (a space will be used if this is NULL)
 789  *
 790  * \note \p word may contain \p separator, though that would be a bad idea if
 791  *       the string needs to be parsed later.
 792  */
 793 void
 794 pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
     /* [previous][next][first][last][top][bottom][index][help] */
 795                          const char *separator)
 796 {
 797     CRM_ASSERT(list != NULL);
 798 
 799     if (pcmk__str_empty(word)) {
 800         return;
 801     }
 802 
 803     if (*list == NULL) {
 804         if (init_size > 0) {
 805             *list = g_string_sized_new(init_size);
 806         } else {
 807             *list = g_string_new(NULL);
 808         }
 809     }
 810 
 811     if ((*list)->len == 0) {
 812         // Don't add a separator before the first word in the list
 813         separator = "";
 814 
 815     } else if (separator == NULL) {
 816         // Default to space-separated
 817         separator = " ";
 818     }
 819 
 820     g_string_append(*list, separator);
 821     g_string_append(*list, word);
 822 }
 823 
 824 /*!
 825  * \internal
 826  * \brief Compress data
 827  *
 828  * \param[in]  data        Data to compress
 829  * \param[in]  length      Number of characters of data to compress
 830  * \param[in]  max         Maximum size of compressed data (or 0 to estimate)
 831  * \param[out] result      Where to store newly allocated compressed result
 832  * \param[out] result_len  Where to store actual compressed length of result
 833  *
 834  * \return Standard Pacemaker return code
 835  */
 836 int
 837 pcmk__compress(const char *data, unsigned int length, unsigned int max,
     /* [previous][next][first][last][top][bottom][index][help] */
 838                char **result, unsigned int *result_len)
 839 {
 840     int rc;
 841     char *compressed = NULL;
 842     char *uncompressed = strdup(data);
 843 #ifdef CLOCK_MONOTONIC
 844     struct timespec after_t;
 845     struct timespec before_t;
 846 #endif
 847 
 848     if (max == 0) {
 849         max = (length * 1.01) + 601; // Size guaranteed to hold result
 850     }
 851 
 852 #ifdef CLOCK_MONOTONIC
 853     clock_gettime(CLOCK_MONOTONIC, &before_t);
 854 #endif
 855 
 856     compressed = pcmk__assert_alloc((size_t) max, sizeof(char));
 857 
 858     *result_len = max;
 859     rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
 860                                   CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
 861     rc = pcmk__bzlib2rc(rc);
 862 
 863     free(uncompressed);
 864 
 865     if (rc != pcmk_rc_ok) {
 866         crm_err("Compression of %d bytes failed: %s " CRM_XS " rc=%d",
 867                 length, pcmk_rc_str(rc), rc);
 868         free(compressed);
 869         return rc;
 870     }
 871 
 872 #ifdef CLOCK_MONOTONIC
 873     clock_gettime(CLOCK_MONOTONIC, &after_t);
 874 
 875     crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
 876              length, *result_len, length / (*result_len),
 877              (after_t.tv_sec - before_t.tv_sec) * 1000 +
 878              (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
 879 #else
 880     crm_trace("Compressed %d bytes into %d (ratio %d:1)",
 881              length, *result_len, length / (*result_len));
 882 #endif
 883 
 884     *result = compressed;
 885     return pcmk_rc_ok;
 886 }
 887 
 888 char *
 889 crm_strdup_printf(char const *format, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
 890 {
 891     va_list ap;
 892     int len = 0;
 893     char *string = NULL;
 894 
 895     va_start(ap, format);
 896     len = vasprintf (&string, format, ap);
 897     CRM_ASSERT(len > 0);
 898     va_end(ap);
 899     return string;
 900 }
 901 
 902 int
 903 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
     /* [previous][next][first][last][top][bottom][index][help] */
 904 {
 905     char *remainder = NULL;
 906     int rc = pcmk_rc_ok;
 907 
 908     CRM_ASSERT(start != NULL && end != NULL);
 909 
 910     *start = PCMK__PARSE_INT_DEFAULT;
 911     *end = PCMK__PARSE_INT_DEFAULT;
 912 
 913     crm_trace("Attempting to decode: [%s]", srcstring);
 914     if (pcmk__str_eq(srcstring, "", pcmk__str_null_matches)) {
 915         return ENODATA;
 916     } else if (pcmk__str_eq(srcstring, "-", pcmk__str_none)) {
 917         return pcmk_rc_bad_input;
 918     }
 919 
 920     /* String starts with a dash, so this is either a range with
 921      * no beginning or garbage.
 922      * */
 923     if (*srcstring == '-') {
 924         int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
 925 
 926         if (rc != pcmk_rc_ok || *remainder != '\0') {
 927             return pcmk_rc_bad_input;
 928         } else {
 929             return pcmk_rc_ok;
 930         }
 931     }
 932 
 933     rc = scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT, &remainder);
 934     if (rc != pcmk_rc_ok) {
 935         return rc;
 936     }
 937 
 938     if (*remainder && *remainder == '-') {
 939         if (*(remainder+1)) {
 940             char *more_remainder = NULL;
 941             int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
 942                              &more_remainder);
 943 
 944             if (rc != pcmk_rc_ok) {
 945                 return rc;
 946             } else if (*more_remainder != '\0') {
 947                 return pcmk_rc_bad_input;
 948             }
 949         }
 950     } else if (*remainder && *remainder != '-') {
 951         *start = PCMK__PARSE_INT_DEFAULT;
 952         return pcmk_rc_bad_input;
 953     } else {
 954         /* The input string contained only one number.  Set start and end
 955          * to the same value and return pcmk_rc_ok.  This gives the caller
 956          * a way to tell this condition apart from a range with no end.
 957          */
 958         *end = *start;
 959     }
 960 
 961     return pcmk_rc_ok;
 962 }
 963 
 964 /*!
 965  * \internal
 966  * \brief Find a string in a list of strings
 967  *
 968  * \note This function takes the same flags and has the same behavior as
 969  *       pcmk__str_eq().
 970  *
 971  * \note No matter what input string or flags are provided, an empty
 972  *       list will always return FALSE.
 973  *
 974  * \param[in] s      String to search for
 975  * \param[in] lst    List to search
 976  * \param[in] flags  A bitfield of pcmk__str_flags to modify operation
 977  *
 978  * \return \c TRUE if \p s is in \p lst, or \c FALSE otherwise
 979  */
 980 gboolean
 981 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 982 {
 983     for (const GList *ele = lst; ele != NULL; ele = ele->next) {
 984         if (pcmk__str_eq(s, ele->data, flags)) {
 985             return TRUE;
 986         }
 987     }
 988 
 989     return FALSE;
 990 }
 991 
 992 static bool
 993 str_any_of(const char *s, va_list args, uint32_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 994 {
 995     if (s == NULL) {
 996         return pcmk_is_set(flags, pcmk__str_null_matches);
 997     }
 998 
 999     while (1) {
1000         const char *ele = va_arg(args, const char *);
1001 
1002         if (ele == NULL) {
1003             break;
1004         } else if (pcmk__str_eq(s, ele, flags)) {
1005             return true;
1006         }
1007     }
1008 
1009     return false;
1010 }
1011 
1012 /*!
1013  * \internal
1014  * \brief Is a string a member of a list of strings?
1015  *
1016  * \param[in]  s    String to search for in \p ...
1017  * \param[in]  ...  Strings to compare \p s against.  The final string
1018  *                  must be NULL.
1019  *
1020  * \note The comparison is done case-insensitively.  The function name is
1021  *       meant to be reminiscent of strcasecmp.
1022  *
1023  * \return \c true if \p s is in \p ..., or \c false otherwise
1024  */
1025 bool
1026 pcmk__strcase_any_of(const char *s, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
1027 {
1028     va_list ap;
1029     bool rc;
1030 
1031     va_start(ap, s);
1032     rc = str_any_of(s, ap, pcmk__str_casei);
1033     va_end(ap);
1034     return rc;
1035 }
1036 
1037 /*!
1038  * \internal
1039  * \brief Is a string a member of a list of strings?
1040  *
1041  * \param[in]  s    String to search for in \p ...
1042  * \param[in]  ...  Strings to compare \p s against.  The final string
1043  *                  must be NULL.
1044  *
1045  * \note The comparison is done taking case into account.
1046  *
1047  * \return \c true if \p s is in \p ..., or \c false otherwise
1048  */
1049 bool
1050 pcmk__str_any_of(const char *s, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
1051 {
1052     va_list ap;
1053     bool rc;
1054 
1055     va_start(ap, s);
1056     rc = str_any_of(s, ap, pcmk__str_none);
1057     va_end(ap);
1058     return rc;
1059 }
1060 
1061 /*!
1062  * \internal
1063  * \brief Sort strings, with numeric portions sorted numerically
1064  *
1065  * Sort two strings case-insensitively like strcasecmp(), but with any numeric
1066  * portions of the string sorted numerically. This is particularly useful for
1067  * node names (for example, "node10" will sort higher than "node9" but lower
1068  * than "remotenode9").
1069  *
1070  * \param[in] s1  First string to compare (must not be NULL)
1071  * \param[in] s2  Second string to compare (must not be NULL)
1072  *
1073  * \retval -1 \p s1 comes before \p s2
1074  * \retval  0 \p s1 and \p s2 are equal
1075  * \retval  1 \p s1 comes after \p s2
1076  */
1077 int
1078 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
1079 {
1080     CRM_ASSERT((s1 != NULL) && (s2 != NULL));
1081 
1082     while (*s1 && *s2) {
1083         if (isdigit(*s1) && isdigit(*s2)) {
1084             // If node names contain a number, sort numerically
1085 
1086             char *end1 = NULL;
1087             char *end2 = NULL;
1088             long num1 = strtol(s1, &end1, 10);
1089             long num2 = strtol(s2, &end2, 10);
1090 
1091             // allow ordering e.g. 007 > 7
1092             size_t len1 = end1 - s1;
1093             size_t len2 = end2 - s2;
1094 
1095             if (num1 < num2) {
1096                 return -1;
1097             } else if (num1 > num2) {
1098                 return 1;
1099             } else if (len1 < len2) {
1100                 return -1;
1101             } else if (len1 > len2) {
1102                 return 1;
1103             }
1104             s1 = end1;
1105             s2 = end2;
1106         } else {
1107             // Compare non-digits case-insensitively
1108             int lower1 = tolower(*s1);
1109             int lower2 = tolower(*s2);
1110 
1111             if (lower1 < lower2) {
1112                 return -1;
1113             } else if (lower1 > lower2) {
1114                 return 1;
1115             }
1116             ++s1;
1117             ++s2;
1118         }
1119     }
1120     if (!*s1 && *s2) {
1121         return -1;
1122     } else if (*s1 && !*s2) {
1123         return 1;
1124     }
1125     return 0;
1126 }
1127 
1128 /*!
1129  * \internal
1130  * \brief Sort strings.
1131  *
1132  * This is your one-stop function for string comparison. By default, this
1133  * function works like \p g_strcmp0. That is, like \p strcmp but a \p NULL
1134  * string sorts before a non-<tt>NULL</tt> string.
1135  *
1136  * The \p pcmk__str_none flag produces the default behavior. Behavior can be
1137  * changed with various flags:
1138  *
1139  * - \p pcmk__str_regex - The second string is a regular expression that the
1140  *                        first string will be matched against.
1141  * - \p pcmk__str_casei - By default, comparisons are done taking case into
1142  *                        account. This flag makes comparisons case-
1143  *                        insensitive. This can be combined with
1144  *                        \p pcmk__str_regex.
1145  * - \p pcmk__str_null_matches - If one string is \p NULL and the other is not,
1146  *                               still return \p 0.
1147  * - \p pcmk__str_star_matches - If one string is \p "*" and the other is not,
1148  *                               still return \p 0.
1149  *
1150  * \param[in] s1     First string to compare
1151  * \param[in] s2     Second string to compare, or a regular expression to
1152  *                   match if \p pcmk__str_regex is set
1153  * \param[in] flags  A bitfield of \p pcmk__str_flags to modify operation
1154  *
1155  * \retval  negative \p s1 is \p NULL or comes before \p s2
1156  * \retval  0        \p s1 and \p s2 are equal, or \p s1 is found in \p s2 if
1157  *                   \c pcmk__str_regex is set
1158  * \retval  positive \p s2 is \p NULL or \p s1 comes after \p s2, or \p s2
1159  *                   is an invalid regular expression, or \p s1 was not found
1160  *                   in \p s2 if \p pcmk__str_regex is set.
1161  */
1162 int
1163 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1164 {
1165     /* If this flag is set, the second string is a regex. */
1166     if (pcmk_is_set(flags, pcmk__str_regex)) {
1167         regex_t r_patt;
1168         int reg_flags = REG_EXTENDED | REG_NOSUB;
1169         int regcomp_rc = 0;
1170         int rc = 0;
1171 
1172         if (s1 == NULL || s2 == NULL) {
1173             return 1;
1174         }
1175 
1176         if (pcmk_is_set(flags, pcmk__str_casei)) {
1177             reg_flags |= REG_ICASE;
1178         }
1179         regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1180         if (regcomp_rc != 0) {
1181             rc = 1;
1182             crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1183         } else {
1184             rc = regexec(&r_patt, s1, 0, NULL, 0);
1185             regfree(&r_patt);
1186             if (rc != 0) {
1187                 rc = 1;
1188             }
1189         }
1190         return rc;
1191     }
1192 
1193     /* If the strings are the same pointer, return 0 immediately. */
1194     if (s1 == s2) {
1195         return 0;
1196     }
1197 
1198     /* If this flag is set, return 0 if either (or both) of the input strings
1199      * are NULL.  If neither one is NULL, we need to continue and compare
1200      * them normally.
1201      */
1202     if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1203         if (s1 == NULL || s2 == NULL) {
1204             return 0;
1205         }
1206     }
1207 
1208     /* Handle the cases where one is NULL and the str_null_matches flag is not set.
1209      * A NULL string always sorts to the beginning.
1210      */
1211     if (s1 == NULL) {
1212         return -1;
1213     } else if (s2 == NULL) {
1214         return 1;
1215     }
1216 
1217     /* If this flag is set, return 0 if either (or both) of the input strings
1218      * are "*".  If neither one is, we need to continue and compare them
1219      * normally.
1220      */
1221     if (pcmk_is_set(flags, pcmk__str_star_matches)) {
1222         if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1223             return 0;
1224         }
1225     }
1226 
1227     if (pcmk_is_set(flags, pcmk__str_casei)) {
1228         return strcasecmp(s1, s2);
1229     } else {
1230         return strcmp(s1, s2);
1231     }
1232 }
1233 
1234 /*!
1235  * \internal
1236  * \brief Copy a string, asserting on failure
1237  *
1238  * \param[in] file      File where \p function is located
1239  * \param[in] function  Calling function
1240  * \param[in] line      Line within \p file
1241  * \param[in] str       String to copy (can be \c NULL)
1242  *
1243  * \return Newly allocated copy of \p str, or \c NULL if \p str is \c NULL
1244  *
1245  * \note The caller is responsible for freeing the return value using \c free().
1246  */
1247 char *
1248 pcmk__str_copy_as(const char *file, const char *function, uint32_t line,
     /* [previous][next][first][last][top][bottom][index][help] */
1249                   const char *str)
1250 {
1251     if (str != NULL) {
1252         char *result = strdup(str);
1253 
1254         if (result == NULL) {
1255             crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
1256             crm_exit(CRM_EX_OSERR);
1257         }
1258         return result;
1259     }
1260     return NULL;
1261 }
1262 
1263 /*!
1264  * \internal
1265  * \brief Update a dynamically allocated string with a new value
1266  *
1267  * Given a dynamically allocated string and a new value for it, if the string
1268  * is different from the new value, free the string and replace it with either a
1269  * newly allocated duplicate of the value or NULL as appropriate.
1270  *
1271  * \param[in,out] str    Pointer to dynamically allocated string
1272  * \param[in]     value  New value to duplicate (or NULL)
1273  *
1274  * \note The caller remains responsibile for freeing \p *str.
1275  */
1276 void
1277 pcmk__str_update(char **str, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
1278 {
1279     if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1280         free(*str);
1281         *str = pcmk__str_copy(value);
1282     }
1283 }
1284 
1285 /*!
1286  * \internal
1287  * \brief Append a list of strings to a destination \p GString
1288  *
1289  * \param[in,out] buffer  Where to append the strings (must not be \p NULL)
1290  * \param[in]     ...     A <tt>NULL</tt>-terminated list of strings
1291  *
1292  * \note This tends to be more efficient than a single call to
1293  *       \p g_string_append_printf().
1294  */
1295 void
1296 pcmk__g_strcat(GString *buffer, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
1297 {
1298     va_list ap;
1299 
1300     CRM_ASSERT(buffer != NULL);
1301     va_start(ap, buffer);
1302 
1303     while (true) {
1304         const char *ele = va_arg(ap, const char *);
1305 
1306         if (ele == NULL) {
1307             break;
1308         }
1309         g_string_append(buffer, ele);
1310     }
1311     va_end(ap);
1312 }
1313 
1314 // Deprecated functions kept only for backward API compatibility
1315 // LCOV_EXCL_START
1316 
1317 #include <crm/common/util_compat.h>
1318 
1319 gboolean
1320 safe_str_neq(const char *a, const char *b)
     /* [previous][next][first][last][top][bottom][index][help] */
1321 {
1322     if (a == b) {
1323         return FALSE;
1324 
1325     } else if (a == NULL || b == NULL) {
1326         return TRUE;
1327 
1328     } else if (strcasecmp(a, b) == 0) {
1329         return FALSE;
1330     }
1331     return TRUE;
1332 }
1333 
1334 gboolean
1335 crm_str_eq(const char *a, const char *b, gboolean use_case)
     /* [previous][next][first][last][top][bottom][index][help] */
1336 {
1337     if (use_case) {
1338         return g_strcmp0(a, b) == 0;
1339 
1340         /* TODO - Figure out which calls, if any, really need to be case independent */
1341     } else if (a == b) {
1342         return TRUE;
1343 
1344     } else if (a == NULL || b == NULL) {
1345         /* shouldn't be comparing NULLs */
1346         return FALSE;
1347 
1348     } else if (strcasecmp(a, b) == 0) {
1349         return TRUE;
1350     }
1351     return FALSE;
1352 }
1353 
1354 char *
1355 crm_itoa_stack(int an_int, char *buffer, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
1356 {
1357     if (buffer != NULL) {
1358         snprintf(buffer, len, "%d", an_int);
1359     }
1360     return buffer;
1361 }
1362 
1363 guint
1364 g_str_hash_traditional(gconstpointer v)
     /* [previous][next][first][last][top][bottom][index][help] */
1365 {
1366     return pcmk__str_hash(v);
1367 }
1368 
1369 gboolean
1370 crm_strcase_equal(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
1371 {
1372     return pcmk__strcase_equal(a, b);
1373 }
1374 
1375 guint
1376 crm_strcase_hash(gconstpointer v)
     /* [previous][next][first][last][top][bottom][index][help] */
1377 {
1378     return pcmk__strcase_hash(v);
1379 }
1380 
1381 GHashTable *
1382 crm_str_table_dup(GHashTable *old_table)
     /* [previous][next][first][last][top][bottom][index][help] */
1383 {
1384     return pcmk__str_table_dup(old_table);
1385 }
1386 
1387 long long
1388 crm_parse_ll(const char *text, const char *default_text)
     /* [previous][next][first][last][top][bottom][index][help] */
1389 {
1390     long long result;
1391 
1392     if (text == NULL) {
1393         text = default_text;
1394         if (text == NULL) {
1395             crm_err("No default conversion value supplied");
1396             errno = EINVAL;
1397             return PCMK__PARSE_INT_DEFAULT;
1398         }
1399     }
1400     scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1401     return result;
1402 }
1403 
1404 int
1405 crm_parse_int(const char *text, const char *default_text)
     /* [previous][next][first][last][top][bottom][index][help] */
1406 {
1407     long long result = crm_parse_ll(text, default_text);
1408 
1409     if (result < INT_MIN) {
1410         // If errno is ERANGE, crm_parse_ll() has already logged a message
1411         if (errno != ERANGE) {
1412             crm_err("Conversion of %s was clipped: %lld", text, result);
1413             errno = ERANGE;
1414         }
1415         return INT_MIN;
1416 
1417     } else if (result > INT_MAX) {
1418         // If errno is ERANGE, crm_parse_ll() has already logged a message
1419         if (errno != ERANGE) {
1420             crm_err("Conversion of %s was clipped: %lld", text, result);
1421             errno = ERANGE;
1422         }
1423         return INT_MAX;
1424     }
1425 
1426     return (int) result;
1427 }
1428 
1429 char *
1430 crm_strip_trailing_newline(char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
1431 {
1432     return pcmk__trim(str);
1433 }
1434 
1435 int
1436 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help] */
1437 {
1438     return pcmk__numeric_strcasecmp(s1, s2);
1439 }
1440 
1441 // LCOV_EXCL_STOP
1442 // End deprecated API

/* [previous][next][first][last][top][bottom][index][help] */