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