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
- pcmk__str_update
- pcmk__g_strcat
- 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
363 long long
364 crm_get_msec(const char *input)
365 {
366 const char *num_start = NULL;
367 const char *units;
368 long long multiplier = 1000;
369 long long divisor = 1;
370 long long msec = PCMK__PARSE_INT_DEFAULT;
371 size_t num_len = 0;
372 char *end_text = NULL;
373
374 if (input == NULL) {
375 return PCMK__PARSE_INT_DEFAULT;
376 }
377
378 num_start = input + strspn(input, WHITESPACE);
379 num_len = strspn(num_start, NUMCHARS);
380 if (num_len < 1) {
381 return PCMK__PARSE_INT_DEFAULT;
382 }
383 units = num_start + num_len;
384 units += strspn(units, WHITESPACE);
385
386 if (!strncasecmp(units, "ms", 2) || !strncasecmp(units, "msec", 4)) {
387 multiplier = 1;
388 divisor = 1;
389 } else if (!strncasecmp(units, "us", 2) || !strncasecmp(units, "usec", 4)) {
390 multiplier = 1;
391 divisor = 1000;
392 } else if (!strncasecmp(units, "s", 1) || !strncasecmp(units, "sec", 3)) {
393 multiplier = 1000;
394 divisor = 1;
395 } else if (!strncasecmp(units, "m", 1) || !strncasecmp(units, "min", 3)) {
396 multiplier = 60 * 1000;
397 divisor = 1;
398 } else if (!strncasecmp(units, "h", 1) || !strncasecmp(units, "hr", 2)) {
399 multiplier = 60 * 60 * 1000;
400 divisor = 1;
401 } else if ((*units != '\0') && (*units != '\n') && (*units != '\r')) {
402 return PCMK__PARSE_INT_DEFAULT;
403 }
404
405 scan_ll(num_start, &msec, PCMK__PARSE_INT_DEFAULT, &end_text);
406 if (msec > (LLONG_MAX / multiplier)) {
407
408 return LLONG_MAX;
409 }
410 msec *= multiplier;
411 msec /= divisor;
412 return msec;
413 }
414
415 gboolean
416 crm_is_true(const char *s)
417 {
418 gboolean ret = FALSE;
419
420 if (s != NULL) {
421 crm_str_to_boolean(s, &ret);
422 }
423 return ret;
424 }
425
426 int
427 crm_str_to_boolean(const char *s, int *ret)
428 {
429 if (s == NULL) {
430 return -1;
431
432 } else if (strcasecmp(s, "true") == 0
433 || strcasecmp(s, "on") == 0
434 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
435 *ret = TRUE;
436 return 1;
437
438 } else if (strcasecmp(s, "false") == 0
439 || strcasecmp(s, "off") == 0
440 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
441 *ret = FALSE;
442 return 1;
443 }
444 return -1;
445 }
446
447
448
449
450
451
452
453
454
455 char *
456 pcmk__trim(char *str)
457 {
458 int len;
459
460 if (str == NULL) {
461 return str;
462 }
463
464 for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
465 str[len] = '\0';
466 }
467
468 return str;
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482
483 bool
484 pcmk__starts_with(const char *str, const char *prefix)
485 {
486 const char *s = str;
487 const char *p = prefix;
488
489 if (!s || !p) {
490 return false;
491 }
492 while (*s && *p) {
493 if (*s++ != *p++) {
494 return false;
495 }
496 }
497 return (*p == 0);
498 }
499
500 static inline bool
501 ends_with(const char *s, const char *match, bool as_extension)
502 {
503 if (pcmk__str_empty(match)) {
504 return true;
505 } else if (s == NULL) {
506 return false;
507 } else {
508 size_t slen, mlen;
509
510
511
512
513 if (as_extension) {
514 s = strrchr(s, match[0]);
515 return (s == NULL)? false : !strcmp(s, match);
516 }
517
518 mlen = strlen(match);
519 slen = strlen(s);
520 return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
521 }
522 }
523
524
525
526
527
528
529
530
531
532
533
534
535 bool
536 pcmk__ends_with(const char *s, const char *match)
537 {
538 return ends_with(s, match, false);
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 bool
563 pcmk__ends_with_ext(const char *s, const char *match)
564 {
565 return ends_with(s, match, true);
566 }
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587 static guint
588 pcmk__str_hash(gconstpointer v)
589 {
590 const signed char *p;
591 guint32 h = 0;
592
593 for (p = v; *p != '\0'; p++)
594 h = (h << 5) - h + *p;
595
596 return h;
597 }
598
599
600
601
602
603
604
605
606
607
608
609
610 GHashTable *
611 pcmk__strkey_table(GDestroyNotify key_destroy_func,
612 GDestroyNotify value_destroy_func)
613 {
614 return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
615 key_destroy_func, value_destroy_func);
616 }
617
618
619 static gboolean
620 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
621 {
622 return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
623 }
624
625 static guint
626 pcmk__strcase_hash(gconstpointer v)
627 {
628 const signed char *p;
629 guint32 h = 0;
630
631 for (p = v; *p != '\0'; p++)
632 h = (h << 5) - h + g_ascii_tolower(*p);
633
634 return h;
635 }
636
637
638
639
640
641
642
643
644
645
646
647
648 GHashTable *
649 pcmk__strikey_table(GDestroyNotify key_destroy_func,
650 GDestroyNotify value_destroy_func)
651 {
652 return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
653 key_destroy_func, value_destroy_func);
654 }
655
656 static void
657 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
658 {
659 if (key && value && user_data) {
660 g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
661 }
662 }
663
664
665
666
667
668
669
670
671
672
673
674 GHashTable *
675 pcmk__str_table_dup(GHashTable *old_table)
676 {
677 GHashTable *new_table = NULL;
678
679 if (old_table) {
680 new_table = pcmk__strkey_table(free, free);
681 g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
682 }
683 return new_table;
684 }
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702 void
703 pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
704 const char *separator)
705 {
706 CRM_ASSERT(list != NULL);
707
708 if (pcmk__str_empty(word)) {
709 return;
710 }
711
712 if (*list == NULL) {
713 if (init_size > 0) {
714 *list = g_string_sized_new(init_size);
715 } else {
716 *list = g_string_new(NULL);
717 }
718 }
719
720 if ((*list)->len == 0) {
721
722 separator = "";
723
724 } else if (separator == NULL) {
725
726 separator = " ";
727 }
728
729 g_string_append(*list, separator);
730 g_string_append(*list, word);
731 }
732
733
734
735
736
737
738
739
740
741
742
743
744
745 int
746 pcmk__compress(const char *data, unsigned int length, unsigned int max,
747 char **result, unsigned int *result_len)
748 {
749 int rc;
750 char *compressed = NULL;
751 char *uncompressed = strdup(data);
752 #ifdef CLOCK_MONOTONIC
753 struct timespec after_t;
754 struct timespec before_t;
755 #endif
756
757 if (max == 0) {
758 max = (length * 1.01) + 601;
759 }
760
761 #ifdef CLOCK_MONOTONIC
762 clock_gettime(CLOCK_MONOTONIC, &before_t);
763 #endif
764
765 compressed = calloc((size_t) max, sizeof(char));
766 CRM_ASSERT(compressed);
767
768 *result_len = max;
769 rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
770 CRM_BZ2_BLOCKS, 0, CRM_BZ2_WORK);
771 free(uncompressed);
772 if (rc != BZ_OK) {
773 crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
774 length, bz2_strerror(rc), rc);
775 free(compressed);
776 return pcmk_rc_error;
777 }
778
779 #ifdef CLOCK_MONOTONIC
780 clock_gettime(CLOCK_MONOTONIC, &after_t);
781
782 crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
783 length, *result_len, length / (*result_len),
784 (after_t.tv_sec - before_t.tv_sec) * 1000 +
785 (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
786 #else
787 crm_trace("Compressed %d bytes into %d (ratio %d:1)",
788 length, *result_len, length / (*result_len));
789 #endif
790
791 *result = compressed;
792 return pcmk_rc_ok;
793 }
794
795 char *
796 crm_strdup_printf(char const *format, ...)
797 {
798 va_list ap;
799 int len = 0;
800 char *string = NULL;
801
802 va_start(ap, format);
803 len = vasprintf (&string, format, ap);
804 CRM_ASSERT(len > 0);
805 va_end(ap);
806 return string;
807 }
808
809 int
810 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
811 {
812 char *remainder = NULL;
813
814 CRM_ASSERT(start != NULL && end != NULL);
815
816 *start = PCMK__PARSE_INT_DEFAULT;
817 *end = PCMK__PARSE_INT_DEFAULT;
818
819 crm_trace("Attempting to decode: [%s]", srcstring);
820 if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
821 return pcmk_rc_unknown_format;
822 }
823
824
825
826
827 if (*srcstring == '-') {
828 int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
829
830 if (rc != pcmk_rc_ok || *remainder != '\0') {
831 return pcmk_rc_unknown_format;
832 } else {
833 return pcmk_rc_ok;
834 }
835 }
836
837 if (scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT,
838 &remainder) != pcmk_rc_ok) {
839 return pcmk_rc_unknown_format;
840 }
841
842 if (*remainder && *remainder == '-') {
843 if (*(remainder+1)) {
844 char *more_remainder = NULL;
845 int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
846 &more_remainder);
847
848 if (rc != pcmk_rc_ok || *more_remainder != '\0') {
849 return pcmk_rc_unknown_format;
850 }
851 }
852 } else if (*remainder && *remainder != '-') {
853 *start = PCMK__PARSE_INT_DEFAULT;
854 return pcmk_rc_unknown_format;
855 } else {
856
857
858
859
860 *end = *start;
861 }
862
863 return pcmk_rc_ok;
864 }
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882 gboolean
883 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
884 {
885 for (const GList *ele = lst; ele != NULL; ele = ele->next) {
886 if (pcmk__str_eq(s, ele->data, flags)) {
887 return TRUE;
888 }
889 }
890
891 return FALSE;
892 }
893
894 static bool
895 str_any_of(const char *s, va_list args, uint32_t flags)
896 {
897 if (s == NULL) {
898 return pcmk_is_set(flags, pcmk__str_null_matches);
899 }
900
901 while (1) {
902 const char *ele = va_arg(args, const char *);
903
904 if (ele == NULL) {
905 break;
906 } else if (pcmk__str_eq(s, ele, flags)) {
907 return true;
908 }
909 }
910
911 return false;
912 }
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927 bool
928 pcmk__strcase_any_of(const char *s, ...)
929 {
930 va_list ap;
931 bool rc;
932
933 va_start(ap, s);
934 rc = str_any_of(s, ap, pcmk__str_casei);
935 va_end(ap);
936 return rc;
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951 bool
952 pcmk__str_any_of(const char *s, ...)
953 {
954 va_list ap;
955 bool rc;
956
957 va_start(ap, s);
958 rc = str_any_of(s, ap, pcmk__str_none);
959 va_end(ap);
960 return rc;
961 }
962
963
964
965
966
967
968
969
970
971
972
973
974 bool
975 pcmk__char_in_any_str(int ch, ...)
976 {
977 bool rc = false;
978 va_list ap;
979
980
981
982
983
984 va_start(ap, ch);
985
986 while (1) {
987 const char *ele = va_arg(ap, const char *);
988
989 if (ele == NULL) {
990 break;
991 } else if (strchr(ele, ch) != NULL) {
992 rc = true;
993 break;
994 }
995 }
996
997 va_end(ap);
998 return rc;
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 int
1018 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1019 {
1020 CRM_ASSERT((s1 != NULL) && (s2 != NULL));
1021
1022 while (*s1 && *s2) {
1023 if (isdigit(*s1) && isdigit(*s2)) {
1024
1025
1026 char *end1 = NULL;
1027 char *end2 = NULL;
1028 long num1 = strtol(s1, &end1, 10);
1029 long num2 = strtol(s2, &end2, 10);
1030
1031
1032 size_t len1 = end1 - s1;
1033 size_t len2 = end2 - s2;
1034
1035 if (num1 < num2) {
1036 return -1;
1037 } else if (num1 > num2) {
1038 return 1;
1039 } else if (len1 < len2) {
1040 return -1;
1041 } else if (len1 > len2) {
1042 return 1;
1043 }
1044 s1 = end1;
1045 s2 = end2;
1046 } else {
1047
1048 int lower1 = tolower(*s1);
1049 int lower2 = tolower(*s2);
1050
1051 if (lower1 < lower2) {
1052 return -1;
1053 } else if (lower1 > lower2) {
1054 return 1;
1055 }
1056 ++s1;
1057 ++s2;
1058 }
1059 }
1060 if (!*s1 && *s2) {
1061 return -1;
1062 } else if (*s1 && !*s2) {
1063 return 1;
1064 }
1065 return 0;
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102 int
1103 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1104 {
1105
1106 if (pcmk_is_set(flags, pcmk__str_regex)) {
1107 regex_t r_patt;
1108 int reg_flags = REG_EXTENDED | REG_NOSUB;
1109 int regcomp_rc = 0;
1110 int rc = 0;
1111
1112 if (s1 == NULL || s2 == NULL) {
1113 return 1;
1114 }
1115
1116 if (pcmk_is_set(flags, pcmk__str_casei)) {
1117 reg_flags |= REG_ICASE;
1118 }
1119 regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1120 if (regcomp_rc != 0) {
1121 rc = 1;
1122 crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1123 } else {
1124 rc = regexec(&r_patt, s1, 0, NULL, 0);
1125
1126 if (rc != 0) {
1127 rc = 1;
1128 }
1129 }
1130
1131 regfree(&r_patt);
1132 return rc;
1133 }
1134
1135
1136 if (s1 == s2) {
1137 return 0;
1138 }
1139
1140
1141
1142
1143
1144 if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1145 if (s1 == NULL || s2 == NULL) {
1146 return 0;
1147 }
1148 }
1149
1150
1151
1152
1153 if (s1 == NULL) {
1154 return -1;
1155 } else if (s2 == NULL) {
1156 return 1;
1157 }
1158
1159
1160
1161
1162
1163 if (pcmk_is_set(flags, pcmk__str_star_matches)) {
1164 if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1165 return 0;
1166 }
1167 }
1168
1169 if (pcmk_is_set(flags, pcmk__str_casei)) {
1170 return strcasecmp(s1, s2);
1171 } else {
1172 return strcmp(s1, s2);
1173 }
1174 }
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 void
1190 pcmk__str_update(char **str, const char *value)
1191 {
1192 if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1193 free(*str);
1194 if (value == NULL) {
1195 *str = NULL;
1196 } else {
1197 *str = strdup(value);
1198 CRM_ASSERT(*str != NULL);
1199 }
1200 }
1201 }
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213 void
1214 pcmk__g_strcat(GString *buffer, ...)
1215 {
1216 va_list ap;
1217
1218 CRM_ASSERT(buffer != NULL);
1219 va_start(ap, buffer);
1220
1221 while (true) {
1222 const char *ele = va_arg(ap, const char *);
1223
1224 if (ele == NULL) {
1225 break;
1226 }
1227 g_string_append(buffer, ele);
1228 }
1229 va_end(ap);
1230 }
1231
1232
1233
1234
1235 #include <crm/common/util_compat.h>
1236
1237 gboolean
1238 safe_str_neq(const char *a, const char *b)
1239 {
1240 if (a == b) {
1241 return FALSE;
1242
1243 } else if (a == NULL || b == NULL) {
1244 return TRUE;
1245
1246 } else if (strcasecmp(a, b) == 0) {
1247 return FALSE;
1248 }
1249 return TRUE;
1250 }
1251
1252 gboolean
1253 crm_str_eq(const char *a, const char *b, gboolean use_case)
1254 {
1255 if (use_case) {
1256 return g_strcmp0(a, b) == 0;
1257
1258
1259 } else if (a == b) {
1260 return TRUE;
1261
1262 } else if (a == NULL || b == NULL) {
1263
1264 return FALSE;
1265
1266 } else if (strcasecmp(a, b) == 0) {
1267 return TRUE;
1268 }
1269 return FALSE;
1270 }
1271
1272 char *
1273 crm_itoa_stack(int an_int, char *buffer, size_t len)
1274 {
1275 if (buffer != NULL) {
1276 snprintf(buffer, len, "%d", an_int);
1277 }
1278 return buffer;
1279 }
1280
1281 guint
1282 g_str_hash_traditional(gconstpointer v)
1283 {
1284 return pcmk__str_hash(v);
1285 }
1286
1287 gboolean
1288 crm_strcase_equal(gconstpointer a, gconstpointer b)
1289 {
1290 return pcmk__strcase_equal(a, b);
1291 }
1292
1293 guint
1294 crm_strcase_hash(gconstpointer v)
1295 {
1296 return pcmk__strcase_hash(v);
1297 }
1298
1299 GHashTable *
1300 crm_str_table_dup(GHashTable *old_table)
1301 {
1302 return pcmk__str_table_dup(old_table);
1303 }
1304
1305 long long
1306 crm_parse_ll(const char *text, const char *default_text)
1307 {
1308 long long result;
1309
1310 if (text == NULL) {
1311 text = default_text;
1312 if (text == NULL) {
1313 crm_err("No default conversion value supplied");
1314 errno = EINVAL;
1315 return PCMK__PARSE_INT_DEFAULT;
1316 }
1317 }
1318 scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1319 return result;
1320 }
1321
1322 int
1323 crm_parse_int(const char *text, const char *default_text)
1324 {
1325 long long result = crm_parse_ll(text, default_text);
1326
1327 if (result < INT_MIN) {
1328
1329 if (errno != ERANGE) {
1330 crm_err("Conversion of %s was clipped: %lld", text, result);
1331 errno = ERANGE;
1332 }
1333 return INT_MIN;
1334
1335 } else if (result > INT_MAX) {
1336
1337 if (errno != ERANGE) {
1338 crm_err("Conversion of %s was clipped: %lld", text, result);
1339 errno = ERANGE;
1340 }
1341 return INT_MAX;
1342 }
1343
1344 return (int) result;
1345 }
1346
1347 char *
1348 crm_strip_trailing_newline(char *str)
1349 {
1350 return pcmk__trim(str);
1351 }
1352
1353 int
1354 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
1355 {
1356 return pcmk__numeric_strcasecmp(s1, s2);
1357 }
1358
1359
1360