root/lib/common/scores.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk_parse_score
  2. char2score
  3. pcmk_readable_score
  4. pcmk__add_scores
  5. score2char
  6. score2char_stack

   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_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <stdio.h>      // snprintf(), NULL
  17 #include <string.h>     // strcpy(), strdup()
  18 #include <ctype.h>      // isspace()
  19 #include <sys/types.h>  // size_t
  20 
  21 int pcmk__score_red = 0;
  22 int pcmk__score_green = 0;
  23 int pcmk__score_yellow = 0;
  24 
  25 /*!
  26  * \brief Parse an integer score from a string
  27  *
  28  * Parse an integer score from a string. This accepts infinity strings as well
  29  * as red, yellow, and green, and bounds the result to +/-INFINITY.
  30  *
  31  * \param[in]  score_s        Score as string
  32  * \param[out] score          Where to store integer value corresponding to
  33  *                            \p score_s (may be NULL to only check validity)
  34  * \param[in]  default_score  Value to use if \p score_s is NULL or invalid
  35  *
  36  * \return Standard Pacemaker return code
  37  */
  38 int
  39 pcmk_parse_score(const char *score_s, int *score, int default_score)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41     int rc = pcmk_rc_ok;
  42     int local_score = 0;
  43 
  44     // Ensure default score is in bounds
  45     default_score = QB_MIN(default_score, PCMK_SCORE_INFINITY);
  46     default_score = QB_MAX(default_score, -PCMK_SCORE_INFINITY);
  47     local_score = default_score;
  48 
  49     if (score_s == NULL) {
  50 
  51     } else if (pcmk_str_is_minus_infinity(score_s)) {
  52         local_score = -PCMK_SCORE_INFINITY;
  53 
  54     } else if (pcmk_str_is_infinity(score_s)) {
  55         local_score = PCMK_SCORE_INFINITY;
  56 
  57     } else if (pcmk__str_eq(score_s, PCMK_VALUE_RED, pcmk__str_casei)) {
  58         local_score = pcmk__score_red;
  59 
  60     } else if (pcmk__str_eq(score_s, PCMK_VALUE_YELLOW, pcmk__str_casei)) {
  61         local_score = pcmk__score_yellow;
  62 
  63     } else if (pcmk__str_eq(score_s, PCMK_VALUE_GREEN, pcmk__str_casei)) {
  64         local_score = pcmk__score_green;
  65 
  66     } else {
  67         long long score_ll = 0LL;
  68 
  69         rc = pcmk__scan_ll(score_s, &score_ll, default_score);
  70         if ((rc == EOVERFLOW) || (rc == ERANGE)) {
  71             const char *c = score_s;
  72 
  73             while (isspace(*c)) {
  74                 ++c;
  75             }
  76             rc = pcmk_rc_ok;
  77             if (*c == '-') {
  78                 score_ll = -PCMK_SCORE_INFINITY;
  79             } else {
  80                 score_ll = PCMK_SCORE_INFINITY;
  81             }
  82         }
  83         if (rc != pcmk_rc_ok) {
  84             local_score = default_score;
  85 
  86         } else if (score_ll > PCMK_SCORE_INFINITY) {
  87             local_score = PCMK_SCORE_INFINITY;
  88 
  89         } else if (score_ll < -PCMK_SCORE_INFINITY) {
  90             local_score = -PCMK_SCORE_INFINITY;
  91 
  92         } else {
  93             local_score = (int) score_ll;
  94         }
  95     }
  96 
  97     if (score != NULL) {
  98         *score = local_score;
  99     }
 100     return rc;
 101 }
 102 
 103 /*!
 104  * \brief Get the integer value of a score string
 105  *
 106  * Given a string representation of a score, return the integer equivalent.
 107  * This accepts infinity strings as well as red, yellow, and green, and
 108  * bounds the result to +/-INFINITY.
 109  *
 110  * \param[in] score  Score as string
 111  *
 112  * \return Integer value corresponding to \p score
 113  */
 114 int
 115 char2score(const char *score)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117     int result = 0;
 118 
 119     (void) pcmk_parse_score(score, &result, 0);
 120     return result;
 121 }
 122 
 123 /*!
 124  * \brief Return a displayable static string for a score value
 125  *
 126  * Given a score value, return a pointer to a static string representation of
 127  * the score suitable for log messages, output, etc.
 128  *
 129  * \param[in] score  Score to display
 130  *
 131  * \return Pointer to static memory containing string representation of \p score
 132  * \note Subsequent calls to this function will overwrite the returned value, so
 133  *       it should be used only in a local context such as a printf()-style
 134  *       statement.
 135  */
 136 const char *
 137 pcmk_readable_score(int score)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139     // The longest possible result is "-INFINITY"
 140     static char score_s[sizeof(PCMK_VALUE_MINUS_INFINITY)];
 141 
 142     if (score >= PCMK_SCORE_INFINITY) {
 143         strcpy(score_s, PCMK_VALUE_INFINITY);
 144 
 145     } else if (score <= -PCMK_SCORE_INFINITY) {
 146         strcpy(score_s, PCMK_VALUE_MINUS_INFINITY);
 147 
 148     } else {
 149         // Range is limited to +/-1000000, so no chance of overflow
 150         snprintf(score_s, sizeof(score_s), "%d", score);
 151     }
 152 
 153     return score_s;
 154 }
 155 
 156 /*!
 157  * \internal
 158  * \brief Add two scores, bounding to +/-INFINITY
 159  *
 160  * \param[in] score1  First score to add
 161  * \param[in] score2  Second score to add
 162  *
 163  * \note This function does not have context about what the scores mean, so it
 164  *       does not log any messages.
 165  */
 166 int
 167 pcmk__add_scores(int score1, int score2)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169     /* As long as PCMK_SCORE_INFINITY is less than half of the maximum integer,
 170      * we can ignore the possibility of integer overflow.
 171      */
 172     int result = score1 + score2;
 173 
 174     // First handle the cases where one or both is infinite
 175     if ((score1 <= -PCMK_SCORE_INFINITY) || (score2 <= -PCMK_SCORE_INFINITY)) {
 176         return -PCMK_SCORE_INFINITY;
 177     }
 178     if ((score1 >= PCMK_SCORE_INFINITY) || (score2 >= PCMK_SCORE_INFINITY)) {
 179         return PCMK_SCORE_INFINITY;
 180     }
 181 
 182     // Bound result to infinity.
 183     if (result >= PCMK_SCORE_INFINITY) {
 184         return PCMK_SCORE_INFINITY;
 185     }
 186     if (result <= -PCMK_SCORE_INFINITY) {
 187         return -PCMK_SCORE_INFINITY;
 188     }
 189 
 190     return result;
 191 }
 192 
 193 // Deprecated functions kept only for backward API compatibility
 194 // LCOV_EXCL_START
 195 
 196 #include <crm/common/scores_compat.h>
 197 
 198 char *
 199 score2char(int score)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201     return pcmk__str_copy(pcmk_readable_score(score));
 202 }
 203 
 204 char *
 205 score2char_stack(int score, char *buf, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207     CRM_CHECK((buf != NULL) && (len >= sizeof(PCMK_VALUE_MINUS_INFINITY)),
 208               return NULL);
 209     strcpy(buf, pcmk_readable_score(score));
 210     return buf;
 211 }
 212 
 213 // LCOV_EXCL_STOP
 214 // End deprecated API

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