25 #include <sys/types.h>
43 scan_ll(
const char *text,
long long *result,
long long default_value,
46 long long local_result = default_value;
47 char *local_end_text = NULL;
52 local_result = strtoll(text, &local_end_text, 10);
53 if (errno == ERANGE) {
55 crm_warn(
"Integer parsed from '%s' was clipped to %lld",
58 }
else if (errno != 0) {
60 local_result = default_value;
61 crm_warn(
"Could not parse integer from '%s' (using %lld instead): "
64 }
else if (local_end_text == text) {
66 local_result = default_value;
67 crm_warn(
"Could not parse integer from '%s' (using %lld instead): "
68 "No digits found", text, default_value);
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);
77 if (end_text != NULL) {
78 *end_text = local_end_text;
81 *result = local_result;
97 pcmk__scan_ll(
const char *text,
long long *result,
long long default_value)
99 long long local_result = default_value;
103 rc = scan_ll(text, &local_result, default_value, NULL);
105 local_result = default_value;
108 if (result != NULL) {
109 *result = local_result;
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;
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;
144 if (result != NULL) {
145 *result = (int) result_ll;
167 && ((port_ll < 0LL) || (port_ll > 65535LL))) {
168 crm_warn(
"Ignoring port specification '%s' "
169 "not in valid range (0-65535)", text);
174 *port = (int) port_ll;
203 char *local_end_text = NULL;
208 text = (text != NULL) ? text : default_text;
212 crm_debug(
"No text and no default conversion value supplied");
216 *result = strtod(text, &local_end_text);
218 if (errno == ERANGE) {
228 const char *over_under;
230 if (fabs(*result) > DBL_MIN) {
235 over_under =
"under";
238 crm_debug(
"Floating-point value parsed from '%s' would %sflow "
239 "(using %g instead)", text, over_under, *result);
241 }
else if (errno != 0) {
246 crm_debug(
"Could not parse floating-point value from '%s' (using "
250 }
else if (local_end_text == text) {
255 crm_debug(
"Could not parse floating-point value from '%s' (using "
256 "%.1f instead): No digits found", text,
259 }
else if (fabs(*result) <= DBL_MIN) {
272 for (
const char *p = text; p != local_end_text; p++) {
273 if (strchr(
"0.eE", *p) == NULL) {
275 crm_debug(
"Floating-point value parsed from '%s' would "
276 "underflow (using %g instead)", text, *result);
282 crm_trace(
"Floating-point value parsed successfully from "
283 "'%s': %g", text, *result);
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);
292 if (end_text != NULL) {
293 *end_text = local_end_text;
318 CRM_CHECK((table != NULL) && (key != NULL),
return EINVAL);
320 if (result != NULL) {
321 *result = default_val;
324 value = g_hash_table_lookup(table, key);
334 if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
335 crm_warn(
"Could not parse non-negative integer from %s", value);
339 if (result != NULL) {
340 *result = (guint) value_ll;
346 # define NUMCHARS "0123456789."
350 # define WHITESPACE " \t\n\r\f"
365 const char *num_start = NULL;
367 long long multiplier = 1000;
368 long long divisor = 1;
371 char *end_text = NULL;
377 num_start = input + strspn(input,
WHITESPACE);
378 num_len = strspn(num_start,
NUMCHARS);
382 units = num_start + num_len;
385 if (!strncasecmp(units,
"ms", 2) || !strncasecmp(units,
"msec", 4)) {
388 }
else if (!strncasecmp(units,
"us", 2) || !strncasecmp(units,
"usec", 4)) {
391 }
else if (!strncasecmp(units,
"s", 1) || !strncasecmp(units,
"sec", 3)) {
394 }
else if (!strncasecmp(units,
"m", 1) || !strncasecmp(units,
"min", 3)) {
395 multiplier = 60 * 1000;
397 }
else if (!strncasecmp(units,
"h", 1) || !strncasecmp(units,
"hr", 2)) {
398 multiplier = 60 * 60 * 1000;
400 }
else if ((*units !=
'\0') && (*units !=
'\n') && (*units !=
'\r')) {
405 if (msec > (LLONG_MAX / multiplier)) {
417 gboolean ret = FALSE;
431 }
else if (strcasecmp(s,
"true") == 0
432 || strcasecmp(s,
"on") == 0
433 || strcasecmp(s,
"yes") == 0 || strcasecmp(s,
"y") == 0 || strcasecmp(s,
"1") == 0) {
437 }
else if (strcasecmp(s,
"false") == 0
438 || strcasecmp(s,
"off") == 0
439 || strcasecmp(s,
"no") == 0 || strcasecmp(s,
"n") == 0 || strcasecmp(s,
"0") == 0) {
463 for (len = strlen(str) - 1; len >= 0 && str[len] ==
'\n'; len--) {
486 const char *p = prefix;
500 ends_with(
const char *s,
const char *match,
bool as_extension)
502 if (pcmk__str_empty(match)) {
504 }
else if (s == NULL) {
513 s = strrchr(s, match[0]);
514 return (s == NULL)?
false : !strcmp(s, match);
517 mlen = strlen(match);
519 return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
537 return ends_with(s, match,
false);
564 return ends_with(s, match,
true);
587 pcmk__str_hash(gconstpointer v)
589 const signed char *p;
592 for (p = v; *p !=
'\0'; p++)
593 h = (h << 5) - h + *p;
611 GDestroyNotify value_destroy_func)
613 return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
614 key_destroy_func, value_destroy_func);
619 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
621 return pcmk__str_eq((
const char *)a, (
const char *)b,
pcmk__str_casei);
625 pcmk__strcase_hash(gconstpointer v)
627 const signed char *p;
630 for (p = v; *p !=
'\0'; p++)
631 h = (h << 5) - h + g_ascii_tolower(*p);
649 GDestroyNotify value_destroy_func)
651 return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
652 key_destroy_func, value_destroy_func);
656 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
658 if (key && value && user_data) {
659 g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
676 GHashTable *new_table = NULL;
680 g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
703 const char *separator)
705 size_t orig_len, new_len;
709 if (pcmk__str_empty(word)) {
714 orig_len = (len != NULL)? *len : ((*list == NULL)? 0 : strlen(*list));
721 }
else if (separator == NULL) {
725 new_len = orig_len + strlen(separator) + strlen(word);
731 *list = pcmk__realloc(*list, new_len + 1);
732 sprintf(*list + orig_len,
"%s%s", separator, word);
749 char **result,
unsigned int *result_len)
752 char *compressed = NULL;
753 char *uncompressed = strdup(data);
754 #ifdef CLOCK_MONOTONIC
755 struct timespec after_t;
756 struct timespec before_t;
760 max = (length * 1.01) + 601;
763 #ifdef CLOCK_MONOTONIC
764 clock_gettime(CLOCK_MONOTONIC, &before_t);
767 compressed = calloc((
size_t) max,
sizeof(
char));
771 rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
775 crm_err(
"Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
781 #ifdef CLOCK_MONOTONIC
782 clock_gettime(CLOCK_MONOTONIC, &after_t);
784 crm_trace(
"Compressed %d bytes into %d (ratio %d:1) in %.0fms",
785 length, *result_len, length / (*result_len),
786 (after_t.tv_sec - before_t.tv_sec) * 1000 +
787 (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
789 crm_trace(
"Compressed %d bytes into %d (ratio %d:1)",
790 length, *result_len, length / (*result_len));
793 *result = compressed;
804 va_start(ap, format);
805 len = vasprintf (&
string, format, ap);
814 char *remainder = NULL;
821 crm_trace(
"Attempting to decode: [%s]", srcstring);
822 if (pcmk__str_empty(srcstring) || !strcmp(srcstring,
"-")) {
829 if (*srcstring ==
'-') {
844 if (*remainder && *remainder ==
'-') {
845 if (*(remainder+1)) {
846 char *more_remainder = NULL;
850 if (rc !=
pcmk_rc_ok || *more_remainder !=
'\0') {
854 }
else if (*remainder && *remainder !=
'-') {
887 if (strcmp(lst->data,
"*") == 0 && lst->next == NULL) {
891 return g_list_find_custom(lst, s, (GCompareFunc) strcmp) != NULL;
895 str_any_of(
bool casei,
const char *s, va_list args)
901 const char *ele = va_arg(args,
const char *);
905 }
else if (pcmk__str_eq(s, ele,
935 rc = str_any_of(
true, s, ap);
959 rc = str_any_of(
false, s, ap);
988 const char *ele = va_arg(ap,
const char *);
992 }
else if (strchr(ele, ch) != NULL) {
1021 while (*s1 && *s2) {
1022 if (isdigit(*s1) && isdigit(*s2)) {
1027 long num1 = strtol(s1, &end1, 10);
1028 long num2 = strtol(s2, &end2, 10);
1031 size_t len1 = end1 - s1;
1032 size_t len2 = end2 - s2;
1036 }
else if (num1 > num2) {
1038 }
else if (len1 < len2) {
1040 }
else if (len1 > len2) {
1047 int lower1 = tolower(*s1);
1048 int lower2 = tolower(*s2);
1050 if (lower1 < lower2) {
1052 }
else if (lower1 > lower2) {
1061 }
else if (*s1 && !*s2) {
1101 regex_t *r_patt = calloc(1,
sizeof(regex_t));
1102 int reg_flags = REG_EXTENDED | REG_NOSUB;
1106 if (s1 == NULL || s2 == NULL) {
1112 reg_flags |= REG_ICASE;
1114 regcomp_rc = regcomp(r_patt, s2, reg_flags);
1115 if (regcomp_rc != 0) {
1119 rc = regexec(r_patt, s1, 0, NULL, 0);
1141 if (s1 == NULL || s2 == NULL) {
1151 }
else if (s2 == NULL) {
1156 return strcasecmp(s1, s2);
1158 return strcmp(s1, s2);
1172 }
else if (a == NULL || b == NULL) {
1175 }
else if (strcasecmp(a, b) == 0) {
1185 return g_strcmp0(a, b) == 0;
1188 }
else if (a == b) {
1191 }
else if (a == NULL || b == NULL) {
1195 }
else if (strcasecmp(a, b) == 0) {
1204 if (buffer != NULL) {
1205 snprintf(buffer, len,
"%d", an_int);
1213 return pcmk__str_hash(v);
1219 return pcmk__strcase_equal(a, b);
1225 return pcmk__strcase_hash(v);
1240 text = default_text;
1242 crm_err(
"No default conversion value supplied");
1256 if (result < INT_MIN) {
1258 if (errno != ERANGE) {
1259 crm_err(
"Conversion of %s was clipped: %lld", text, result);
1264 }
else if (result > INT_MAX) {
1266 if (errno != ERANGE) {
1267 crm_err(
"Conversion of %s was clipped: %lld", text, result);
1273 return (
int) result;
#define CRM_CHECK(expr, failure_action)
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
const char * bz2_strerror(int rc)
bool pcmk__char_in_any_str(int ch,...) G_GNUC_NULL_TERMINATED
int pcmk__scan_min_int(const char *text, int *result, int minimum)
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
char * crm_itoa_stack(int an_int, char *buf, size_t len)
guint crm_strcase_hash(gconstpointer v)
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
int crm_parse_int(const char *text, const char *default_text)
#define PCMK__PARSE_DBL_DEFAULT
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
char * strerror(int errnum)
bool pcmk__ends_with(const char *s, const char *match)
#define PCMK__PARSE_INT_DEFAULT
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
#define crm_warn(fmt, args...)
int pcmk__scan_port(const char *text, int *port)
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
#define crm_debug(fmt, args...)
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
guint g_str_hash_traditional(gconstpointer v)
#define crm_trace(fmt, args...)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
int pcmk_numeric_strcasecmp(const char *s1, const char *s2)
int crm_str_to_boolean(const char *s, int *ret)
long long crm_parse_ll(const char *text, const char *default_text)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
#define crm_err(fmt, args...)
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
gboolean safe_str_neq(const char *a, const char *b)
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
gboolean crm_strcase_equal(gconstpointer a, gconstpointer b)
gboolean crm_is_true(const char *s)
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
char * pcmk__trim(char *str)
char * crm_strip_trailing_newline(char *str)
GHashTable * crm_str_table_dup(GHashTable *old_table)
Deprecated Pacemaker utilities.
bool pcmk__ends_with_ext(const char *s, const char *match)
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)