pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
strings.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 <regex.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <float.h> // DBL_MIN
22 #include <limits.h>
23 #include <math.h> // fabs()
24 #include <bzlib.h>
25 #include <sys/types.h>
26 
27 char *
28 crm_itoa_stack(int an_int, char *buffer, size_t len)
29 {
30  if (buffer != NULL) {
31  snprintf(buffer, len, "%d", an_int);
32  }
33 
34  return buffer;
35 }
36 
50 static int
51 scan_ll(const char *text, long long *result, char **end_text)
52 {
53  long long local_result = PCMK__PARSE_INT_DEFAULT;
54  char *local_end_text = NULL;
55  int rc = pcmk_rc_ok;
56 
57  errno = 0;
58  if (text != NULL) {
59 #ifdef ANSI_ONLY
60  local_result = (long long) strtol(text, &local_end_text, 10);
61 #else
62  local_result = strtoll(text, &local_end_text, 10);
63 #endif
64  if (errno == ERANGE) {
65  rc = EOVERFLOW;
66  crm_warn("Integer parsed from %s was clipped to %lld",
67  text, local_result);
68 
69  } else if (errno != 0) {
70  rc = errno;
71  local_result = PCMK__PARSE_INT_DEFAULT;
72  crm_warn("Could not parse integer from %s (using %d instead): %s",
74 
75  } else if (local_end_text == text) {
76  rc = EINVAL;
77  local_result = PCMK__PARSE_INT_DEFAULT;
78  crm_warn("Could not parse integer from %s (using %d instead): "
79  "No digits found", text, PCMK__PARSE_INT_DEFAULT);
80  }
81 
82  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
83  crm_warn("Characters left over after parsing '%s': '%s'",
84  text, local_end_text);
85  }
86  errno = rc;
87  }
88  if (end_text != NULL) {
89  *end_text = local_end_text;
90  }
91  if (result != NULL) {
92  *result = local_result;
93  }
94  return rc;
95 }
96 
106 long long
107 crm_parse_ll(const char *text, const char *default_text)
108 {
109  long long result;
110 
111  if (text == NULL) {
112  text = default_text;
113  if (text == NULL) {
114  crm_err("No default conversion value supplied");
115  errno = EINVAL;
117  }
118  }
119  scan_ll(text, &result, NULL);
120  return result;
121 }
122 
133 int
134 crm_parse_int(const char *text, const char *default_text)
135 {
136  long long result = crm_parse_ll(text, default_text);
137 
138  if (result < INT_MIN) {
139  // If errno is ERANGE, crm_parse_ll() has already logged a message
140  if (errno != ERANGE) {
141  crm_err("Conversion of %s was clipped: %lld", text, result);
142  errno = ERANGE;
143  }
144  return INT_MIN;
145 
146  } else if (result > INT_MAX) {
147  // If errno is ERANGE, crm_parse_ll() has already logged a message
148  if (errno != ERANGE) {
149  crm_err("Conversion of %s was clipped: %lld", text, result);
150  errno = ERANGE;
151  }
152  return INT_MAX;
153  }
154 
155  return (int) result;
156 }
157 
177 int
178 pcmk__scan_double(const char *text, double *result, const char *default_text,
179  char **end_text)
180 {
181  int rc = pcmk_rc_ok;
182  char *local_end_text = NULL;
183 
184  CRM_ASSERT(result != NULL);
185  *result = PCMK__PARSE_DBL_DEFAULT;
186 
187  text = (text != NULL) ? text : default_text;
188 
189  if (text == NULL) {
190  rc = EINVAL;
191  crm_debug("No text and no default conversion value supplied");
192 
193  } else {
194  errno = 0;
195  *result = strtod(text, &local_end_text);
196 
197  if (errno == ERANGE) {
198  /*
199  * Overflow: strtod() returns +/- HUGE_VAL and sets errno to
200  * ERANGE
201  *
202  * Underflow: strtod() returns "a value whose magnitude is
203  * no greater than the smallest normalized
204  * positive" double. Whether ERANGE is set is
205  * implementation-defined.
206  */
207  const char *over_under;
208 
209  if (fabs(*result) > DBL_MIN) {
210  rc = EOVERFLOW;
211  over_under = "over";
212  } else {
214  over_under = "under";
215  }
216 
217  crm_debug("Floating-point value parsed from '%s' would %sflow "
218  "(using %g instead)", text, over_under, *result);
219 
220  } else if (errno != 0) {
221  rc = errno;
222  // strtod() set *result = 0 on parse failure
223  *result = PCMK__PARSE_DBL_DEFAULT;
224 
225  crm_debug("Could not parse floating-point value from '%s' (using "
226  "%.1f instead): %s", text, PCMK__PARSE_DBL_DEFAULT,
227  pcmk_rc_str(rc));
228 
229  } else if (local_end_text == text) {
230  // errno == 0, but nothing was parsed
231  rc = EINVAL;
232  *result = PCMK__PARSE_DBL_DEFAULT;
233 
234  crm_debug("Could not parse floating-point value from '%s' (using "
235  "%.1f instead): No digits found", text,
237 
238  } else if (fabs(*result) <= DBL_MIN) {
239  /*
240  * errno == 0 and text was parsed, but value might have
241  * underflowed.
242  *
243  * ERANGE might not be set for underflow. Check magnitude
244  * of *result, but also make sure the input number is not
245  * actually zero (0 <= DBL_MIN is not underflow).
246  *
247  * This check must come last. A parse failure in strtod()
248  * also sets *result == 0, so a parse failure would match
249  * this test condition prematurely.
250  */
251  for (const char *p = text; p != local_end_text; p++) {
252  if (strchr("0.eE", *p) == NULL) {
254  crm_debug("Floating-point value parsed from '%s' would "
255  "underflow (using %g instead)", text, *result);
256  break;
257  }
258  }
259 
260  } else {
261  crm_trace("Floating-point value parsed successfully from "
262  "'%s': %g", text, *result);
263  }
264 
265  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
266  crm_debug("Characters left over after parsing '%s': '%s'",
267  text, local_end_text);
268  }
269  }
270 
271  if (end_text != NULL) {
272  *end_text = local_end_text;
273  }
274 
275  return rc;
276 }
277 
289 int
290 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
291  guint *result)
292 {
293  const char *value;
294  long long value_ll;
295 
296  CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
297 
298  value = g_hash_table_lookup(table, key);
299  if (value == NULL) {
300  if (result != NULL) {
301  *result = default_val;
302  }
303  return pcmk_rc_ok;
304  }
305 
306  errno = 0;
307  value_ll = crm_parse_ll(value, NULL);
308  if (errno != 0) {
309  return errno; // Message already logged
310  }
311  if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
312  crm_warn("Could not parse non-negative integer from %s", value);
313  return ERANGE;
314  }
315 
316  if (result != NULL) {
317  *result = (guint) value_ll;
318  }
319  return pcmk_rc_ok;
320 }
321 
322 #ifndef NUMCHARS
323 # define NUMCHARS "0123456789."
324 #endif
325 
326 #ifndef WHITESPACE
327 # define WHITESPACE " \t\n\r\f"
328 #endif
329 
339 long long
340 crm_get_msec(const char *input)
341 {
342  const char *num_start = NULL;
343  const char *units;
344  long long multiplier = 1000;
345  long long divisor = 1;
346  long long msec = PCMK__PARSE_INT_DEFAULT;
347  size_t num_len = 0;
348  char *end_text = NULL;
349 
350  if (input == NULL) {
352  }
353 
354  num_start = input + strspn(input, WHITESPACE);
355  num_len = strspn(num_start, NUMCHARS);
356  if (num_len < 1) {
358  }
359  units = num_start + num_len;
360  units += strspn(units, WHITESPACE);
361 
362  if (!strncasecmp(units, "ms", 2) || !strncasecmp(units, "msec", 4)) {
363  multiplier = 1;
364  divisor = 1;
365  } else if (!strncasecmp(units, "us", 2) || !strncasecmp(units, "usec", 4)) {
366  multiplier = 1;
367  divisor = 1000;
368  } else if (!strncasecmp(units, "s", 1) || !strncasecmp(units, "sec", 3)) {
369  multiplier = 1000;
370  divisor = 1;
371  } else if (!strncasecmp(units, "m", 1) || !strncasecmp(units, "min", 3)) {
372  multiplier = 60 * 1000;
373  divisor = 1;
374  } else if (!strncasecmp(units, "h", 1) || !strncasecmp(units, "hr", 2)) {
375  multiplier = 60 * 60 * 1000;
376  divisor = 1;
377  } else if ((*units != EOS) && (*units != '\n') && (*units != '\r')) {
379  }
380 
381  scan_ll(num_start, &msec, &end_text);
382  if (msec > (LLONG_MAX / multiplier)) {
383  // Arithmetics overflow while multiplier/divisor mutually exclusive
384  return LLONG_MAX;
385  }
386  msec *= multiplier;
387  msec /= divisor;
388  return msec;
389 }
390 
391 gboolean
392 crm_is_true(const char *s)
393 {
394  gboolean ret = FALSE;
395 
396  if (s != NULL) {
397  crm_str_to_boolean(s, &ret);
398  }
399  return ret;
400 }
401 
402 int
403 crm_str_to_boolean(const char *s, int *ret)
404 {
405  if (s == NULL) {
406  return -1;
407 
408  } else if (strcasecmp(s, "true") == 0
409  || strcasecmp(s, "on") == 0
410  || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
411  *ret = TRUE;
412  return 1;
413 
414  } else if (strcasecmp(s, "false") == 0
415  || strcasecmp(s, "off") == 0
416  || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
417  *ret = FALSE;
418  return 1;
419  }
420  return -1;
421 }
422 
423 char *
425 {
426  int len;
427 
428  if (str == NULL) {
429  return str;
430  }
431 
432  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
433  str[len] = '\0';
434  }
435 
436  return str;
437 }
438 
451 bool
452 pcmk__starts_with(const char *str, const char *prefix)
453 {
454  const char *s = str;
455  const char *p = prefix;
456 
457  if (!s || !p) {
458  return false;
459  }
460  while (*s && *p) {
461  if (*s++ != *p++) {
462  return false;
463  }
464  }
465  return (*p == 0);
466 }
467 
468 static inline bool
469 ends_with(const char *s, const char *match, bool as_extension)
470 {
471  if (pcmk__str_empty(match)) {
472  return true;
473  } else if (s == NULL) {
474  return false;
475  } else {
476  size_t slen, mlen;
477 
478  /* Besides as_extension, we could also check
479  !strchr(&match[1], match[0]) but that would be inefficient.
480  */
481  if (as_extension) {
482  s = strrchr(s, match[0]);
483  return (s == NULL)? false : !strcmp(s, match);
484  }
485 
486  mlen = strlen(match);
487  slen = strlen(s);
488  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
489  }
490 }
491 
503 bool
504 pcmk__ends_with(const char *s, const char *match)
505 {
506  return ends_with(s, match, false);
507 }
508 
530 bool
531 pcmk__ends_with_ext(const char *s, const char *match)
532 {
533  return ends_with(s, match, true);
534 }
535 
536 /*
537  * This re-implements g_str_hash as it was prior to glib2-2.28:
538  *
539  * https://gitlab.gnome.org/GNOME/glib/commit/354d655ba8a54b754cb5a3efb42767327775696c
540  *
541  * Note that the new g_str_hash is presumably a *better* hash (it's actually
542  * a correct implementation of DJB's hash), but we need to preserve existing
543  * behaviour, because the hash key ultimately determines the "sort" order
544  * when iterating through GHashTables, which affects allocation of scores to
545  * clone instances when iterating through rsc->allowed_nodes. It (somehow)
546  * also appears to have some minor impact on the ordering of a few
547  * pseudo_event IDs in the transition graph.
548  */
549 guint
550 g_str_hash_traditional(gconstpointer v)
551 {
552  const signed char *p;
553  guint32 h = 0;
554 
555  for (p = v; *p != '\0'; p++)
556  h = (h << 5) - h + *p;
557 
558  return h;
559 }
560 
561 /* used with hash tables where case does not matter */
562 gboolean
563 crm_strcase_equal(gconstpointer a, gconstpointer b)
564 {
565  return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
566 }
567 
568 guint
569 crm_strcase_hash(gconstpointer v)
570 {
571  const signed char *p;
572  guint32 h = 0;
573 
574  for (p = v; *p != '\0'; p++)
575  h = (h << 5) - h + g_ascii_tolower(*p);
576 
577  return h;
578 }
579 
580 static void
581 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
582 {
583  if (key && value && user_data) {
584  g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
585  }
586 }
587 
588 GHashTable *
589 crm_str_table_dup(GHashTable *old_table)
590 {
591  GHashTable *new_table = NULL;
592 
593  if (old_table) {
594  new_table = crm_str_table_new();
595  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
596  }
597  return new_table;
598 }
599 
616 void
617 pcmk__add_separated_word(char **list, size_t *len, const char *word,
618  const char *separator)
619 {
620  size_t orig_len, new_len;
621 
622  CRM_ASSERT(list != NULL);
623 
624  if (pcmk__str_empty(word)) {
625  return;
626  }
627 
628  // Use provided length, or calculate it if not available
629  orig_len = (len != NULL)? *len : ((*list == NULL)? 0 : strlen(*list));
630 
631  // Don't add a separator before the first word in the list
632  if (orig_len == 0) {
633  separator = "";
634 
635  // Default to space-separated
636  } else if (separator == NULL) {
637  separator = " ";
638  }
639 
640  new_len = orig_len + strlen(separator) + strlen(word);
641  if (len != NULL) {
642  *len = new_len;
643  }
644 
645  // +1 for null terminator
646  *list = pcmk__realloc(*list, new_len + 1);
647  sprintf(*list + orig_len, "%s%s", separator, word);
648 }
649 
662 int
663 pcmk__compress(const char *data, unsigned int length, unsigned int max,
664  char **result, unsigned int *result_len)
665 {
666  int rc;
667  char *compressed = NULL;
668  char *uncompressed = strdup(data);
669 #ifdef CLOCK_MONOTONIC
670  struct timespec after_t;
671  struct timespec before_t;
672 #endif
673 
674  if (max == 0) {
675  max = (length * 1.01) + 601; // Size guaranteed to hold result
676  }
677 
678 #ifdef CLOCK_MONOTONIC
679  clock_gettime(CLOCK_MONOTONIC, &before_t);
680 #endif
681 
682  compressed = calloc((size_t) max, sizeof(char));
683  CRM_ASSERT(compressed);
684 
685  *result_len = max;
686  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
688  free(uncompressed);
689  if (rc != BZ_OK) {
690  crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
691  length, bz2_strerror(rc), rc);
692  free(compressed);
693  return pcmk_rc_error;
694  }
695 
696 #ifdef CLOCK_MONOTONIC
697  clock_gettime(CLOCK_MONOTONIC, &after_t);
698 
699  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
700  length, *result_len, length / (*result_len),
701  (after_t.tv_sec - before_t.tv_sec) * 1000 +
702  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
703 #else
704  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
705  length, *result_len, length / (*result_len));
706 #endif
707 
708  *result = compressed;
709  return pcmk_rc_ok;
710 }
711 
712 char *
713 crm_strdup_printf(char const *format, ...)
714 {
715  va_list ap;
716  int len = 0;
717  char *string = NULL;
718 
719  va_start(ap, format);
720  len = vasprintf (&string, format, ap);
721  CRM_ASSERT(len > 0);
722  va_end(ap);
723  return string;
724 }
725 
726 int
727 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
728 {
729  char *remainder = NULL;
730 
731  CRM_ASSERT(start != NULL && end != NULL);
732 
733  *start = PCMK__PARSE_INT_DEFAULT;
735 
736  crm_trace("Attempting to decode: [%s]", srcstring);
737  if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
738  return pcmk_rc_unknown_format;
739  }
740 
741  /* String starts with a dash, so this is either a range with
742  * no beginning or garbage.
743  * */
744  if (*srcstring == '-') {
745  int rc = scan_ll(srcstring+1, end, &remainder);
746 
747  if (rc != pcmk_rc_ok || *remainder != '\0') {
748  return pcmk_rc_unknown_format;
749  } else {
750  return pcmk_rc_ok;
751  }
752  }
753 
754  if (scan_ll(srcstring, start, &remainder) != pcmk_rc_ok) {
755  return pcmk_rc_unknown_format;
756  }
757 
758  if (*remainder && *remainder == '-') {
759  if (*(remainder+1)) {
760  char *more_remainder = NULL;
761  int rc = scan_ll(remainder+1, end, &more_remainder);
762 
763  if (rc != pcmk_rc_ok || *more_remainder != '\0') {
764  return pcmk_rc_unknown_format;
765  }
766  }
767  } else if (*remainder && *remainder != '-') {
768  *start = PCMK__PARSE_INT_DEFAULT;
769  return pcmk_rc_unknown_format;
770  } else {
771  /* The input string contained only one number. Set start and end
772  * to the same value and return pcmk_rc_ok. This gives the caller
773  * a way to tell this condition apart from a range with no end.
774  */
775  *end = *start;
776  }
777 
778  return pcmk_rc_ok;
779 }
780 
793 gboolean
794 pcmk__str_in_list(GList *lst, const gchar *s)
795 {
796  if (lst == NULL) {
797  return FALSE;
798  }
799 
800  if (strcmp(lst->data, "*") == 0 && lst->next == NULL) {
801  return TRUE;
802  }
803 
804  return g_list_find_custom(lst, s, (GCompareFunc) strcmp) != NULL;
805 }
806 
807 static bool
808 str_any_of(bool casei, const char *s, va_list args)
809 {
810  bool rc = false;
811 
812  if (s != NULL) {
813  while (1) {
814  const char *ele = va_arg(args, const char *);
815 
816  if (ele == NULL) {
817  break;
818  } else if (pcmk__str_eq(s, ele,
819  casei? pcmk__str_casei : pcmk__str_none)) {
820  rc = true;
821  break;
822  }
823  }
824  }
825  return rc;
826 }
827 
841 bool
842 pcmk__strcase_any_of(const char *s, ...)
843 {
844  va_list ap;
845  bool rc;
846 
847  va_start(ap, s);
848  rc = str_any_of(true, s, ap);
849  va_end(ap);
850  return rc;
851 }
852 
865 bool
866 pcmk__str_any_of(const char *s, ...)
867 {
868  va_list ap;
869  bool rc;
870 
871  va_start(ap, s);
872  rc = str_any_of(false, s, ap);
873  va_end(ap);
874  return rc;
875 }
876 
888 bool
890 {
891  bool rc = false;
892  va_list ap;
893 
894  /*
895  * Passing a char to va_start() can generate compiler warnings,
896  * so ch is declared as an int.
897  */
898  va_start(ap, ch);
899 
900  while (1) {
901  const char *ele = va_arg(ap, const char *);
902 
903  if (ele == NULL) {
904  break;
905  } else if (strchr(ele, ch) != NULL) {
906  rc = true;
907  break;
908  }
909  }
910 
911  va_end(ap);
912  return rc;
913 }
914 
930 int
931 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
932 {
933  while (*s1 && *s2) {
934  if (isdigit(*s1) && isdigit(*s2)) {
935  // If node names contain a number, sort numerically
936 
937  char *end1 = NULL;
938  char *end2 = NULL;
939  long num1 = strtol(s1, &end1, 10);
940  long num2 = strtol(s2, &end2, 10);
941 
942  // allow ordering e.g. 007 > 7
943  size_t len1 = end1 - s1;
944  size_t len2 = end2 - s2;
945 
946  if (num1 < num2) {
947  return -1;
948  } else if (num1 > num2) {
949  return 1;
950  } else if (len1 < len2) {
951  return -1;
952  } else if (len1 > len2) {
953  return 1;
954  }
955  s1 = end1;
956  s2 = end2;
957  } else {
958  // Compare non-digits case-insensitively
959  int lower1 = tolower(*s1);
960  int lower2 = tolower(*s2);
961 
962  if (lower1 < lower2) {
963  return -1;
964  } else if (lower1 > lower2) {
965  return 1;
966  }
967  ++s1;
968  ++s2;
969  }
970  }
971  if (!*s1 && *s2) {
972  return -1;
973  } else if (*s1 && !*s2) {
974  return 1;
975  }
976  return 0;
977 }
978 
979 /*
980  * \brief Sort strings.
981  *
982  * This is your one-stop function for string comparison. By default, this
983  * function works like g_strcmp0. That is, like strcmp but a NULL string
984  * sorts before a non-NULL string.
985  *
986  * Behavior can be changed with various flags:
987  *
988  * - pcmk__str_regex - The second string is a regular expression that the
989  * first string will be matched against.
990  * - pcmk__str_casei - By default, comparisons are done taking case into
991  * account. This flag makes comparisons case-insensitive.
992  * This can be combined with pcmk__str_regex.
993  * - pcmk__str_null_matches - If one string is NULL and the other is not,
994  * still return 0.
995  *
996  * \param[in] s1 First string to compare
997  * \param[in] s2 Second string to compare, or a regular expression to
998  * match if pcmk__str_regex is set
999  * \param[in] flags A bitfield of pcmk__str_flags to modify operation
1000  *
1001  * \retval -1 \p s1 is NULL or comes before \p s2
1002  * \retval 0 \p s1 and \p s2 are equal, or \p s1 is found in \p s2 if
1003  * pcmk__str_regex is set
1004  * \retval 1 \p s2 is NULL or \p s1 comes after \p s2, or if \p s2
1005  * is an invalid regular expression, or \p s1 was not found
1006  * in \p s2 if pcmk__str_regex is set.
1007  */
1008 int
1009 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1010 {
1011  /* If this flag is set, the second string is a regex. */
1013  regex_t *r_patt = calloc(1, sizeof(regex_t));
1014  int reg_flags = REG_EXTENDED | REG_NOSUB;
1015  int regcomp_rc = 0;
1016  int rc = 0;
1017 
1018  if (s1 == NULL || s2 == NULL) {
1019  free(r_patt);
1020  return 1;
1021  }
1022 
1024  reg_flags |= REG_ICASE;
1025  }
1026  regcomp_rc = regcomp(r_patt, s2, reg_flags);
1027  if (regcomp_rc != 0) {
1028  rc = 1;
1029  crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1030  } else {
1031  rc = regexec(r_patt, s1, 0, NULL, 0);
1032 
1033  if (rc != 0) {
1034  rc = 1;
1035  }
1036  }
1037 
1038  regfree(r_patt);
1039  free(r_patt);
1040  return rc;
1041  }
1042 
1043  /* If the strings are the same pointer, return 0 immediately. */
1044  if (s1 == s2) {
1045  return 0;
1046  }
1047 
1048  /* If this flag is set, return 0 if either (or both) of the input strings
1049  * are NULL. If neither one is NULL, we need to continue and compare
1050  * them normally.
1051  */
1053  if (s1 == NULL || s2 == NULL) {
1054  return 0;
1055  }
1056  }
1057 
1058  /* Handle the cases where one is NULL and the str_null_matches flag is not set.
1059  * A NULL string always sorts to the beginning.
1060  */
1061  if (s1 == NULL) {
1062  return -1;
1063  } else if (s2 == NULL) {
1064  return 1;
1065  }
1066 
1068  return strcasecmp(s1, s2);
1069  } else {
1070  return strcmp(s1, s2);
1071  }
1072 }
1073 
1074 // Deprecated functions kept only for backward API compatibility
1075 
1076 gboolean safe_str_neq(const char *a, const char *b);
1077 
1078 gboolean crm_str_eq(const char *a, const char *b, gboolean use_case);
1079 
1081 gboolean
1082 safe_str_neq(const char *a, const char *b)
1083 {
1084  if (a == b) {
1085  return FALSE;
1086 
1087  } else if (a == NULL || b == NULL) {
1088  return TRUE;
1089 
1090  } else if (strcasecmp(a, b) == 0) {
1091  return FALSE;
1092  }
1093  return TRUE;
1094 }
1095 
1097 gboolean
1098 crm_str_eq(const char *a, const char *b, gboolean use_case)
1099 {
1100  if (use_case) {
1101  return g_strcmp0(a, b) == 0;
1102 
1103  /* TODO - Figure out which calls, if any, really need to be case independent */
1104  } else if (a == b) {
1105  return TRUE;
1106 
1107  } else if (a == NULL || b == NULL) {
1108  /* shouldn't be comparing NULLs */
1109  return FALSE;
1110 
1111  } else if (strcasecmp(a, b) == 0) {
1112  return TRUE;
1113  }
1114  return FALSE;
1115 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:452
const char * bz2_strerror(int rc)
Definition: results.c:726
char * crm_strdup_printf(char const *format,...)
Definition: strings.c:713
int pcmk_numeric_strcasecmp(const char *s1, const char *s2)
Sort strings, with numeric portions sorted numerically.
Definition: strings.c:931
guint g_str_hash_traditional(gconstpointer v)
Definition: strings.c:550
#define PCMK__PARSE_DBL_DEFAULT
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
Definition: strings.c:794
bool pcmk__str_any_of(const char *s,...)
Definition: strings.c:866
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:178
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:420
char * strerror(int errnum)
#define CRM_BZ2_WORK
Definition: xml.h:46
#define PCMK__PARSE_INT_DEFAULT
#define crm_warn(fmt, args...)
Definition: logging.h:348
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:290
int rc
Definition: pcmk_fence.c:35
#define crm_debug(fmt, args...)
Definition: logging.h:352
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:727
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
Definition: strings.c:663
#define crm_trace(fmt, args...)
Definition: logging.h:353
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:196
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:340
#define EOS
Definition: crm.h:56
char * crm_itoa_stack(int an_int, char *buffer, size_t len)
Definition: strings.c:28
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:403
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition: strings.c:617
#define CRM_XS
Definition: logging.h:54
char * crm_strip_trailing_newline(char *str)
Definition: strings.c:424
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
Definition: strings.c:1009
gboolean crm_is_true(const char *s)
Definition: strings.c:392
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:531
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:1098
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:134
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
Definition: strings.c:107
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
char data[0]
Definition: internal.h:90
gboolean crm_strcase_equal(gconstpointer a, gconstpointer b)
Definition: strings.c:563
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:1082
guint crm_strcase_hash(gconstpointer v)
Definition: strings.c:569
#define CRM_BZ2_BLOCKS
Definition: xml.h:45
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:589
#define WHITESPACE
Definition: strings.c:327
bool pcmk__char_in_any_str(int ch,...)
Definition: strings.c:889
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:504
#define NUMCHARS
Definition: strings.c:323
uint64_t flags
Definition: remote.c:149
bool pcmk__strcase_any_of(const char *s,...)
Definition: strings.c:842