This source file includes following definitions.
- scan_ll
- pcmk__scan_ll
- pcmk__scan_min_int
- pcmk__scan_port
- pcmk__scan_double
- pcmk__guint_from_hash
- crm_get_msec
- crm_is_true
- crm_str_to_boolean
- pcmk__trim
- pcmk__starts_with
- ends_with
- pcmk__ends_with
- pcmk__ends_with_ext
- pcmk__str_hash
- pcmk__strkey_table
- pcmk__strcase_equal
- pcmk__strcase_hash
- pcmk__strikey_table
- copy_str_table_entry
- pcmk__str_table_dup
- pcmk__add_separated_word
- pcmk__compress
- crm_strdup_printf
- pcmk__parse_ll_range
- pcmk__str_in_list
- str_any_of
- pcmk__strcase_any_of
- pcmk__str_any_of
- pcmk__char_in_any_str
- pcmk__numeric_strcasecmp
- pcmk__strcmp
- safe_str_neq
- crm_str_eq
- crm_itoa_stack
- g_str_hash_traditional
- crm_strcase_equal
- crm_strcase_hash
- crm_str_table_dup
- crm_parse_ll
- crm_parse_int
- crm_strip_trailing_newline
- pcmk_numeric_strcasecmp
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <regex.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <float.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <bzlib.h>
25 #include <sys/types.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 static int
43 scan_ll(const char *text, long long *result, long long default_value,
44 char **end_text)
45 {
46 long long local_result = default_value;
47 char *local_end_text = NULL;
48 int rc = pcmk_rc_ok;
49
50 errno = 0;
51 if (text != NULL) {
52 local_result = strtoll(text, &local_end_text, 10);
53 if (errno == ERANGE) {
54 rc = EOVERFLOW;
55 crm_warn("Integer parsed from '%s' was clipped to %lld",
56 text, local_result);
57
58 } else if (errno != 0) {
59 rc = errno;
60 local_result = default_value;
61 crm_warn("Could not parse integer from '%s' (using %lld instead): "
62 "%s", text, default_value, pcmk_rc_str(rc));
63
64 } else if (local_end_text == text) {
65 rc = EINVAL;
66 local_result = default_value;
67 crm_warn("Could not parse integer from '%s' (using %lld instead): "
68 "No digits found", text, default_value);
69 }
70
71 if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
72 crm_warn("Characters left over after parsing '%s': '%s'",
73 text, local_end_text);
74 }
75 errno = rc;
76 }
77 if (end_text != NULL) {
78 *end_text = local_end_text;
79 }
80 if (result != NULL) {
81 *result = local_result;
82 }
83 return rc;
84 }
85
86
87
88
89
90
91
92
93
94
95
96 int
97 pcmk__scan_ll(const char *text, long long *result, long long default_value)
98 {
99 long long local_result = default_value;
100 int rc = pcmk_rc_ok;
101
102 if (text != NULL) {
103 rc = scan_ll(text, &local_result, default_value, NULL);
104 if (rc != pcmk_rc_ok) {
105 local_result = default_value;
106 }
107 }
108 if (result != NULL) {
109 *result = local_result;
110 }
111 return rc;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126 int
127 pcmk__scan_min_int(const char *text, int *result, int minimum)
128 {
129 int rc;
130 long long result_ll;
131
132 rc = pcmk__scan_ll(text, &result_ll, (long long) minimum);
133
134 if (result_ll < (long long) minimum) {
135 crm_warn("Clipped '%s' to minimum acceptable value %d", text, minimum);
136 result_ll = (long long) minimum;
137
138 } else if (result_ll > INT_MAX) {
139 crm_warn("Clipped '%s' to maximum integer %d", text, INT_MAX);
140 result_ll = (long long) INT_MAX;
141 rc = EOVERFLOW;
142 }
143
144 if (result != NULL) {
145 *result = (int) result_ll;
146 }
147 return rc;
148 }
149
150
151
152
153
154
155
156
157
158
159
160 int
161 pcmk__scan_port(const char *text, int *port)
162 {
163 long long port_ll;
164 int rc = pcmk__scan_ll(text, &port_ll, -1LL);
165
166 if ((text != NULL) && (rc == pcmk_rc_ok)
167 && ((port_ll < 0LL) || (port_ll > 65535LL))) {
168 crm_warn("Ignoring port specification '%s' "
169 "not in valid range (0-65535)", text);
170 rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range;
171 port_ll = -1LL;
172 }
173 if (port != NULL) {
174 *port = (int) port_ll;
175 }
176 return rc;
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 int
199 pcmk__scan_double(const char *text, double *result, const char *default_text,
200 char **end_text)
201 {
202 int rc = pcmk_rc_ok;
203 char *local_end_text = NULL;
204
205 CRM_ASSERT(result != NULL);
206 *result = PCMK__PARSE_DBL_DEFAULT;
207
208 text = (text != NULL) ? text : default_text;
209
210 if (text == NULL) {
211 rc = EINVAL;
212 crm_debug("No text and no default conversion value supplied");
213
214 } else {
215 errno = 0;
216 *result = strtod(text, &local_end_text);
217
218 if (errno == ERANGE) {
219
220
221
222
223
224
225
226
227
228 const char *over_under;
229
230 if (fabs(*result) > DBL_MIN) {
231 rc = EOVERFLOW;
232 over_under = "over";
233 } else {
234 rc = pcmk_rc_underflow;
235 over_under = "under";
236 }
237
238 crm_debug("Floating-point value parsed from '%s' would %sflow "
239 "(using %g instead)", text, over_under, *result);
240
241 } else if (errno != 0) {
242 rc = errno;
243
244 *result = PCMK__PARSE_DBL_DEFAULT;
245
246 crm_debug("Could not parse floating-point value from '%s' (using "
247 "%.1f instead): %s", text, PCMK__PARSE_DBL_DEFAULT,
248 pcmk_rc_str(rc));
249
250 } else if (local_end_text == text) {
251
252 rc = EINVAL;
253 *result = PCMK__PARSE_DBL_DEFAULT;
254
255 crm_debug("Could not parse floating-point value from '%s' (using "
256 "%.1f instead): No digits found", text,
257 PCMK__PARSE_DBL_DEFAULT);
258
259 } else if (fabs(*result) <= DBL_MIN) {
260
261
262
263
264
265
266
267
268
269
270
271
272 for (const char *p = text; p != local_end_text; p++) {
273 if (strchr("0.eE", *p) == NULL) {
274 rc = pcmk_rc_underflow;
275 crm_debug("Floating-point value parsed from '%s' would "
276 "underflow (using %g instead)", text, *result);
277 break;
278 }
279 }
280
281 } else {
282 crm_trace("Floating-point value parsed successfully from "
283 "'%s': %g", text, *result);
284 }
285
286 if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
287 crm_debug("Characters left over after parsing '%s': '%s'",
288 text, local_end_text);
289 }
290 }
291
292 if (end_text != NULL) {
293 *end_text = local_end_text;
294 }
295
296 return rc;
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310 int
311 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
312 guint *result)
313 {
314 const char *value;
315 long long value_ll;
316 int rc = pcmk_rc_ok;
317
318 CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
319
320 if (result != NULL) {
321 *result = default_val;
322 }
323
324 value = g_hash_table_lookup(table, key);
325 if (value == NULL) {
326 return pcmk_rc_ok;
327 }
328
329 rc = pcmk__scan_ll(value, &value_ll, 0LL);
330 if (rc != pcmk_rc_ok) {
331 return rc;
332 }
333
334 if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
335 crm_warn("Could not parse non-negative integer from %s", value);
336 return ERANGE;
337 }
338
339 if (result != NULL) {
340 *result = (guint) value_ll;
341 }
342 return pcmk_rc_ok;
343 }
344
345 #ifndef NUMCHARS
346 # define NUMCHARS "0123456789."
347 #endif
348
349 #ifndef WHITESPACE
350 # define WHITESPACE " \t\n\r\f"
351 #endif
352
353
354
355
356
357
358
359
360
361
362 long long
363 crm_get_msec(const char *input)
364 {
365 const char *num_start = NULL;
366 const char *units;
367 long long multiplier = 1000;
368 long long divisor = 1;
369 long long msec = PCMK__PARSE_INT_DEFAULT;
370 size_t num_len = 0;
371 char *end_text = NULL;
372
373 if (input == NULL) {
374 return PCMK__PARSE_INT_DEFAULT;
375 }
376
377 num_start = input + strspn(input, WHITESPACE);
378 num_len = strspn(num_start, NUMCHARS);
379 if (num_len < 1) {
380 return PCMK__PARSE_INT_DEFAULT;
381 }
382 units = num_start + num_len;
383 units += strspn(units, WHITESPACE);
384
385 if (!strncasecmp(units, "ms", 2) || !strncasecmp(units, "msec", 4)) {
386 multiplier = 1;
387 divisor = 1;
388 } else if (!strncasecmp(units, "us", 2) || !strncasecmp(units, "usec", 4)) {
389 multiplier = 1;
390 divisor = 1000;
391 } else if (!strncasecmp(units, "s", 1) || !strncasecmp(units, "sec", 3)) {
392 multiplier = 1000;
393 divisor = 1;
394 } else if (!strncasecmp(units, "m", 1) || !strncasecmp(units, "min", 3)) {
395 multiplier = 60 * 1000;
396 divisor = 1;
397 } else if (!strncasecmp(units, "h", 1) || !strncasecmp(units, "hr", 2)) {
398 multiplier = 60 * 60 * 1000;
399 divisor = 1;
400 } else if ((*units != '\0') && (*units != '\n') && (*units != '\r')) {
401 return PCMK__PARSE_INT_DEFAULT;
402 }
403
404 scan_ll(num_start, &msec, PCMK__PARSE_INT_DEFAULT, &end_text);
405 if (msec > (LLONG_MAX / multiplier)) {
406
407 return LLONG_MAX;
408 }
409 msec *= multiplier;
410 msec /= divisor;
411 return msec;
412 }
413
414 gboolean
415 crm_is_true(const char *s)
416 {
417 gboolean ret = FALSE;
418
419 if (s != NULL) {
420 crm_str_to_boolean(s, &ret);
421 }
422 return ret;
423 }
424
425 int
426 crm_str_to_boolean(const char *s, int *ret)
427 {
428 if (s == NULL) {
429 return -1;
430
431 } else if (strcasecmp(s, "true") == 0
432 || strcasecmp(s, "on") == 0
433 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
434 *ret = TRUE;
435 return 1;
436
437 } else if (strcasecmp(s, "false") == 0
438 || strcasecmp(s, "off") == 0
439 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
440 *ret = FALSE;
441 return 1;
442 }
443 return -1;
444 }
445
446
447
448
449
450
451
452
453
454 char *
455 pcmk__trim(char *str)
456 {
457 int len;
458
459 if (str == NULL) {
460 return str;
461 }
462
463 for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
464 str[len] = '\0';
465 }
466
467 return str;
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481
482 bool
483 pcmk__starts_with(const char *str, const char *prefix)
484 {
485 const char *s = str;
486 const char *p = prefix;
487
488 if (!s || !p) {
489 return false;
490 }
491 while (*s && *p) {
492 if (*s++ != *p++) {
493 return false;
494 }
495 }
496 return (*p == 0);
497 }
498
499 static inline bool
500 ends_with(const char *s, const char *match, bool as_extension)
501 {
502 if (pcmk__str_empty(match)) {
503 return true;
504 } else if (s == NULL) {
505 return false;
506 } else {
507 size_t slen, mlen;
508
509
510
511
512 if (as_extension) {
513 s = strrchr(s, match[0]);
514 return (s == NULL)? false : !strcmp(s, match);
515 }
516
517 mlen = strlen(match);
518 slen = strlen(s);
519 return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
520 }
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534 bool
535 pcmk__ends_with(const char *s, const char *match)
536 {
537 return ends_with(s, match, false);
538 }
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561 bool
562 pcmk__ends_with_ext(const char *s, const char *match)
563 {
564 return ends_with(s, match, true);
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 static guint
587 pcmk__str_hash(gconstpointer v)
588 {
589 const signed char *p;
590 guint32 h = 0;
591
592 for (p = v; *p != '\0'; p++)
593 h = (h << 5) - h + *p;
594
595 return h;
596 }
597
598
599
600
601
602
603
604
605
606
607
608
609 GHashTable *
610 pcmk__strkey_table(GDestroyNotify key_destroy_func,
611 GDestroyNotify value_destroy_func)
612 {
613 return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
614 key_destroy_func, value_destroy_func);
615 }
616
617
618 static gboolean
619 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
620 {
621 return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
622 }
623
624 static guint
625 pcmk__strcase_hash(gconstpointer v)
626 {
627 const signed char *p;
628 guint32 h = 0;
629
630 for (p = v; *p != '\0'; p++)
631 h = (h << 5) - h + g_ascii_tolower(*p);
632
633 return h;
634 }
635
636
637
638
639
640
641
642
643
644
645
646
647 GHashTable *
648 pcmk__strikey_table(GDestroyNotify key_destroy_func,
649 GDestroyNotify value_destroy_func)
650 {
651 return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
652 key_destroy_func, value_destroy_func);
653 }
654
655 static void
656 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
657 {
658 if (key && value && user_data) {
659 g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
660 }
661 }
662
663
664
665
666
667
668
669
670
671
672
673 GHashTable *
674 pcmk__str_table_dup(GHashTable *old_table)
675 {
676 GHashTable *new_table = NULL;
677
678 if (old_table) {
679 new_table = pcmk__strkey_table(free, free);
680 g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
681 }
682 return new_table;
683 }
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701 void
702 pcmk__add_separated_word(char **list, size_t *len, const char *word,
703 const char *separator)
704 {
705 size_t orig_len, new_len;
706
707 CRM_ASSERT(list != NULL);
708
709 if (pcmk__str_empty(word)) {
710 return;
711 }
712
713
714 orig_len = (len != NULL)? *len : ((*list == NULL)? 0 : strlen(*list));
715
716
717 if (orig_len == 0) {
718 separator = "";
719
720
721 } else if (separator == NULL) {
722 separator = " ";
723 }
724
725 new_len = orig_len + strlen(separator) + strlen(word);
726 if (len != NULL) {
727 *len = new_len;
728 }
729
730
731 *list = pcmk__realloc(*list, new_len + 1);
732 sprintf(*list + orig_len, "%s%s", separator, word);
733 }
734
735
736
737
738
739
740
741
742
743
744
745
746
747 int
748 pcmk__compress(const char *data, unsigned int length, unsigned int max,
749 char **result, unsigned int *result_len)
750 {
751 int rc;
752 char *compressed = NULL;
753 char *uncompressed = strdup(data);
754 #ifdef CLOCK_MONOTONIC
755 struct timespec after_t;
756 struct timespec before_t;
757 #endif
758
759 if (max == 0) {
760 max = (length * 1.01) + 601;
761 }
762
763 #ifdef CLOCK_MONOTONIC
764 clock_gettime(CLOCK_MONOTONIC, &before_t);
765 #endif
766
767 compressed = calloc((size_t) max, sizeof(char));
768 CRM_ASSERT(compressed);
769
770 *result_len = max;
771 rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
772 CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
773 free(uncompressed);
774 if (rc != BZ_OK) {
775 crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
776 length, bz2_strerror(rc), rc);
777 free(compressed);
778 return pcmk_rc_error;
779 }
780
781 #ifdef CLOCK_MONOTONIC
782 clock_gettime(CLOCK_MONOTONIC, &after_t);
783
784 crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
785 length, *result_len, length / (*result_len),
786 (after_t.tv_sec - before_t.tv_sec) * 1000 +
787 (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
788 #else
789 crm_trace("Compressed %d bytes into %d (ratio %d:1)",
790 length, *result_len, length / (*result_len));
791 #endif
792
793 *result = compressed;
794 return pcmk_rc_ok;
795 }
796
797 char *
798 crm_strdup_printf(char const *format, ...)
799 {
800 va_list ap;
801 int len = 0;
802 char *string = NULL;
803
804 va_start(ap, format);
805 len = vasprintf (&string, format, ap);
806 CRM_ASSERT(len > 0);
807 va_end(ap);
808 return string;
809 }
810
811 int
812 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
813 {
814 char *remainder = NULL;
815
816 CRM_ASSERT(start != NULL && end != NULL);
817
818 *start = PCMK__PARSE_INT_DEFAULT;
819 *end = PCMK__PARSE_INT_DEFAULT;
820
821 crm_trace("Attempting to decode: [%s]", srcstring);
822 if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
823 return pcmk_rc_unknown_format;
824 }
825
826
827
828
829 if (*srcstring == '-') {
830 int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
831
832 if (rc != pcmk_rc_ok || *remainder != '\0') {
833 return pcmk_rc_unknown_format;
834 } else {
835 return pcmk_rc_ok;
836 }
837 }
838
839 if (scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT,
840 &remainder) != pcmk_rc_ok) {
841 return pcmk_rc_unknown_format;
842 }
843
844 if (*remainder && *remainder == '-') {
845 if (*(remainder+1)) {
846 char *more_remainder = NULL;
847 int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
848 &more_remainder);
849
850 if (rc != pcmk_rc_ok || *more_remainder != '\0') {
851 return pcmk_rc_unknown_format;
852 }
853 }
854 } else if (*remainder && *remainder != '-') {
855 *start = PCMK__PARSE_INT_DEFAULT;
856 return pcmk_rc_unknown_format;
857 } else {
858
859
860
861
862 *end = *start;
863 }
864
865 return pcmk_rc_ok;
866 }
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894 gboolean
895 pcmk__str_in_list(GList *lst, const gchar *s, uint32_t flags)
896 {
897 GCompareFunc fn;
898
899 if (lst == NULL) {
900 return FALSE;
901 }
902
903 if (strcmp(lst->data, "*") == 0 && lst->next == NULL) {
904 return TRUE;
905 }
906
907 if (s == NULL) {
908 return pcmk_is_set(flags, pcmk__str_null_matches);
909 }
910
911 if (pcmk_is_set(flags, pcmk__str_casei)) {
912 fn = (GCompareFunc) strcasecmp;
913 } else {
914 fn = (GCompareFunc) strcmp;
915 }
916
917 return g_list_find_custom(lst, s, fn) != NULL;
918 }
919
920 static bool
921 str_any_of(bool casei, const char *s, va_list args)
922 {
923 bool rc = false;
924
925 if (s != NULL) {
926 while (1) {
927 const char *ele = va_arg(args, const char *);
928
929 if (ele == NULL) {
930 break;
931 } else if (pcmk__str_eq(s, ele,
932 casei? pcmk__str_casei : pcmk__str_none)) {
933 rc = true;
934 break;
935 }
936 }
937 }
938 return rc;
939 }
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954 bool
955 pcmk__strcase_any_of(const char *s, ...)
956 {
957 va_list ap;
958 bool rc;
959
960 va_start(ap, s);
961 rc = str_any_of(true, s, ap);
962 va_end(ap);
963 return rc;
964 }
965
966
967
968
969
970
971
972
973
974
975
976
977
978 bool
979 pcmk__str_any_of(const char *s, ...)
980 {
981 va_list ap;
982 bool rc;
983
984 va_start(ap, s);
985 rc = str_any_of(false, s, ap);
986 va_end(ap);
987 return rc;
988 }
989
990
991
992
993
994
995
996
997
998
999
1000
1001 bool
1002 pcmk__char_in_any_str(int ch, ...)
1003 {
1004 bool rc = false;
1005 va_list ap;
1006
1007
1008
1009
1010
1011 va_start(ap, ch);
1012
1013 while (1) {
1014 const char *ele = va_arg(ap, const char *);
1015
1016 if (ele == NULL) {
1017 break;
1018 } else if (strchr(ele, ch) != NULL) {
1019 rc = true;
1020 break;
1021 }
1022 }
1023
1024 va_end(ap);
1025 return rc;
1026 }
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 int
1045 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1046 {
1047 while (*s1 && *s2) {
1048 if (isdigit(*s1) && isdigit(*s2)) {
1049
1050
1051 char *end1 = NULL;
1052 char *end2 = NULL;
1053 long num1 = strtol(s1, &end1, 10);
1054 long num2 = strtol(s2, &end2, 10);
1055
1056
1057 size_t len1 = end1 - s1;
1058 size_t len2 = end2 - s2;
1059
1060 if (num1 < num2) {
1061 return -1;
1062 } else if (num1 > num2) {
1063 return 1;
1064 } else if (len1 < len2) {
1065 return -1;
1066 } else if (len1 > len2) {
1067 return 1;
1068 }
1069 s1 = end1;
1070 s2 = end2;
1071 } else {
1072
1073 int lower1 = tolower(*s1);
1074 int lower2 = tolower(*s2);
1075
1076 if (lower1 < lower2) {
1077 return -1;
1078 } else if (lower1 > lower2) {
1079 return 1;
1080 }
1081 ++s1;
1082 ++s2;
1083 }
1084 }
1085 if (!*s1 && *s2) {
1086 return -1;
1087 } else if (*s1 && !*s2) {
1088 return 1;
1089 }
1090 return 0;
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 int
1123 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1124 {
1125
1126 if (pcmk_is_set(flags, pcmk__str_regex)) {
1127 regex_t *r_patt = calloc(1, sizeof(regex_t));
1128 int reg_flags = REG_EXTENDED | REG_NOSUB;
1129 int regcomp_rc = 0;
1130 int rc = 0;
1131
1132 if (s1 == NULL || s2 == NULL) {
1133 free(r_patt);
1134 return 1;
1135 }
1136
1137 if (pcmk_is_set(flags, pcmk__str_casei)) {
1138 reg_flags |= REG_ICASE;
1139 }
1140 regcomp_rc = regcomp(r_patt, s2, reg_flags);
1141 if (regcomp_rc != 0) {
1142 rc = 1;
1143 crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1144 } else {
1145 rc = regexec(r_patt, s1, 0, NULL, 0);
1146
1147 if (rc != 0) {
1148 rc = 1;
1149 }
1150 }
1151
1152 regfree(r_patt);
1153 free(r_patt);
1154 return rc;
1155 }
1156
1157
1158 if (s1 == s2) {
1159 return 0;
1160 }
1161
1162
1163
1164
1165
1166 if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1167 if (s1 == NULL || s2 == NULL) {
1168 return 0;
1169 }
1170 }
1171
1172
1173
1174
1175 if (s1 == NULL) {
1176 return -1;
1177 } else if (s2 == NULL) {
1178 return 1;
1179 }
1180
1181 if (pcmk_is_set(flags, pcmk__str_casei)) {
1182 return strcasecmp(s1, s2);
1183 } else {
1184 return strcmp(s1, s2);
1185 }
1186 }
1187
1188
1189
1190 #include <crm/common/util_compat.h>
1191
1192 gboolean
1193 safe_str_neq(const char *a, const char *b)
1194 {
1195 if (a == b) {
1196 return FALSE;
1197
1198 } else if (a == NULL || b == NULL) {
1199 return TRUE;
1200
1201 } else if (strcasecmp(a, b) == 0) {
1202 return FALSE;
1203 }
1204 return TRUE;
1205 }
1206
1207 gboolean
1208 crm_str_eq(const char *a, const char *b, gboolean use_case)
1209 {
1210 if (use_case) {
1211 return g_strcmp0(a, b) == 0;
1212
1213
1214 } else if (a == b) {
1215 return TRUE;
1216
1217 } else if (a == NULL || b == NULL) {
1218
1219 return FALSE;
1220
1221 } else if (strcasecmp(a, b) == 0) {
1222 return TRUE;
1223 }
1224 return FALSE;
1225 }
1226
1227 char *
1228 crm_itoa_stack(int an_int, char *buffer, size_t len)
1229 {
1230 if (buffer != NULL) {
1231 snprintf(buffer, len, "%d", an_int);
1232 }
1233 return buffer;
1234 }
1235
1236 guint
1237 g_str_hash_traditional(gconstpointer v)
1238 {
1239 return pcmk__str_hash(v);
1240 }
1241
1242 gboolean
1243 crm_strcase_equal(gconstpointer a, gconstpointer b)
1244 {
1245 return pcmk__strcase_equal(a, b);
1246 }
1247
1248 guint
1249 crm_strcase_hash(gconstpointer v)
1250 {
1251 return pcmk__strcase_hash(v);
1252 }
1253
1254 GHashTable *
1255 crm_str_table_dup(GHashTable *old_table)
1256 {
1257 return pcmk__str_table_dup(old_table);
1258 }
1259
1260 long long
1261 crm_parse_ll(const char *text, const char *default_text)
1262 {
1263 long long result;
1264
1265 if (text == NULL) {
1266 text = default_text;
1267 if (text == NULL) {
1268 crm_err("No default conversion value supplied");
1269 errno = EINVAL;
1270 return PCMK__PARSE_INT_DEFAULT;
1271 }
1272 }
1273 scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1274 return result;
1275 }
1276
1277 int
1278 crm_parse_int(const char *text, const char *default_text)
1279 {
1280 long long result = crm_parse_ll(text, default_text);
1281
1282 if (result < INT_MIN) {
1283
1284 if (errno != ERANGE) {
1285 crm_err("Conversion of %s was clipped: %lld", text, result);
1286 errno = ERANGE;
1287 }
1288 return INT_MIN;
1289
1290 } else if (result > INT_MAX) {
1291
1292 if (errno != ERANGE) {
1293 crm_err("Conversion of %s was clipped: %lld", text, result);
1294 errno = ERANGE;
1295 }
1296 return INT_MAX;
1297 }
1298
1299 return (int) result;
1300 }
1301
1302 char *
1303 crm_strip_trailing_newline(char *str)
1304 {
1305 return pcmk__trim(str);
1306 }
1307
1308 int
1309 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
1310 {
1311 return pcmk__numeric_strcasecmp(s1, s2);
1312 }
1313
1314