LCOV - code coverage report
Current view: top level - common - strings.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 370 435 85.1 %
Date: 2024-05-07 11:09:47 Functions: 28 36 77.8 %

          Line data    Source code
       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        2794 : scan_ll(const char *text, long long *result, long long default_value,
      44             :         char **end_text)
      45             : {
      46        2794 :     long long local_result = default_value;
      47        2794 :     char *local_end_text = NULL;
      48        2794 :     int rc = pcmk_rc_ok;
      49             : 
      50        2794 :     errno = 0;
      51        2794 :     if (text != NULL) {
      52        2794 :         local_result = strtoll(text, &local_end_text, 10);
      53        2794 :         if (errno == ERANGE) {
      54           2 :             rc = EOVERFLOW;
      55           2 :             crm_warn("Integer parsed from '%s' was clipped to %lld",
      56             :                      text, local_result);
      57             : 
      58        2792 :         } else if (errno != 0) {
      59           0 :             rc = errno;
      60           0 :             local_result = default_value;
      61           0 :             crm_warn("Could not parse integer from '%s' (using %lld instead): "
      62             :                      "%s", text, default_value, pcmk_rc_str(rc));
      63             : 
      64        2792 :         } else if (local_end_text == text) {
      65          29 :             rc = EINVAL;
      66          29 :             local_result = default_value;
      67          29 :             crm_warn("Could not parse integer from '%s' (using %lld instead): "
      68             :                     "No digits found", text, default_value);
      69             :         }
      70             : 
      71        2794 :         if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
      72          31 :             crm_warn("Characters left over after parsing '%s': '%s'",
      73             :                      text, local_end_text);
      74             :         }
      75        2794 :         errno = rc;
      76             :     }
      77        2794 :     if (end_text != NULL) {
      78         824 :         *end_text = local_end_text;
      79             :     }
      80        2794 :     if (result != NULL) {
      81        2794 :         *result = local_result;
      82             :     }
      83        2794 :     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        2096 : pcmk__scan_ll(const char *text, long long *result, long long default_value)
      98             : {
      99        2096 :     long long local_result = default_value;
     100        2096 :     int rc = pcmk_rc_ok;
     101             : 
     102        2096 :     if (text != NULL) {
     103        1970 :         rc = scan_ll(text, &local_result, default_value, NULL);
     104        1970 :         if (rc != pcmk_rc_ok) {
     105          22 :             local_result = default_value;
     106             :         }
     107             :     }
     108        2096 :     if (result != NULL) {
     109        1770 :         *result = local_result;
     110             :     }
     111        2096 :     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         348 : pcmk__scan_min_int(const char *text, int *result, int minimum)
     128             : {
     129             :     int rc;
     130             :     long long result_ll;
     131             : 
     132         348 :     rc = pcmk__scan_ll(text, &result_ll, (long long) minimum);
     133             : 
     134         348 :     if (result_ll < (long long) minimum) {
     135           1 :         crm_warn("Clipped '%s' to minimum acceptable value %d", text, minimum);
     136           1 :         result_ll = (long long) minimum;
     137             : 
     138         347 :     } else if (result_ll > INT_MAX) {
     139           1 :         crm_warn("Clipped '%s' to maximum integer %d", text, INT_MAX);
     140           1 :         result_ll = (long long) INT_MAX;
     141           1 :         rc = EOVERFLOW;
     142             :     }
     143             : 
     144         348 :     if (result != NULL) {
     145         348 :         *result = (int) result_ll;
     146             :     }
     147         348 :     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           6 : pcmk__scan_port(const char *text, int *port)
     162             : {
     163             :     long long port_ll;
     164           6 :     int rc = pcmk__scan_ll(text, &port_ll, -1LL);
     165             : 
     166           6 :     if ((text != NULL) && (rc == pcmk_rc_ok) // wasn't default or invalid
     167           4 :         && ((port_ll < 0LL) || (port_ll > 65535LL))) {
     168           2 :         crm_warn("Ignoring port specification '%s' "
     169             :                  "not in valid range (0-65535)", text);
     170           2 :         rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range;
     171           2 :         port_ll = -1LL;
     172             :     }
     173           6 :     if (port != NULL) {
     174           6 :         *port = (int) port_ll;
     175             :     }
     176           6 :     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          47 : pcmk__scan_double(const char *text, double *result, const char *default_text,
     200             :                   char **end_text)
     201             : {
     202          47 :     int rc = pcmk_rc_ok;
     203          47 :     char *local_end_text = NULL;
     204             : 
     205          47 :     CRM_ASSERT(result != NULL);
     206          46 :     *result = PCMK__PARSE_DBL_DEFAULT;
     207             : 
     208          46 :     text = (text != NULL) ? text : default_text;
     209             : 
     210          46 :     if (text == NULL) {
     211           2 :         rc = EINVAL;
     212           2 :         crm_debug("No text and no default conversion value supplied");
     213             : 
     214             :     } else {
     215          44 :         errno = 0;
     216          44 :         *result = strtod(text, &local_end_text);
     217             : 
     218          44 :         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           4 :             if (QB_ABS(*result) > DBL_MIN) {
     231           2 :                 rc = EOVERFLOW;
     232           2 :                 over_under = "over";
     233             :             } else {
     234           2 :                 rc = pcmk_rc_underflow;
     235           2 :                 over_under = "under";
     236             :             }
     237             : 
     238           4 :             crm_debug("Floating-point value parsed from '%s' would %sflow "
     239             :                       "(using %g instead)", text, over_under, *result);
     240             : 
     241          40 :         } else if (errno != 0) {
     242           0 :             rc = errno;
     243             :             // strtod() set *result = 0 on parse failure
     244           0 :             *result = PCMK__PARSE_DBL_DEFAULT;
     245             : 
     246           0 :             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          40 :         } else if (local_end_text == text) {
     251             :             // errno == 0, but nothing was parsed
     252          16 :             rc = EINVAL;
     253          16 :             *result = PCMK__PARSE_DBL_DEFAULT;
     254             : 
     255          16 :             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          24 :         } 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          14 :             for (const char *p = text; p != local_end_text; p++) {
     273          10 :                 if (strchr("0.eE", *p) == NULL) {
     274           0 :                     rc = pcmk_rc_underflow;
     275           0 :                     crm_debug("Floating-point value parsed from '%s' would "
     276             :                               "underflow (using %g instead)", text, *result);
     277           0 :                     break;
     278             :                 }
     279             :             }
     280             : 
     281             :         } else {
     282          20 :             crm_trace("Floating-point value parsed successfully from "
     283             :                       "'%s': %g", text, *result);
     284             :         }
     285             : 
     286          44 :         if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
     287          12 :             crm_debug("Characters left over after parsing '%s': '%s'",
     288             :                       text, local_end_text);
     289             :         }
     290             :     }
     291             : 
     292          46 :     if (end_text != NULL) {
     293           2 :         *end_text = local_end_text;
     294             :     }
     295             : 
     296          46 :     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           7 : 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           7 :     int rc = pcmk_rc_ok;
     317             : 
     318           7 :     CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
     319             : 
     320           5 :     if (result != NULL) {
     321           5 :         *result = default_val;
     322             :     }
     323             : 
     324           5 :     value = g_hash_table_lookup(table, key);
     325           5 :     if (value == NULL) {
     326           1 :         return pcmk_rc_ok;
     327             :     }
     328             : 
     329           4 :     rc = pcmk__scan_ll(value, &value_ll, 0LL);
     330           4 :     if (rc != pcmk_rc_ok) {
     331           1 :         return rc;
     332             :     }
     333             : 
     334           3 :     if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
     335           2 :         crm_warn("Could not parse non-negative integer from %s", value);
     336           2 :         return ERANGE;
     337             :     }
     338             : 
     339           1 :     if (result != NULL) {
     340           1 :         *result = (guint) value_ll;
     341             :     }
     342           1 :     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         771 : crm_get_msec(const char *input)
     357             : {
     358         771 :     char *units = NULL; // Do not free; will point to part of input
     359         771 :     long long multiplier = 1000;
     360         771 :     long long divisor = 1;
     361         771 :     long long msec = PCMK__PARSE_INT_DEFAULT;
     362             : 
     363         771 :     if (input == NULL) {
     364           1 :         return PCMK__PARSE_INT_DEFAULT;
     365             :     }
     366             : 
     367             :     // Skip initial whitespace
     368         800 :     while (isspace(*input)) {
     369          30 :         input++;
     370             :     }
     371             : 
     372             :     // Reject negative and unparsable inputs
     373         770 :     scan_ll(input, &msec, -1, &units);
     374         770 :     if (msec < 0) {
     375           5 :         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         826 :     while (isdigit(*units) || (*units == '.')) {
     387          61 :         units++;
     388             :     }
     389             : 
     390             :     // Skip any additional whitespace after the number
     391         796 :     while (isspace(*units)) {
     392          31 :         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         765 :     if ((*units == '\0')
     399         498 :         || (strncasecmp(units, "s", 1) == 0)
     400         203 :         || (strncasecmp(units, "sec", 3) == 0)) {
     401         562 :         multiplier = 1000;
     402         562 :         divisor = 1;
     403             : 
     404         203 :     } else if ((strncasecmp(units, "ms", 2) == 0)
     405         192 :                || (strncasecmp(units, "msec", 4) == 0)) {
     406          11 :         multiplier = 1;
     407          11 :         divisor = 1;
     408             : 
     409         192 :     } else if ((strncasecmp(units, "us", 2) == 0)
     410         190 :                || (strncasecmp(units, "usec", 4) == 0)) {
     411           2 :         multiplier = 1;
     412           2 :         divisor = 1000;
     413             : 
     414         190 :     } else if ((strncasecmp(units, "m", 1) == 0)
     415           8 :                || (strncasecmp(units, "min", 3) == 0)) {
     416         182 :         multiplier = 60 * 1000;
     417         182 :         divisor = 1;
     418             : 
     419           8 :     } else if ((strncasecmp(units, "h", 1) == 0)
     420           6 :                || (strncasecmp(units, "hr", 2) == 0)) {
     421           2 :         multiplier = 60 * 60 * 1000;
     422           2 :         divisor = 1;
     423             : 
     424             :     } else {
     425             :         // Invalid units
     426           6 :         return PCMK__PARSE_INT_DEFAULT;
     427             :     }
     428             : 
     429             :     // Apply units, capping at LLONG_MAX
     430         759 :     if (msec > (LLONG_MAX / multiplier)) {
     431           1 :         return LLONG_MAX;
     432             :     }
     433         758 :     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           0 : pcmk_parse_interval_spec(const char *input, guint *result_ms)
     452             : {
     453           0 :     long long msec = PCMK__PARSE_INT_DEFAULT;
     454           0 :     int rc = pcmk_rc_ok;
     455             : 
     456           0 :     if (input == NULL) {
     457           0 :         msec = 0;
     458           0 :         goto done;
     459             :     }
     460             : 
     461           0 :     if (input[0] == 'P') {
     462           0 :         crm_time_t *period_s = crm_time_parse_duration(input);
     463             : 
     464           0 :         if (period_s != NULL) {
     465           0 :             msec = 1000 * crm_time_get_seconds(period_s);
     466           0 :             crm_time_free(period_s);
     467             :         }
     468             : 
     469             :     } else {
     470           0 :         msec = crm_get_msec(input);
     471             :     }
     472             : 
     473           0 :     if (msec == PCMK__PARSE_INT_DEFAULT) {
     474           0 :         crm_warn("Using 0 instead of invalid interval specification '%s'",
     475             :                  input);
     476           0 :         msec = 0;
     477           0 :         rc = EINVAL;
     478             :     }
     479             : 
     480           0 : done:
     481           0 :     if (result_ms != NULL) {
     482           0 :         *result_ms = (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
     483             :     }
     484           0 :     return rc;
     485             : }
     486             : 
     487             : gboolean
     488        1486 : crm_is_true(const char *s)
     489             : {
     490        1486 :     gboolean ret = FALSE;
     491             : 
     492        1486 :     return (crm_str_to_boolean(s, &ret) < 0)? FALSE : ret;
     493             : }
     494             : 
     495             : int
     496        2584 : crm_str_to_boolean(const char *s, int *ret)
     497             : {
     498        2584 :     if (s == NULL) {
     499         692 :         return -1;
     500             :     }
     501             : 
     502        1892 :     if (pcmk__strcase_any_of(s, PCMK_VALUE_TRUE, "on", "yes", "y", "1", NULL)) {
     503         838 :         if (ret != NULL) {
     504         431 :             *ret = TRUE;
     505             :         }
     506         838 :         return 1;
     507             :     }
     508             : 
     509        1054 :     if (pcmk__strcase_any_of(s, PCMK_VALUE_FALSE, "off", "no", "n", "0",
     510             :                              NULL)) {
     511        1029 :         if (ret != NULL) {
     512         488 :             *ret = FALSE;
     513             :         }
     514        1029 :         return 1;
     515             :     }
     516          25 :     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           7 : pcmk__trim(char *str)
     529             : {
     530             :     int len;
     531             : 
     532           7 :     if (str == NULL) {
     533           1 :         return str;
     534             :     }
     535             : 
     536           8 :     for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
     537           2 :         str[len] = '\0';
     538             :     }
     539             : 
     540           6 :     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          31 : pcmk__starts_with(const char *str, const char *prefix)
     557             : {
     558          31 :     const char *s = str;
     559          31 :     const char *p = prefix;
     560             : 
     561          31 :     if (!s || !p) {
     562           2 :         return false;
     563             :     }
     564         120 :     while (*s && *p) {
     565          99 :         if (*s++ != *p++) {
     566           8 :             return false;
     567             :         }
     568             :     }
     569          21 :     return (*p == 0);
     570             : }
     571             : 
     572             : static inline bool
     573       13262 : ends_with(const char *s, const char *match, bool as_extension)
     574             : {
     575       13262 :     if (pcmk__str_empty(match)) {
     576           6 :         return true;
     577       13256 :     } else if (s == NULL) {
     578           1 :         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       13255 :         if (as_extension) {
     586        1530 :             s = strrchr(s, match[0]);
     587        1530 :             return (s == NULL)? false : !strcmp(s, match);
     588             :         }
     589             : 
     590       11725 :         mlen = strlen(match);
     591       11725 :         slen = strlen(s);
     592       11725 :         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       11732 : pcmk__ends_with(const char *s, const char *match)
     609             : {
     610       11732 :     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        1530 : pcmk__ends_with_ext(const char *s, const char *match)
     636             : {
     637        1530 :     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           0 : pcmk__str_hash(gconstpointer v)
     661             : {
     662             :     const signed char *p;
     663           0 :     guint32 h = 0;
     664             : 
     665           0 :     for (p = v; *p != '\0'; p++)
     666           0 :         h = (h << 5) - h + *p;
     667             : 
     668           0 :     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        1884 : pcmk__strkey_table(GDestroyNotify key_destroy_func,
     684             :                    GDestroyNotify value_destroy_func)
     685             : {
     686        1884 :     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           0 : pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
     702             : {
     703           0 :     CRM_ASSERT((table != NULL) && (name != NULL));
     704             : 
     705           0 :     g_hash_table_insert(table, pcmk__str_copy(name), pcmk__str_copy(value));
     706           0 : }
     707             : 
     708             : /* used with hash tables where case does not matter */
     709             : static gboolean
     710           0 : pcmk__strcase_equal(gconstpointer a, gconstpointer b)
     711             : {
     712           0 :     return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
     713             : }
     714             : 
     715             : static guint
     716           0 : pcmk__strcase_hash(gconstpointer v)
     717             : {
     718             :     const signed char *p;
     719           0 :     guint32 h = 0;
     720             : 
     721           0 :     for (p = v; *p != '\0'; p++)
     722           0 :         h = (h << 5) - h + g_ascii_tolower(*p);
     723             : 
     724           0 :     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         159 : pcmk__strikey_table(GDestroyNotify key_destroy_func,
     740             :                     GDestroyNotify value_destroy_func)
     741             : {
     742         159 :     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           0 : copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
     748             : {
     749           0 :     if (key && value && user_data) {
     750           0 :         pcmk__insert_dup((GHashTable *) user_data,
     751             :                          (const char *) key, (const char *) value);
     752             :     }
     753           0 : }
     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           3 : pcmk__str_table_dup(GHashTable *old_table)
     767             : {
     768           3 :     GHashTable *new_table = NULL;
     769             : 
     770           3 :     if (old_table) {
     771           2 :         new_table = pcmk__strkey_table(free, free);
     772           2 :         g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
     773             :     }
     774           3 :     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          28 : pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
     795             :                          const char *separator)
     796             : {
     797          28 :     CRM_ASSERT(list != NULL);
     798             : 
     799          28 :     if (pcmk__str_empty(word)) {
     800           2 :         return;
     801             :     }
     802             : 
     803          26 :     if (*list == NULL) {
     804          12 :         if (init_size > 0) {
     805          10 :             *list = g_string_sized_new(init_size);
     806             :         } else {
     807           2 :             *list = g_string_new(NULL);
     808             :         }
     809             :     }
     810             : 
     811          26 :     if ((*list)->len == 0) {
     812             :         // Don't add a separator before the first word in the list
     813          12 :         separator = "";
     814             : 
     815          14 :     } else if (separator == NULL) {
     816             :         // Default to space-separated
     817           2 :         separator = " ";
     818             :     }
     819             : 
     820          26 :     g_string_append(*list, separator);
     821          26 :     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           5 : pcmk__compress(const char *data, unsigned int length, unsigned int max,
     838             :                char **result, unsigned int *result_len)
     839             : {
     840             :     int rc;
     841           5 :     char *compressed = NULL;
     842           5 :     char *uncompressed = strdup(data);
     843             : #ifdef CLOCK_MONOTONIC
     844             :     struct timespec after_t;
     845             :     struct timespec before_t;
     846             : #endif
     847             : 
     848           5 :     if (max == 0) {
     849           3 :         max = (length * 1.01) + 601; // Size guaranteed to hold result
     850             :     }
     851             : 
     852             : #ifdef CLOCK_MONOTONIC
     853           5 :     clock_gettime(CLOCK_MONOTONIC, &before_t);
     854             : #endif
     855             : 
     856           5 :     compressed = pcmk__assert_alloc((size_t) max, sizeof(char));
     857             : 
     858           4 :     *result_len = max;
     859           4 :     rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
     860             :                                   CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
     861           4 :     rc = pcmk__bzlib2rc(rc);
     862             : 
     863           4 :     free(uncompressed);
     864             : 
     865           4 :     if (rc != pcmk_rc_ok) {
     866           2 :         crm_err("Compression of %d bytes failed: %s " CRM_XS " rc=%d",
     867             :                 length, pcmk_rc_str(rc), rc);
     868           2 :         free(compressed);
     869           2 :         return rc;
     870             :     }
     871             : 
     872             : #ifdef CLOCK_MONOTONIC
     873           2 :     clock_gettime(CLOCK_MONOTONIC, &after_t);
     874             : 
     875           2 :     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           2 :     *result = compressed;
     885           2 :     return pcmk_rc_ok;
     886             : }
     887             : 
     888             : char *
     889           0 : crm_strdup_printf(char const *format, ...)
     890             : {
     891             :     va_list ap;
     892           0 :     int len = 0;
     893           0 :     char *string = NULL;
     894             : 
     895           0 :     va_start(ap, format);
     896           0 :     len = vasprintf (&string, format, ap);
     897           0 :     CRM_ASSERT(len > 0);
     898           0 :     va_end(ap);
     899           0 :     return string;
     900             : }
     901             : 
     902             : int
     903          55 : pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
     904             : {
     905          55 :     char *remainder = NULL;
     906          55 :     int rc = pcmk_rc_ok;
     907             : 
     908          55 :     CRM_ASSERT(start != NULL && end != NULL);
     909             : 
     910          53 :     *start = PCMK__PARSE_INT_DEFAULT;
     911          53 :     *end = PCMK__PARSE_INT_DEFAULT;
     912             : 
     913          53 :     crm_trace("Attempting to decode: [%s]", srcstring);
     914          53 :     if (pcmk__str_eq(srcstring, "", pcmk__str_null_matches)) {
     915           6 :         return ENODATA;
     916          47 :     } else if (pcmk__str_eq(srcstring, "-", pcmk__str_none)) {
     917           1 :         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          46 :     if (*srcstring == '-') {
     924           3 :         int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
     925             : 
     926           3 :         if (rc != pcmk_rc_ok || *remainder != '\0') {
     927           1 :             return pcmk_rc_bad_input;
     928             :         } else {
     929           2 :             return pcmk_rc_ok;
     930             :         }
     931             :     }
     932             : 
     933          43 :     rc = scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT, &remainder);
     934          43 :     if (rc != pcmk_rc_ok) {
     935           3 :         return rc;
     936             :     }
     937             : 
     938          40 :     if (*remainder && *remainder == '-') {
     939          11 :         if (*(remainder+1)) {
     940           8 :             char *more_remainder = NULL;
     941           8 :             int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
     942             :                              &more_remainder);
     943             : 
     944           8 :             if (rc != pcmk_rc_ok) {
     945           2 :                 return rc;
     946           7 :             } else if (*more_remainder != '\0') {
     947           1 :                 return pcmk_rc_bad_input;
     948             :             }
     949             :         }
     950          29 :     } else if (*remainder && *remainder != '-') {
     951           1 :         *start = PCMK__PARSE_INT_DEFAULT;
     952           1 :         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          28 :         *end = *start;
     959             :     }
     960             : 
     961          37 :     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          27 : pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
     982             : {
     983          49 :     for (const GList *ele = lst; ele != NULL; ele = ele->next) {
     984          33 :         if (pcmk__str_eq(s, ele->data, flags)) {
     985          11 :             return TRUE;
     986             :         }
     987             :     }
     988             : 
     989          16 :     return FALSE;
     990             : }
     991             : 
     992             : static bool
     993       10174 : str_any_of(const char *s, va_list args, uint32_t flags)
     994             : {
     995       10174 :     if (s == NULL) {
     996          10 :         return pcmk_is_set(flags, pcmk__str_null_matches);
     997             :     }
     998             : 
     999       12783 :     while (1) {
    1000       22947 :         const char *ele = va_arg(args, const char *);
    1001             : 
    1002       22947 :         if (ele == NULL) {
    1003        3752 :             break;
    1004       19195 :         } else if (pcmk__str_eq(s, ele, flags)) {
    1005        6412 :             return true;
    1006             :         }
    1007             :     }
    1008             : 
    1009        3752 :     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        9275 : pcmk__strcase_any_of(const char *s, ...)
    1027             : {
    1028             :     va_list ap;
    1029             :     bool rc;
    1030             : 
    1031        9275 :     va_start(ap, s);
    1032        9275 :     rc = str_any_of(s, ap, pcmk__str_casei);
    1033        9275 :     va_end(ap);
    1034        9275 :     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         899 : pcmk__str_any_of(const char *s, ...)
    1051             : {
    1052             :     va_list ap;
    1053             :     bool rc;
    1054             : 
    1055         899 :     va_start(ap, s);
    1056         899 :     rc = str_any_of(s, ap, pcmk__str_none);
    1057         899 :     va_end(ap);
    1058         899 :     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          84 : pcmk__numeric_strcasecmp(const char *s1, const char *s2)
    1079             : {
    1080          84 :     CRM_ASSERT((s1 != NULL) && (s2 != NULL));
    1081             : 
    1082         410 :     while (*s1 && *s2) {
    1083         401 :         if (isdigit(*s1) && isdigit(*s2)) {
    1084             :             // If node names contain a number, sort numerically
    1085             : 
    1086          59 :             char *end1 = NULL;
    1087          59 :             char *end2 = NULL;
    1088          59 :             long num1 = strtol(s1, &end1, 10);
    1089          59 :             long num2 = strtol(s2, &end2, 10);
    1090             : 
    1091             :             // allow ordering e.g. 007 > 7
    1092          59 :             size_t len1 = end1 - s1;
    1093          59 :             size_t len2 = end2 - s2;
    1094             : 
    1095          59 :             if (num1 < num2) {
    1096          52 :                 return -1;
    1097          55 :             } else if (num1 > num2) {
    1098          46 :                 return 1;
    1099           9 :             } else if (len1 < len2) {
    1100           1 :                 return -1;
    1101           8 :             } else if (len1 > len2) {
    1102           1 :                 return 1;
    1103             :             }
    1104           7 :             s1 = end1;
    1105           7 :             s2 = end2;
    1106             :         } else {
    1107             :             // Compare non-digits case-insensitively
    1108         342 :             int lower1 = tolower(*s1);
    1109         342 :             int lower2 = tolower(*s2);
    1110             : 
    1111         342 :             if (lower1 < lower2) {
    1112           4 :                 return -1;
    1113         338 :             } else if (lower1 > lower2) {
    1114          16 :                 return 1;
    1115             :             }
    1116         322 :             ++s1;
    1117         322 :             ++s2;
    1118             :         }
    1119             :     }
    1120           9 :     if (!*s1 && *s2) {
    1121           2 :         return -1;
    1122           7 :     } else if (*s1 && !*s2) {
    1123           2 :         return 1;
    1124             :     }
    1125           5 :     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       61609 : pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
    1164             : {
    1165             :     /* If this flag is set, the second string is a regex. */
    1166       61609 :     if (pcmk_is_set(flags, pcmk__str_regex)) {
    1167             :         regex_t r_patt;
    1168          11 :         int reg_flags = REG_EXTENDED | REG_NOSUB;
    1169          11 :         int regcomp_rc = 0;
    1170          11 :         int rc = 0;
    1171             : 
    1172          11 :         if (s1 == NULL || s2 == NULL) {
    1173           2 :             return 1;
    1174             :         }
    1175             : 
    1176           9 :         if (pcmk_is_set(flags, pcmk__str_casei)) {
    1177           2 :             reg_flags |= REG_ICASE;
    1178             :         }
    1179           9 :         regcomp_rc = regcomp(&r_patt, s2, reg_flags);
    1180           9 :         if (regcomp_rc != 0) {
    1181           1 :             rc = 1;
    1182           1 :             crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
    1183             :         } else {
    1184           8 :             rc = regexec(&r_patt, s1, 0, NULL, 0);
    1185           8 :             regfree(&r_patt);
    1186           8 :             if (rc != 0) {
    1187           4 :                 rc = 1;
    1188             :             }
    1189             :         }
    1190           9 :         return rc;
    1191             :     }
    1192             : 
    1193             :     /* If the strings are the same pointer, return 0 immediately. */
    1194       61598 :     if (s1 == s2) {
    1195         425 :         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       61173 :     if (pcmk_is_set(flags, pcmk__str_null_matches)) {
    1203        1607 :         if (s1 == NULL || s2 == NULL) {
    1204         593 :             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       60580 :     if (s1 == NULL) {
    1212        1483 :         return -1;
    1213       59097 :     } else if (s2 == NULL) {
    1214         240 :         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       58857 :     if (pcmk_is_set(flags, pcmk__str_star_matches)) {
    1222           4 :         if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
    1223           4 :             return 0;
    1224             :         }
    1225             :     }
    1226             : 
    1227       58853 :     if (pcmk_is_set(flags, pcmk__str_casei)) {
    1228       44417 :         return strcasecmp(s1, s2);
    1229             :     } else {
    1230       14436 :         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           0 : pcmk__str_copy_as(const char *file, const char *function, uint32_t line,
    1249             :                   const char *str)
    1250             : {
    1251           0 :     if (str != NULL) {
    1252           0 :         char *result = strdup(str);
    1253             : 
    1254           0 :         if (result == NULL) {
    1255           0 :             crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
    1256           0 :             crm_exit(CRM_EX_OSERR);
    1257             :         }
    1258           0 :         return result;
    1259             :     }
    1260           0 :     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          61 : pcmk__str_update(char **str, const char *value)
    1278             : {
    1279          61 :     if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
    1280          25 :         free(*str);
    1281          25 :         *str = pcmk__str_copy(value);
    1282             :     }
    1283          60 : }
    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        6007 : pcmk__g_strcat(GString *buffer, ...)
    1297             : {
    1298             :     va_list ap;
    1299             : 
    1300        6007 :     CRM_ASSERT(buffer != NULL);
    1301        6005 :     va_start(ap, buffer);
    1302             : 
    1303       26406 :     while (true) {
    1304       32411 :         const char *ele = va_arg(ap, const char *);
    1305             : 
    1306       32411 :         if (ele == NULL) {
    1307        6005 :             break;
    1308             :         }
    1309             :         g_string_append(buffer, ele);
    1310             :     }
    1311        6005 :     va_end(ap);
    1312        6005 : }
    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)
    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)
    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)
    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)
    1365             : {
    1366             :     return pcmk__str_hash(v);
    1367             : }
    1368             : 
    1369             : gboolean
    1370             : crm_strcase_equal(gconstpointer a, gconstpointer b)
    1371             : {
    1372             :     return pcmk__strcase_equal(a, b);
    1373             : }
    1374             : 
    1375             : guint
    1376             : crm_strcase_hash(gconstpointer v)
    1377             : {
    1378             :     return pcmk__strcase_hash(v);
    1379             : }
    1380             : 
    1381             : GHashTable *
    1382             : crm_str_table_dup(GHashTable *old_table)
    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)
    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)
    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)
    1431             : {
    1432             :     return pcmk__trim(str);
    1433             : }
    1434             : 
    1435             : int
    1436             : pcmk_numeric_strcasecmp(const char *s1, const char *s2)
    1437             : {
    1438             :     return pcmk__numeric_strcasecmp(s1, s2);
    1439             : }
    1440             : 
    1441             : // LCOV_EXCL_STOP
    1442             : // End deprecated API

Generated by: LCOV version 1.14