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