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
914
915 *end = PCMK__PARSE_INT_DEFAULT;
916
917 crm_trace("Attempting to decode: [%s]", srcstring);
918 if (pcmk__str_eq(srcstring, "", pcmk__str_null_matches)) {
919 return ENODATA;
920 } else if (pcmk__str_eq(srcstring, "-", pcmk__str_none)) {
921 return pcmk_rc_bad_input;
922 }
923
924
925
926
927 if (*srcstring == '-') {
928 int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
929
930 if ((rc == pcmk_rc_ok) && (*remainder != '\0')) {
931 rc = pcmk_rc_bad_input;
932 }
933 return rc;
934 }
935
936 rc = scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT, &remainder);
937 if (rc != pcmk_rc_ok) {
938 return rc;
939 }
940
941 if (*remainder && *remainder == '-') {
942 if (*(remainder+1)) {
943 char *more_remainder = NULL;
944 int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
945 &more_remainder);
946
947 if (rc != pcmk_rc_ok) {
948 return rc;
949 } else if (*more_remainder != '\0') {
950 return pcmk_rc_bad_input;
951 }
952 }
953 } else if (*remainder && *remainder != '-') {
954 *start = PCMK__PARSE_INT_DEFAULT;
955 return pcmk_rc_bad_input;
956 } else {
957
958
959
960
961 *end = *start;
962 }
963
964 return pcmk_rc_ok;
965 }
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983 gboolean
984 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
985 {
986 for (const GList *ele = lst; ele != NULL; ele = ele->next) {
987 if (pcmk__str_eq(s, ele->data, flags)) {
988 return TRUE;
989 }
990 }
991
992 return FALSE;
993 }
994
995 static bool
996 str_any_of(const char *s, va_list args, uint32_t flags)
997 {
998 if (s == NULL) {
999 return false;
1000 }
1001
1002 while (1) {
1003 const char *ele = va_arg(args, const char *);
1004
1005 if (ele == NULL) {
1006 break;
1007 } else if (pcmk__str_eq(s, ele, flags)) {
1008 return true;
1009 }
1010 }
1011
1012 return false;
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028 bool
1029 pcmk__strcase_any_of(const char *s, ...)
1030 {
1031 va_list ap;
1032 bool rc;
1033
1034 va_start(ap, s);
1035 rc = str_any_of(s, ap, pcmk__str_casei);
1036 va_end(ap);
1037 return rc;
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 bool
1053 pcmk__str_any_of(const char *s, ...)
1054 {
1055 va_list ap;
1056 bool rc;
1057
1058 va_start(ap, s);
1059 rc = str_any_of(s, ap, pcmk__str_none);
1060 va_end(ap);
1061 return rc;
1062 }
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080 int
1081 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1082 {
1083 pcmk__assert((s1 != NULL) && (s2 != NULL));
1084
1085 while (*s1 && *s2) {
1086 if (isdigit(*s1) && isdigit(*s2)) {
1087
1088
1089 char *end1 = NULL;
1090 char *end2 = NULL;
1091 long num1 = strtol(s1, &end1, 10);
1092 long num2 = strtol(s2, &end2, 10);
1093
1094
1095 size_t len1 = end1 - s1;
1096 size_t len2 = end2 - s2;
1097
1098 if (num1 < num2) {
1099 return -1;
1100 } else if (num1 > num2) {
1101 return 1;
1102 } else if (len1 < len2) {
1103 return -1;
1104 } else if (len1 > len2) {
1105 return 1;
1106 }
1107 s1 = end1;
1108 s2 = end2;
1109 } else {
1110
1111 int lower1 = tolower(*s1);
1112 int lower2 = tolower(*s2);
1113
1114 if (lower1 < lower2) {
1115 return -1;
1116 } else if (lower1 > lower2) {
1117 return 1;
1118 }
1119 ++s1;
1120 ++s2;
1121 }
1122 }
1123 if (!*s1 && *s2) {
1124 return -1;
1125 } else if (*s1 && !*s2) {
1126 return 1;
1127 }
1128 return 0;
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
1164
1165 int
1166 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1167 {
1168
1169 if (pcmk_is_set(flags, pcmk__str_regex)) {
1170 regex_t r_patt;
1171 int reg_flags = REG_EXTENDED | REG_NOSUB;
1172 int regcomp_rc = 0;
1173 int rc = 0;
1174
1175 if (s1 == NULL || s2 == NULL) {
1176 return 1;
1177 }
1178
1179 if (pcmk_is_set(flags, pcmk__str_casei)) {
1180 reg_flags |= REG_ICASE;
1181 }
1182 regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1183 if (regcomp_rc != 0) {
1184 rc = 1;
1185 crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1186 } else {
1187 rc = regexec(&r_patt, s1, 0, NULL, 0);
1188 regfree(&r_patt);
1189 if (rc != 0) {
1190 rc = 1;
1191 }
1192 }
1193 return rc;
1194 }
1195
1196
1197 if (s1 == s2) {
1198 return 0;
1199 }
1200
1201
1202
1203
1204
1205 if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1206 if (s1 == NULL || s2 == NULL) {
1207 return 0;
1208 }
1209 }
1210
1211
1212
1213
1214 if (s1 == NULL) {
1215 return -1;
1216 } else if (s2 == NULL) {
1217 return 1;
1218 }
1219
1220
1221
1222
1223
1224 if (pcmk_is_set(flags, pcmk__str_star_matches)) {
1225 if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1226 return 0;
1227 }
1228 }
1229
1230 if (pcmk_is_set(flags, pcmk__str_casei)) {
1231 return strcasecmp(s1, s2);
1232 } else {
1233 return strcmp(s1, s2);
1234 }
1235 }
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250 char *
1251 pcmk__str_copy_as(const char *file, const char *function, uint32_t line,
1252 const char *str)
1253 {
1254 if (str != NULL) {
1255 char *result = strdup(str);
1256
1257 if (result == NULL) {
1258 crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
1259 crm_exit(CRM_EX_OSERR);
1260 }
1261 return result;
1262 }
1263 return NULL;
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279 void
1280 pcmk__str_update(char **str, const char *value)
1281 {
1282 if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1283 free(*str);
1284 *str = pcmk__str_copy(value);
1285 }
1286 }
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298 void
1299 pcmk__g_strcat(GString *buffer, ...)
1300 {
1301 va_list ap;
1302
1303 pcmk__assert(buffer != NULL);
1304 va_start(ap, buffer);
1305
1306 while (true) {
1307 const char *ele = va_arg(ap, const char *);
1308
1309 if (ele == NULL) {
1310 break;
1311 }
1312 g_string_append(buffer, ele);
1313 }
1314 va_end(ap);
1315 }