Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-61841
-rw-r--r--include/common.h18
-rw-r--r--include/zbxtypes.h4
-rw-r--r--src/libs/zbxcommon/Makefile.am3
-rw-r--r--src/libs/zbxcommon/str.c58
-rw-r--r--src/libs/zbxcommon/time.c274
-rw-r--r--src/libs/zbxserver/expression.c73
-rw-r--r--src/libs/zbxserver/macrofunc.c129
8 files changed, 531 insertions, 29 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-6184 b/ChangeLog.d/feature/ZBXNEXT-6184
new file mode 100644
index 00000000000..944ae9533f7
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-6184
@@ -0,0 +1 @@
+........S. [ZBXNEXT-6184] added formatting macro functions fmttime and fmtnum (viktors, wiper)
diff --git a/include/common.h b/include/common.h
index ae29dfec97b..ae6a82f7db5 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1093,6 +1093,7 @@ time_t calculate_proxy_nextcheck(zbx_uint64_t hostid, unsigned int delay, time_t
int zbx_check_time_period(const char *period, time_t time, const char *tz, int *res);
void zbx_hex2octal(const char *input, char **output, int *olen);
int str_in_list(const char *list, const char *value, char delimiter);
+int str_n_in_list(const char *list, const char *value, size_t len, char delimiter);
char *str_linefeed(const char *src, size_t maxline, const char *delim);
void zbx_strarr_init(char ***arr);
void zbx_strarr_add(char ***arr, const char *entry);
@@ -1652,4 +1653,21 @@ int zbx_str_extract(const char *text, size_t len, char **value);
#define AUDIT_ACTION_EXECUTE 7
#define AUDIT_RESOURCE_SCRIPT 25
+typedef enum
+{
+ ZBX_TIME_UNIT_UNKNOWN,
+ ZBX_TIME_UNIT_HOUR,
+ ZBX_TIME_UNIT_DAY,
+ ZBX_TIME_UNIT_WEEK,
+ ZBX_TIME_UNIT_MONTH,
+ ZBX_TIME_UNIT_YEAR
+}
+zbx_time_unit_t;
+
+void zbx_tm_add(struct tm *tm, int multiplier, zbx_time_unit_t base);
+void zbx_tm_sub(struct tm *tm, int multiplier, zbx_time_unit_t base);
+
+zbx_time_unit_t zbx_tm_str_to_unit(const char *text);
+int zbx_tm_parse_period(const char *period, size_t *len, int *multiplier, zbx_time_unit_t *base, char **error);
+
#endif
diff --git a/include/zbxtypes.h b/include/zbxtypes.h
index 0d3a5b421ed..9495e412e7e 100644
--- a/include/zbxtypes.h
+++ b/include/zbxtypes.h
@@ -214,4 +214,8 @@ zbx_uint128_t;
/* macro to test if a signed value has been assigned to unsigned type (char, short, int, long long) */
#define ZBX_IS_TOP_BIT_SET(x) (0 != ((__UINT64_C(1) << ((sizeof(x) << 3) - 1)) & (x)))
+#if defined(_WINDOWS)
+ #define localtime_r(x, y) localtime_s(y, x)
+#endif
+
#endif
diff --git a/src/libs/zbxcommon/Makefile.am b/src/libs/zbxcommon/Makefile.am
index dda144eff47..221a9a93ab3 100644
--- a/src/libs/zbxcommon/Makefile.am
+++ b/src/libs/zbxcommon/Makefile.am
@@ -13,6 +13,7 @@ libzbxcommon_a_SOURCES = \
variant.c \
variant_misc.c \
xml.c \
- zbxgetopt.c
+ zbxgetopt.c \
+ time.c
libzbxcommon_a_CFLAGS = $(ICONV_CFLAGS)
diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c
index b9f4e736825..425da0c83b0 100644
--- a/src/libs/zbxcommon/str.c
+++ b/src/libs/zbxcommon/str.c
@@ -5337,42 +5337,66 @@ void remove_param(char *param, int num)
/******************************************************************************
* *
- * Function: str_in_list *
+ * Function: str_n_in_list *
* *
* Purpose: check if string is contained in a list of delimited strings *
* *
- * Parameters: list - strings a,b,ccc,ddd *
- * value - value *
- * delimiter - delimiter *
+ * Parameters: list - [IN] strings a,b,ccc,ddd *
+ * value - [IN] value *
+ * len - [IN] value length *
+ * delimiter - [IN] delimiter *
* *
* Return value: SUCCEED - string is in the list, FAIL - otherwise *
* *
- * Author: Alexei Vladishev, Aleksandrs Saveljevs *
- * *
******************************************************************************/
-int str_in_list(const char *list, const char *value, char delimiter)
+int str_n_in_list(const char *list, const char *value, size_t len, char delimiter)
{
const char *end;
- int ret = FAIL;
- size_t len;
+ size_t token_len, next = 1;
- len = strlen(value);
-
- while (SUCCEED != ret)
+ while ('\0' != *list)
{
if (NULL != (end = strchr(list, delimiter)))
{
- ret = (len == (size_t)(end - list) && 0 == strncmp(list, value, len) ? SUCCEED : FAIL);
- list = end + 1;
+ token_len = end - list;
+ next = 1;
}
else
{
- ret = (0 == strcmp(list, value) ? SUCCEED : FAIL);
- break;
+ token_len = strlen(list);
+ next = 0;
}
+
+ if (len == token_len && 0 == memcmp(list, value, len))
+ return SUCCEED;
+
+ list += token_len + next;
}
- return ret;
+ if (1 == next && 0 == len)
+ return SUCCEED;
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: str_in_list *
+ * *
+ * Purpose: check if string is contained in a list of delimited strings *
+ * *
+ * Parameters: list - strings a,b,ccc,ddd *
+ * value - value *
+ * delimiter - delimiter *
+ * *
+ * Return value: SUCCEED - string is in the list, FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev, Aleksandrs Saveljevs *
+ * *
+ ******************************************************************************/
+int str_in_list(const char *list, const char *value, char delimiter)
+{
+ return str_n_in_list(list, value, strlen(value), delimiter);
}
/******************************************************************************
diff --git a/src/libs/zbxcommon/time.c b/src/libs/zbxcommon/time.c
new file mode 100644
index 00000000000..187ffcb5315
--- /dev/null
+++ b/src/libs/zbxcommon/time.c
@@ -0,0 +1,274 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2020 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "common.h"
+
+static void tm_sub(struct tm *tm, int multiplier, zbx_time_unit_t base);
+
+zbx_time_unit_t zbx_tm_str_to_unit(const char *text)
+{
+ switch (*text)
+ {
+ case 'h':
+ return ZBX_TIME_UNIT_HOUR;
+ case 'd':
+ return ZBX_TIME_UNIT_DAY;
+ case 'w':
+ return ZBX_TIME_UNIT_WEEK;
+ case 'M':
+ return ZBX_TIME_UNIT_MONTH;
+ case 'y':
+ return ZBX_TIME_UNIT_YEAR;
+ default:
+ return ZBX_TIME_UNIT_UNKNOWN;
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_tm_parse_period *
+ * *
+ * Purpose: parse time period in format <multiplier><time unit> *
+ * *
+ * Parameters: period - [IN] the time period *
+ * len - [OUT] the length of parsed time period *
+ * multiplier - [OUT] the parsed multiplier *
+ * base - [OUT] the parsed time unit *
+ * error - [OUT] the error message if parsing failed *
+ * *
+ * Return value: SUCCEED - period was parsed successfully *
+ * FAIL - invalid time period was specified *
+ * *
+ ******************************************************************************/
+int zbx_tm_parse_period(const char *period, size_t *len, int *multiplier, zbx_time_unit_t *base, char **error)
+{
+ const char *ptr;
+
+ for (ptr = period; 0 != isdigit(*ptr); ptr++)
+ ;
+
+ if (FAIL == is_uint_n_range(period, ptr - period, multiplier, sizeof(*multiplier), 1, UINT32_MAX))
+ {
+ *error = zbx_strdup(*error, "invalid period multiplier");
+ return FAIL;
+ }
+
+ if (ZBX_TIME_UNIT_UNKNOWN == (*base = zbx_tm_str_to_unit(ptr)))
+ {
+ *error = zbx_strdup(*error, "invalid period time unit");
+ return FAIL;
+ }
+
+ *len = ptr - period + 1;
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: tm_add *
+ * *
+ * Purpose: add time duration without adjusting DST clocks *
+ * *
+ * Parameter: tm - [IN/OUT] the time structure *
+ * multiplier - [IN] the unit multiplier *
+ * base - [IN] the time unit to add *
+ * *
+ ******************************************************************************/
+static void tm_add(struct tm *tm, int multiplier, zbx_time_unit_t base)
+{
+ int shift;
+
+ switch (base)
+ {
+ case ZBX_TIME_UNIT_HOUR:
+ tm->tm_hour += multiplier;
+ if (24 <= tm->tm_hour)
+ {
+ shift = tm->tm_hour / 24;
+ tm->tm_hour %= 24;
+ tm_add(tm, shift, ZBX_TIME_UNIT_DAY);
+ }
+ break;
+ case ZBX_TIME_UNIT_DAY:
+ tm->tm_mday += multiplier;
+ while (tm->tm_mday > (shift = zbx_day_in_month(tm->tm_year + 1900, tm->tm_mon + 1)))
+ {
+ tm->tm_mday -= shift;
+ tm_add(tm, 1, ZBX_TIME_UNIT_MONTH);
+ }
+ tm->tm_wday += multiplier;
+ tm->tm_wday %= 7;
+ break;
+ case ZBX_TIME_UNIT_WEEK:
+ tm_add(tm, multiplier * 7, ZBX_TIME_UNIT_DAY);
+ break;
+ case ZBX_TIME_UNIT_MONTH:
+ tm->tm_mon += multiplier;
+ if (12 <= tm->tm_mon)
+ {
+ shift = tm->tm_mon / 12;
+ tm->tm_mon %= 12;
+ tm_add(tm, shift, ZBX_TIME_UNIT_YEAR);
+ }
+ break;
+ case ZBX_TIME_UNIT_YEAR:
+ tm->tm_year += multiplier;
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_tm_add *
+ * *
+ * Purpose: add time duration *
+ * *
+ * Parameter: tm - [IN/OUT] the time structure *
+ * multiplier - [IN] the unit multiplier *
+ * base - [IN] the time unit to add *
+ * *
+ ******************************************************************************/
+void zbx_tm_add(struct tm *tm, int multiplier, zbx_time_unit_t base)
+{
+ time_t time_new;
+ struct tm tm_new;
+
+ tm_add(tm, multiplier, base);
+
+ /* adjust clock if DST changes were in effect */
+
+ tm_new = *tm;
+
+ if (-1 != (time_new = mktime(&tm_new)))
+ {
+ tm_new = *localtime(&time_new);
+ if (tm->tm_isdst != tm_new.tm_isdst && -1 != tm->tm_isdst && -1 != tm_new.tm_isdst)
+ {
+ *tm = tm_new;
+ if (0 == tm->tm_isdst)
+ tm_add(tm, 1, ZBX_TIME_UNIT_HOUR);
+ else
+ tm_sub(tm, 1, ZBX_TIME_UNIT_HOUR);
+ }
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: tm_sub *
+ * *
+ * Purpose: subtracts time duration without adjusting DST clocks *
+ * *
+ * Parameter: tm - [IN/OUT] the time structure *
+ * multiplier - [IN] the unit multiplier *
+ * base - [IN] the time unit to add *
+ * *
+ ******************************************************************************/
+static void tm_sub(struct tm *tm, int multiplier, zbx_time_unit_t base)
+{
+ int shift;
+
+ switch (base)
+ {
+ case ZBX_TIME_UNIT_HOUR:
+ tm->tm_hour -= multiplier;
+ if (0 > tm->tm_hour)
+ {
+ shift = -tm->tm_hour / 24 + 1;
+ tm->tm_hour = 24 + tm->tm_hour % 24;
+ tm_sub(tm, shift, ZBX_TIME_UNIT_DAY);
+ }
+ return;
+ case ZBX_TIME_UNIT_DAY:
+ tm->tm_mday -= multiplier;
+ while (0 >= tm->tm_mday)
+ {
+ int prev_mon;
+
+ if (0 > (prev_mon = tm->tm_mon - 1))
+ prev_mon = 11;
+ prev_mon++;
+
+ tm->tm_mday += zbx_day_in_month(tm->tm_year + 1900, prev_mon);
+ tm_sub(tm, 1, ZBX_TIME_UNIT_MONTH);
+ }
+ tm->tm_wday -= multiplier;
+ if (0 < tm->tm_wday)
+ tm->tm_wday = 7 + tm->tm_wday % 7;
+ return;
+ case ZBX_TIME_UNIT_WEEK:
+ tm_sub(tm, multiplier * 7, ZBX_TIME_UNIT_DAY);
+ return;
+ case ZBX_TIME_UNIT_MONTH:
+ tm->tm_mon -= multiplier;
+ if (0 > tm->tm_mon)
+ {
+ shift = -tm->tm_mon / 12 + 1;
+ tm->tm_mon = 12 + tm->tm_mon % 12;
+ tm_sub(tm, shift, ZBX_TIME_UNIT_YEAR);
+ }
+ return;
+ case ZBX_TIME_UNIT_YEAR:
+ tm->tm_year -= multiplier;
+ return;
+ default:
+ return;
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_tm_sub *
+ * *
+ * Purpose: subtracts time duration *
+ * *
+ * Parameter: tm - [IN/OUT] the time structure *
+ * multiplier - [IN] the unit multiplier *
+ * base - [IN] the time unit to add *
+ * *
+ ******************************************************************************/
+void zbx_tm_sub(struct tm *tm, int multiplier, zbx_time_unit_t base)
+{
+ time_t time_new;
+ struct tm tm_new;
+
+ tm_sub(tm, multiplier, base);
+
+ /* adjust clock if DST changes were in effect */
+
+ tm_new = *tm;
+
+ if (-1 != (time_new = mktime(&tm_new)))
+ {
+ tm_new = *localtime(&time_new);
+
+ if (tm->tm_isdst != tm_new.tm_isdst && -1 != tm->tm_isdst && -1 != tm_new.tm_isdst)
+ {
+ *tm = tm_new;
+ if (0 == tm->tm_isdst)
+ tm_add(tm, 1, ZBX_TIME_UNIT_HOUR);
+ else
+ tm_sub(tm, 1, ZBX_TIME_UNIT_HOUR);
+
+ }
+ }
+}
diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c
index 0f295bb5ee5..d6639575738 100644
--- a/src/libs/zbxserver/expression.c
+++ b/src/libs/zbxserver/expression.c
@@ -2054,8 +2054,22 @@ static const char *ex_macros[] =
static const char *simple_host_macros[] = {MVAR_HOST_HOST, MVAR_HOSTNAME, NULL};
static const char *simple_key_macros[] = {MVAR_ITEM_KEY, MVAR_TRIGGER_KEY, NULL};
+typedef struct
+{
+ char *macro;
+ char *functions;
+}
+zbx_macro_functions_t;
+
/* macros that can be modified using macro functions */
-static const char *mod_macros[] = {MVAR_ITEM_VALUE, MVAR_ITEM_LASTVALUE, NULL};
+static zbx_macro_functions_t mod_macros[] =
+{
+ {MVAR_ITEM_VALUE, "regsub,iregsub,fmtnum"},
+ {MVAR_ITEM_LASTVALUE, "regsub,iregsub,fmtnum"},
+ {MVAR_TIME, "fmttime"},
+ {"?", "fmtnum"},
+ {NULL, NULL}
+};
typedef struct
{
@@ -2658,6 +2672,54 @@ static const char *macro_in_list(const char *str, zbx_strloc_t strloc, const cha
/******************************************************************************
* *
+ * Function: func_macro_in_list *
+ * *
+ * Purpose: check if a macro function one in the list for the macro *
+ * *
+ * Parameters: str - [IN] string containing potential macro *
+ * fm - [IN] function macro to check *
+ * N_functionid - [OUT] index of the macro in string (if valid) *
+ * *
+ * Return value: unindexed macro from the allowed list or NULL *
+ * *
+ ******************************************************************************/
+static const char *func_macro_in_list(const char *str, zbx_token_func_macro_t *fm, int *N_functionid)
+{
+ int i;
+
+ for (i = 0; NULL != mod_macros[i].macro; i++)
+ {
+ size_t len, fm_len;
+
+ len = strlen(mod_macros[i].macro);
+ fm_len = fm->macro.r - fm->macro.l + 1;
+
+ if (len > fm_len || 0 != strncmp(mod_macros[i].macro, str + fm->macro.l, len - 1))
+ continue;
+
+ if (len != fm_len)
+ {
+ if (SUCCEED != is_uint_n_range(str + fm->macro.l + len - 1, fm_len - len, N_functionid,
+ sizeof(*N_functionid), 1, 9))
+ {
+ continue;
+ }
+ }
+ else if (mod_macros[i].macro[len - 1] != str[fm->macro.l + len - 1])
+ continue;
+
+ if (SUCCEED == str_n_in_list(mod_macros[i].functions, str + fm->func.l, fm->func_param.l - fm->func.l,
+ ','))
+ {
+ return mod_macros[i].macro;
+ }
+ }
+
+ return NULL;
+}
+
+/******************************************************************************
+ * *
* Function: get_trigger_function_value *
* *
* Purpose: trying to evaluate a trigger function *
@@ -2982,8 +3044,7 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT
case ZBX_TOKEN_FUNC_MACRO:
raw_value = 1;
indexed_macro = is_indexed_macro(*data, &token);
- if (NULL == (m = macro_in_list(*data, token.data.func_macro.macro, mod_macros,
- &N_functionid)))
+ if (NULL == (m = func_macro_in_list(*data, &token.data.func_macro, &N_functionid)))
{
/* Ignore functions with macros not supporting them, but do not skip the */
/* whole token, nested macro should be resolved in this case. */
@@ -3215,7 +3276,7 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT
ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
}
- else if (0 == strcmp(m, MVAR_TIME))
+ else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME))
{
replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
}
@@ -3464,7 +3525,7 @@ static int substitute_simple_macros_impl(zbx_uint64_t *actionid, const DB_EVENT
ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
}
- else if (0 == strcmp(m, MVAR_TIME))
+ else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME))
{
replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
}
@@ -5903,7 +5964,7 @@ int substitute_lld_macros(char **data, const struct zbx_json_parse *jp_row, cons
pos = token.loc.r;
break;
case ZBX_TOKEN_FUNC_MACRO:
- if (NULL != macro_in_list(*data, token.data.func_macro.macro, mod_macros, NULL))
+ if (NULL != func_macro_in_list(*data, &token.data.func_macro, NULL))
{
ret = substitute_func_macro(data, &token, jp_row, lld_macro_paths,
error, max_error_len);
diff --git a/src/libs/zbxserver/macrofunc.c b/src/libs/zbxserver/macrofunc.c
index 12eaf90f345..97f40f5cb68 100644
--- a/src/libs/zbxserver/macrofunc.c
+++ b/src/libs/zbxserver/macrofunc.c
@@ -20,6 +20,7 @@
#include "common.h"
#include "zbxregexp.h"
#include "macrofunc.h"
+#include "log.h"
/******************************************************************************
* *
@@ -27,8 +28,9 @@
* *
* Purpose: calculates regular expression substitution *
* *
- * Parameters: func - [IN] the function data *
- * out - [IN/OUT] the input/output value *
+ * Parameters: params - [IN] the function parameters *
+ * nparam - [IN] the function parameter count *
+ * out - [IN/OUT] the input/output value *
* *
* Return value: SUCCEED - the function was calculated successfully. *
* FAIL - the function calculation failed. *
@@ -59,8 +61,9 @@ static int macrofunc_regsub(char **params, size_t nparam, char **out)
* *
* Purpose: calculates case insensitive regular expression substitution *
* *
- * Parameters: func - [IN] the function data *
- * out - [IN/OUT] the input/output value *
+ * Parameters: params - [IN] the function parameters *
+ * nparam - [IN] the function parameter count *
+ * out - [IN/OUT] the input/output value *
* *
* Return value: SUCCEED - the function was calculated successfully. *
* FAIL - the function calculation failed. *
@@ -87,6 +90,115 @@ static int macrofunc_iregsub(char **params, size_t nparam, char **out)
/******************************************************************************
* *
+ * Function: macrofunc_fmttime *
+ * *
+ * Purpose: time formatting macro function *
+ * *
+ * Parameters: params - [IN] the function parameters *
+ * nparam - [IN] the function parameter count *
+ * out - [IN/OUT] the input/output value *
+ * *
+ * Return value: SUCCEED - the function was calculated successfully. *
+ * FAIL - the function calculation failed. *
+ * *
+ ******************************************************************************/
+static int macrofunc_fmttime(char **params, size_t nparam, char **out)
+{
+ struct tm local_time;
+ time_t time_new;
+ char *buf = NULL;
+
+ if (0 == nparam || 2 < nparam)
+ return FAIL;
+
+ time_new = time(&time_new);
+ localtime_r(&time_new, &local_time);
+
+ if (2 == nparam)
+ {
+ char *period = params[1], *error = NULL;
+ int period_num;
+ zbx_time_unit_t base;
+ size_t len;
+
+ /* second parameter must start with a negative sign, contain a value and end with a time unit */
+ if ('-' != period[0] || 2 >= strlen(period))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "invalid second parameter \"%s\"", params[1]);
+ return FAIL;
+ }
+
+ if (FAIL == zbx_tm_parse_period(++period, &len, &period_num, &base, &error) || '\0' != period[len])
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "cannot parse second parameter \"%s\": %s", params[1],
+ ZBX_NULL2STR(error));
+
+ zbx_free(error);
+ return FAIL;
+ }
+
+ zbx_tm_sub(&local_time, period_num, base);
+ }
+
+ buf = zbx_malloc(NULL, MAX_STRING_LEN);
+
+ if (0 == strftime(buf, MAX_STRING_LEN, params[0], &local_time))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "invalid first parameter \"%s\"", params[0]);
+ zbx_free(buf);
+ return FAIL;
+ }
+
+ zbx_free(*out);
+ *out = buf;
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: macrofunc_fmtnum *
+ * *
+ * Purpose: number formatting macro function *
+ * *
+ * Parameters: params - [IN] the function data *
+ * nparam - [IN] parameter count *
+ * out - [IN/OUT] the input/output value *
+ * *
+ * Return value: SUCCEED - the function was calculated successfully. *
+ * FAIL - the function calculation failed. *
+ * *
+ ******************************************************************************/
+static int macrofunc_fmtnum(char **params, size_t nparam, char **out)
+{
+ double value;
+ int precision;
+
+ if (1 != nparam)
+ return FAIL;
+
+ if (SUCCEED == is_uint32(*out, &value))
+ return SUCCEED;
+
+ if (FAIL == is_double(*out, &value))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "macro \"%s\" is not a number", *out);
+ return FAIL;
+ }
+
+ if (FAIL == is_uint32(params[0], &precision))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "invalid parameter \"%s\"", params[0]);
+ return FAIL;
+ }
+
+ *out = zbx_dsprintf(*out, "%.*f", precision, value);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
* Function: zbx_calculate_macro_function *
* *
* Purpose: calculates macro function value *
@@ -106,6 +218,8 @@ int zbx_calculate_macro_function(const char *expression, const zbx_token_func_ma
size_t nparam = 0, param_alloc = 8, buf_alloc = 0, buf_offset = 0, len, sep_pos;
int (*macrofunc)(char **params, size_t nparam, char **out), ret;
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
+
ptr = expression + func_macro->func.l;
len = func_macro->func_param.l - func_macro->func.l;
@@ -113,6 +227,10 @@ int zbx_calculate_macro_function(const char *expression, const zbx_token_func_ma
macrofunc = macrofunc_regsub;
else if (ZBX_CONST_STRLEN("iregsub") == len && 0 == strncmp(ptr, "iregsub", len))
macrofunc = macrofunc_iregsub;
+ else if (ZBX_CONST_STRLEN("fmttime") == len && 0 == strncmp(ptr, "fmttime", len))
+ macrofunc = macrofunc_fmttime;
+ else if (ZBX_CONST_STRLEN("fmtnum") == len && 0 == strncmp(ptr, "fmtnum", len))
+ macrofunc = macrofunc_fmtnum;
else
return FAIL;
@@ -143,6 +261,7 @@ int zbx_calculate_macro_function(const char *expression, const zbx_token_func_ma
zbx_free(params);
zbx_free(buf);
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s(), ret: %s", __func__, zbx_result_string(ret));
+
return ret;
}
-