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