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