20 #include <sys/types.h> 38 scan_ll(
const char *text,
long long *
result,
long long default_value,
41 long long local_result = default_value;
42 char *local_end_text = NULL;
47 local_result = strtoll(text, &local_end_text, 10);
48 if (errno == ERANGE) {
50 crm_debug(
"Integer parsed from '%s' was clipped to %lld",
53 }
else if (local_end_text == text) {
55 local_result = default_value;
56 crm_debug(
"Could not parse integer from '%s' (using %lld instead): " 57 "No digits found", text, default_value);
59 }
else if (errno != 0) {
61 local_result = default_value;
62 crm_debug(
"Could not parse integer from '%s' (using %lld instead): " 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);
72 if (end_text != NULL) {
73 *end_text = local_end_text;
94 long long local_result = default_value;
95 int rc = scan_ll(text, &local_result, default_value, NULL);
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;
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;
134 *
result = (int) result_ll;
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);
166 *port = (int) port_ll;
195 char *local_end_text = NULL;
200 text = (text != NULL) ? text : default_text;
204 crm_debug(
"No text and no default conversion value supplied");
208 *
result = strtod(text, &local_end_text);
210 if (errno == ERANGE) {
220 const char *over_under;
222 if (QB_ABS(*
result) > DBL_MIN) {
227 over_under =
"under";
230 crm_debug(
"Floating-point value parsed from '%s' would %sflow " 231 "(using %g instead)", text, over_under, *
result);
233 }
else if (errno != 0) {
238 crm_debug(
"Could not parse floating-point value from '%s' (using " 242 }
else if (local_end_text == text) {
247 crm_debug(
"Could not parse floating-point value from '%s' (using " 248 "%.1f instead): No digits found", text,
251 }
else if (QB_ABS(*
result) <= DBL_MIN) {
264 for (
const char *p = text; p != local_end_text; p++) {
265 if (strchr(
"0.eE", *p) == NULL) {
267 crm_debug(
"Floating-point value parsed from '%s' would " 268 "underflow (using %g instead)", text, *
result);
274 crm_trace(
"Floating-point value parsed successfully from " 275 "'%s': %g", text, *
result);
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);
284 if (end_text != NULL) {
285 *end_text = local_end_text;
310 CRM_CHECK((table != NULL) && (key != NULL),
return EINVAL);
316 value = g_hash_table_lookup(table, key);
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));
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);
335 *
result = (guint) value_ll;
354 long long multiplier = 1000;
355 long long divisor = 1;
364 while (isspace(*
input)) {
370 if ((rc == ERANGE) && (msec > 0)) {
373 }
else if ((rc !=
pcmk_rc_ok) || (msec < 0)) {
374 crm_warn(
"'%s' is not a valid time duration: %s",
387 while (isdigit(*units) || (*units ==
'.')) {
392 while (isspace(*units)) {
400 || (strncasecmp(units,
"s", 1) == 0)
401 || (strncasecmp(units,
"sec", 3) == 0)) {
405 }
else if ((strncasecmp(units,
"ms", 2) == 0)
406 || (strncasecmp(units,
"msec", 4) == 0)) {
410 }
else if ((strncasecmp(units,
"us", 2) == 0)
411 || (strncasecmp(units,
"usec", 4) == 0)) {
415 }
else if ((strncasecmp(units,
"m", 1) == 0)
416 || (strncasecmp(units,
"min", 3) == 0)) {
417 multiplier = 60 * 1000;
420 }
else if ((strncasecmp(units,
"h", 1) == 0)
421 || (strncasecmp(units,
"hr", 2) == 0)) {
422 multiplier = 60 * 60 * 1000;
431 if (msec > (LLONG_MAX / multiplier)) {
434 return (msec * multiplier) / divisor;
462 if (
input[0] ==
'P') {
465 if (period_s != NULL) {
467 msec = QB_MIN(msec, G_MAXUINT / 1000) * 1000;
476 crm_warn(
"Using 0 instead of invalid interval specification '%s'",
483 if (result_ms != NULL) {
484 *result_ms = (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
492 gboolean ret = FALSE;
538 for (len = strlen(str) - 1; len >= 0 && str[len] ==
'\n'; len--) {
561 const char *p = prefix;
575 ends_with(
const char *s,
const char *match,
bool as_extension)
577 if (pcmk__str_empty(match)) {
579 }
else if (s == NULL) {
588 s = strrchr(s, match[0]);
589 return (s == NULL)? false : !strcmp(s, match);
592 mlen = strlen(match);
594 return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
612 return ends_with(s, match,
false);
639 return ends_with(s, match,
true);
662 pcmk__str_hash(gconstpointer v)
664 const signed char *p;
667 for (p = v; *p !=
'\0'; p++)
668 h = (h << 5) - h + *p;
686 GDestroyNotify value_destroy_func)
688 return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
689 key_destroy_func, value_destroy_func);
712 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
714 return pcmk__str_eq((
const char *)a, (
const char *)b,
pcmk__str_casei);
718 pcmk__strcase_hash(gconstpointer v)
720 const signed char *p;
723 for (p = v; *p !=
'\0'; p++)
724 h = (h << 5) - h + g_ascii_tolower(*p);
742 GDestroyNotify value_destroy_func)
744 return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
745 key_destroy_func, value_destroy_func);
749 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
751 if (key && value && user_data) {
753 (
const char *) key, (
const char *) value);
770 GHashTable *new_table = NULL;
774 g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
797 const char *separator)
801 if (pcmk__str_empty(word)) {
807 *list = g_string_sized_new(init_size);
809 *list = g_string_new(NULL);
813 if ((*list)->len == 0) {
817 }
else if (separator == NULL) {
822 g_string_append(*list, separator);
823 g_string_append(*list, word);
840 char **
result,
unsigned int *result_len)
843 char *compressed = NULL;
844 char *uncompressed = strdup(
data);
845 #ifdef CLOCK_MONOTONIC 846 struct timespec after_t;
847 struct timespec before_t;
851 max = (length * 1.01) + 601;
854 #ifdef CLOCK_MONOTONIC 855 clock_gettime(CLOCK_MONOTONIC, &before_t);
861 rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
868 crm_err(
"Compression of %d bytes failed: %s " QB_XS
" rc=%d",
874 #ifdef CLOCK_MONOTONIC 875 clock_gettime(CLOCK_MONOTONIC, &after_t);
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);
882 crm_trace(
"Compressed %d bytes into %d (ratio %d:1)",
883 length, *result_len, length / (*result_len));
897 va_start(ap, format);
898 len = vasprintf(&
string, format, ap);
907 char *remainder = NULL;
915 crm_trace(
"Attempting to decode: [%s]", srcstring);
925 if (*srcstring ==
'-') {
928 if ((rc ==
pcmk_rc_ok) && (*remainder !=
'\0')) {
939 if (*remainder && *remainder ==
'-') {
940 if (*(remainder+1)) {
941 char *more_remainder = NULL;
947 }
else if (*more_remainder !=
'\0') {
951 }
else if (*remainder && *remainder !=
'-') {
984 for (
const GList *ele = lst; ele != NULL; ele = ele->next) {
985 if (pcmk__str_eq(s, ele->data,
flags)) {
994 str_any_of(
const char *s, va_list args, uint32_t
flags)
1001 const char *ele = va_arg(args,
const char *);
1005 }
else if (pcmk__str_eq(s, ele,
flags)) {
1083 while (*s1 && *s2) {
1084 if (isdigit(*s1) && isdigit(*s2)) {
1089 long num1 = strtol(s1, &end1, 10);
1090 long num2 = strtol(s2, &end2, 10);
1093 size_t len1 = end1 - s1;
1094 size_t len2 = end2 - s2;
1098 }
else if (num1 > num2) {
1100 }
else if (len1 < len2) {
1102 }
else if (len1 > len2) {
1109 int lower1 = tolower(*s1);
1110 int lower2 = tolower(*s2);
1112 if (lower1 < lower2) {
1114 }
else if (lower1 > lower2) {
1123 }
else if (*s1 && !*s2) {
1169 int reg_flags = REG_EXTENDED | REG_NOSUB;
1173 if (s1 == NULL || s2 == NULL) {
1178 reg_flags |= REG_ICASE;
1180 regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1181 if (regcomp_rc != 0) {
1183 crm_err(
"Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1185 rc = regexec(&r_patt, s1, 0, NULL, 0);
1204 if (s1 == NULL || s2 == NULL) {
1214 }
else if (s2 == NULL) {
1223 if (strcmp(s1,
"*") == 0 || strcmp(s2,
"*") == 0) {
1229 return strcasecmp(s1, s2);
1231 return strcmp(s1, s2);
1253 char *
result = strdup(str);
1256 crm_abort(file,
function, line,
"Out of memory", FALSE, TRUE);
1280 if ((str != NULL) && !pcmk__str_eq(*str, value,
pcmk__str_none)) {
1302 va_start(ap, buffer);
1305 const char *ele = va_arg(ap,
const char *);
1310 g_string_append(buffer, ele);
#define CRM_CHECK(expr, failure_action)
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
char * crm_strdup_printf(char const *format,...)
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
struct crm_time_s crm_time_t
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
#define PCMK__PARSE_DBL_DEFAULT
int pcmk__scan_port(const char *text, int *port)
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
bool pcmk__str_any_of(const char *s,...)
crm_time_t * crm_time_parse_duration(const char *duration_str)
Parse a time duration from an ISO 8601 duration specification.
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
void pcmk__str_update(char **str, const char *value)
#define PCMK__PARSE_INT_DEFAULT
#define crm_warn(fmt, args...)
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
#define crm_debug(fmt, args...)
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
External (OS/environmental) problem.
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
#define crm_trace(fmt, args...)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
int pcmk__scan_min_int(const char *text, int *result, int minimum)
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
long long crm_time_get_seconds(const crm_time_t *dt)
#define pcmk__str_copy(str)
int crm_str_to_boolean(const char *s, int *ret)
#define pcmk__assert(expr)
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
gboolean crm_is_true(const char *s)
bool pcmk__ends_with_ext(const char *s, const char *match)
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
pcmk__action_result_t result
#define crm_err(fmt, args...)
void pcmk__g_strcat(GString *buffer,...)
char * pcmk__str_copy_as(const char *file, const char *function, uint32_t line, const char *str)
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
char * pcmk__trim(char *str)
#define pcmk__assert_alloc(nmemb, size)
bool pcmk__ends_with(const char *s, const char *match)
bool pcmk__strcase_any_of(const char *s,...)
void crm_time_free(crm_time_t *dt)