1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "log.h"
22 #include "zbxalgo.h"
23 #include "zbxserver.h"
24 #include "eval.h"
25 
26 /* exit code in addition to SUCCEED/FAIL */
27 #define UNKNOWN		1
28 
29 /* bit function types */
30 typedef enum
31 {
32 	FUNCTION_OPTYPE_BIT_AND = 0,
33 	FUNCTION_OPTYPE_BIT_OR,
34 	FUNCTION_OPTYPE_BIT_XOR,
35 	FUNCTION_OPTYPE_BIT_LSHIFT,
36 	FUNCTION_OPTYPE_BIT_RSHIFT
37 }
38 zbx_function_bit_optype_t;
39 
40 /* trim function types */
41 typedef enum
42 {
43 	FUNCTION_OPTYPE_TRIM_ALL = 0,
44 	FUNCTION_OPTYPE_TRIM_LEFT,
45 	FUNCTION_OPTYPE_TRIM_RIGHT
46 }
47 zbx_function_trim_optype_t;
48 
49 /******************************************************************************
50  *                                                                            *
51  * Function: variant_convert_suffixed_num                                     *
52  *                                                                            *
53  * Purpose: convert variant string value containing suffixed number to        *
54  *          floating point variant value                                      *
55  *                                                                            *
56  * Parameters: value     - [OUT] the output value                             *
57  *             value_num - [IN] the value to convert                          *
58  *                                                                            *
59  * Return value: SUCCEED - the value was converted successfully               *
60  *               FAIL    - otherwise                                          *
61  *                                                                            *
62  ******************************************************************************/
variant_convert_suffixed_num(zbx_variant_t * value,const zbx_variant_t * value_num)63 static int	variant_convert_suffixed_num(zbx_variant_t *value, const zbx_variant_t *value_num)
64 {
65 	char	suffix;
66 	double	result;
67 
68 	if (ZBX_VARIANT_STR != value_num->type)
69 		return FAIL;
70 
71 	if (SUCCEED != eval_suffixed_number_parse(value_num->data.str, &suffix))
72 		return FAIL;
73 
74 	result = atof(value_num->data.str) * suffix2factor(suffix);
75 
76 	if (FP_ZERO != fpclassify(result) && FP_NORMAL != fpclassify(result))
77 		return FAIL;
78 
79 	zbx_variant_set_dbl(value, result);
80 
81 	return SUCCEED;
82 }
83 
84 /******************************************************************************
85  *                                                                            *
86  * Function: eval_execute_op_unary                                            *
87  *                                                                            *
88  * Purpose: evaluate unary operator                                           *
89  *                                                                            *
90  * Parameters: ctx      - [IN] the evaluation context                         *
91  *             token    - [IN] the operator token                             *
92  *             output   - [IN/OUT] the output value stack                     *
93  *             error    - [OUT] the error message in the case of failure      *
94  *                                                                            *
95  * Return value: SUCCEED - the operator was evaluated successfully            *
96  *               FAIL    - otherwise                                          *
97  *                                                                            *
98  ******************************************************************************/
eval_execute_op_unary(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)99 static int	eval_execute_op_unary(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
100 		zbx_vector_var_t *output, char **error)
101 {
102 	zbx_variant_t	*right;
103 	double		value;
104 
105 	if (1 > output->values_num)
106 	{
107 		*error = zbx_dsprintf(*error, "unary operator requires one operand at \"%s\"",
108 				ctx->expression + token->loc.l);
109 		return FAIL;
110 	}
111 
112 	right = &output->values[output->values_num - 1];
113 
114 	if (ZBX_VARIANT_ERR == right->type)
115 		return SUCCEED;
116 
117 	if (SUCCEED != zbx_variant_convert(right, ZBX_VARIANT_DBL))
118 	{
119 		*error = zbx_dsprintf(*error, "unary operator operand \"%s\" is not a numeric value at \"%s\"",
120 				zbx_variant_value_desc(right), ctx->expression + token->loc.l);
121 		return FAIL;
122 	}
123 
124 	switch (token->type)
125 	{
126 		case ZBX_EVAL_TOKEN_OP_MINUS:
127 			value = -right->data.dbl;
128 			break;
129 		case ZBX_EVAL_TOKEN_OP_NOT:
130 			value = (SUCCEED == zbx_double_compare(right->data.dbl, 0) ? 1 : 0);
131 			break;
132 		default:
133 			THIS_SHOULD_NEVER_HAPPEN;
134 			*error = zbx_dsprintf(*error, "unknown unary operator at \"%s\"",
135 					ctx->expression + token->loc.l);
136 			return FAIL;
137 	}
138 
139 	if (FP_ZERO != fpclassify(value) && FP_NORMAL != fpclassify(value))
140 	{
141 		*error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"",
142 				ctx->expression + token->loc.l);
143 		return FAIL;
144 	}
145 
146 	zbx_variant_clear(right);
147 	zbx_variant_set_dbl(right, value);
148 
149 	return SUCCEED;
150 }
151 
152 /******************************************************************************
153  *                                                                            *
154  * Function: eval_execute_op_logic_err                                        *
155  *                                                                            *
156  * Purpose: evaluate logical or/and operator with one operand being error     *
157  *                                                                            *
158  * Parameters: token  - [IN] the operator token                               *
159  *             value  - [IN] the other operand                                *
160  *             result - [OUT] the resulting value                             *
161  *                                                                            *
162  * Return value: SUCCEED - the oeprator was evaluated successfully            *
163  *               FAIL    - otherwise                                          *
164  *                                                                            *
165  ******************************************************************************/
eval_execute_op_logic_err(const zbx_eval_token_t * token,const zbx_variant_t * value,double * result)166 static int	eval_execute_op_logic_err(const zbx_eval_token_t *token, const zbx_variant_t *value, double *result)
167 {
168 	zbx_variant_t	value_dbl;
169 
170 	if (ZBX_VARIANT_ERR == value->type)
171 		return FAIL;
172 
173 	zbx_variant_copy(&value_dbl, value);
174 	if (SUCCEED != zbx_variant_convert(&value_dbl, ZBX_VARIANT_DBL))
175 	{
176 		zbx_variant_clear(&value_dbl);
177 		return FAIL;
178 	}
179 
180 	switch (token->type)
181 	{
182 		case ZBX_EVAL_TOKEN_OP_AND:
183 			if (SUCCEED == zbx_double_compare(value_dbl.data.dbl, 0))
184 			{
185 				*result = 0;
186 				return SUCCEED;
187 			}
188 			break;
189 		case ZBX_EVAL_TOKEN_OP_OR:
190 			if (SUCCEED != zbx_double_compare(value_dbl.data.dbl, 0))
191 			{
192 				*result = 1;
193 				return SUCCEED;
194 			}
195 			break;
196 	}
197 
198 	return FAIL;
199 }
200 
201 /******************************************************************************
202  *                                                                            *
203  * Function: eval_variant_compare                                             *
204  *                                                                            *
205  * Purpose: compare two variant values supporting suffixed numbers            *
206  *                                                                            *
207  * Return value: <0 - the first value is less than the second                 *
208  *               >0 - the first value is greater than the second              *
209  *               0  - the values are equal                                    *
210  *                                                                            *
211  ******************************************************************************/
eval_variant_compare(const zbx_variant_t * left,const zbx_variant_t * right)212 static int	eval_variant_compare(const zbx_variant_t *left, const zbx_variant_t *right)
213 {
214 	zbx_variant_t	val_l, val_r;
215 	int		ret;
216 
217 	zbx_variant_set_none(&val_l);
218 	zbx_variant_set_none(&val_r);
219 
220 	if (SUCCEED == variant_convert_suffixed_num(&val_l, left))
221 		left = &val_l;
222 
223 	if (SUCCEED == variant_convert_suffixed_num(&val_r, right))
224 		right = &val_r;
225 
226 	ret = zbx_variant_compare(left, right);
227 
228 	zbx_variant_clear(&val_l);
229 	zbx_variant_clear(&val_r);
230 
231 	return ret;
232 }
233 
234 /******************************************************************************
235  *                                                                            *
236  * Function: eval_execute_op_binary                                           *
237  *                                                                            *
238  * Purpose: evaluate binary operator                                          *
239  *                                                                            *
240  * Parameters: ctx      - [IN] the evaluation context                         *
241  *             token    - [IN] the operator token                             *
242  *             output   - [IN/OUT] the output value stack                     *
243  *             error    - [OUT] the error message in the case of failure      *
244  *                                                                            *
245  * Return value: SUCCEED - the operator was evaluated successfully            *
246  *               FAIL    - otherwise                                          *
247  *                                                                            *
248  ******************************************************************************/
eval_execute_op_binary(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)249 static int	eval_execute_op_binary(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
250 		zbx_vector_var_t *output, char **error)
251 {
252 	zbx_variant_t	*left, *right;
253 	double		value;
254 
255 	if (2 > output->values_num)
256 	{
257 		*error = zbx_dsprintf(*error, "binary operator requires two operands at \"%s\"",
258 				ctx->expression + token->loc.l);
259 
260 		return FAIL;
261 	}
262 
263 	left = &output->values[output->values_num - 2];
264 	right = &output->values[output->values_num - 1];
265 
266 	/* process error operands */
267 
268 	if (ZBX_VARIANT_ERR == left->type)
269 	{
270 		if (ZBX_EVAL_TOKEN_OP_AND == token->type || ZBX_EVAL_TOKEN_OP_OR == token->type)
271 		{
272 			if (SUCCEED == eval_execute_op_logic_err(token, right, &value))
273 				goto finish;
274 		}
275 
276 		zbx_variant_clear(right);
277 		output->values_num--;
278 
279 		return SUCCEED;
280 	}
281 	else if (ZBX_VARIANT_ERR == right->type)
282 	{
283 		if (ZBX_EVAL_TOKEN_OP_AND == token->type || ZBX_EVAL_TOKEN_OP_OR == token->type)
284 		{
285 			if (SUCCEED == eval_execute_op_logic_err(token, left, &value))
286 				goto finish;
287 		}
288 		zbx_variant_clear(left);
289 		*left = *right;
290 		output->values_num--;
291 
292 		return SUCCEED;
293 	}
294 
295 	/* check logical equal, not equal operators */
296 
297 	if (ZBX_EVAL_TOKEN_OP_EQ == token->type || ZBX_EVAL_TOKEN_OP_NE == token->type)
298 	{
299 		if (ZBX_VARIANT_DBL_VECTOR == left->type || ZBX_VARIANT_DBL_VECTOR == right->type)
300 		{
301 			*error = zbx_dsprintf(*error, "vector cannot be used with comparison operator at \"%s\"",
302 					ctx->expression + token->loc.l);
303 			return FAIL;
304 		}
305 
306 		switch (token->type)
307 		{
308 			case ZBX_EVAL_TOKEN_OP_EQ:
309 				value = (0 == eval_variant_compare(left, right) ? 1 : 0);
310 				goto finish;
311 			case ZBX_EVAL_TOKEN_OP_NE:
312 				value = (0 == eval_variant_compare(left, right) ? 0 : 1);
313 				goto finish;
314 		}
315 	}
316 
317 	/* check arithmetic operators */
318 
319 	if (SUCCEED != zbx_variant_convert(left, ZBX_VARIANT_DBL))
320 	{
321 		*error = zbx_dsprintf(*error, "left operand \"%s\" is not a numeric value for operator at \"%s\"",
322 				zbx_variant_value_desc(left), ctx->expression + token->loc.l);
323 		return FAIL;
324 	}
325 
326 	if (SUCCEED != zbx_variant_convert(right, ZBX_VARIANT_DBL))
327 	{
328 		*error = zbx_dsprintf(*error, "right operand \"%s\" is not a numeric value for operator at \"%s\"",
329 				zbx_variant_value_desc(right), ctx->expression + token->loc.l);
330 		return FAIL;
331 	}
332 
333 	/* check logical operators */
334 
335 	switch (token->type)
336 	{
337 		case ZBX_EVAL_TOKEN_OP_AND:
338 			if (SUCCEED == zbx_double_compare(left->data.dbl, 0) ||
339 					SUCCEED == zbx_double_compare(right->data.dbl, 0))
340 			{
341 				value = 0;
342 			}
343 			else
344 				value = 1;
345 			goto finish;
346 		case ZBX_EVAL_TOKEN_OP_OR:
347 			if (SUCCEED != zbx_double_compare(left->data.dbl, 0) ||
348 					SUCCEED != zbx_double_compare(right->data.dbl, 0))
349 			{
350 				value = 1;
351 			}
352 			else
353 				value = 0;
354 			goto finish;
355 	}
356 
357 	/* check arithmetic operators */
358 
359 	switch (token->type)
360 	{
361 		case ZBX_EVAL_TOKEN_OP_LT:
362 			value = (0 > zbx_variant_compare(left, right) ? 1 : 0);
363 			break;
364 		case ZBX_EVAL_TOKEN_OP_LE:
365 			value = (0 >= zbx_variant_compare(left, right) ? 1 : 0);
366 			break;
367 		case ZBX_EVAL_TOKEN_OP_GT:
368 			value = (0 < zbx_variant_compare(left, right) ? 1 : 0);
369 			break;
370 		case ZBX_EVAL_TOKEN_OP_GE:
371 			value = (0 <= zbx_variant_compare(left, right) ? 1 : 0);
372 			break;
373 		case ZBX_EVAL_TOKEN_OP_ADD:
374 			value = left->data.dbl + right->data.dbl;
375 			break;
376 		case ZBX_EVAL_TOKEN_OP_SUB:
377 			value = left->data.dbl - right->data.dbl;
378 			break;
379 		case ZBX_EVAL_TOKEN_OP_MUL:
380 			value = left->data.dbl * right->data.dbl;
381 			break;
382 		case ZBX_EVAL_TOKEN_OP_DIV:
383 			if (SUCCEED == zbx_double_compare(right->data.dbl, 0))
384 			{
385 				*error = zbx_dsprintf(*error, "division by zero at \"%s\"",
386 						ctx->expression + token->loc.l);
387 				return FAIL;
388 			}
389 			value = left->data.dbl / right->data.dbl;
390 			break;
391 	}
392 
393 	if (FP_ZERO != fpclassify(value) && FP_NORMAL != fpclassify(value))
394 	{
395 		*error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"",
396 				ctx->expression + token->loc.l);
397 		return FAIL;
398 	}
399 
400 finish:
401 	zbx_variant_clear(left);
402 	zbx_variant_clear(right);
403 	zbx_variant_set_dbl(left, value);
404 	output->values_num--;
405 
406 	return SUCCEED;
407 }
408 
409 /******************************************************************************
410  *                                                                            *
411  * Function: eval_suffixed_number_parse                                       *
412  *                                                                            *
413  * Purpose: check if the value is suffixed number and return the suffix if    *
414  *          exists                                                            *
415  *                                                                            *
416  * Parameters: value  - [IN] the value to check                               *
417  *             suffix - [OUT] the suffix or 0 if number does not have suffix  *
418  *                            (optional)                                      *
419  *                                                                            *
420  * Return value: SUCCEED - the value is suffixed number                       *
421  *               FAIL    - otherwise                                          *
422  *                                                                            *
423  ******************************************************************************/
eval_suffixed_number_parse(const char * value,char * suffix)424 int	 eval_suffixed_number_parse(const char *value, char *suffix)
425 {
426 	int	len, num_len;
427 
428 	if ('-' == *value)
429 		value++;
430 
431 	len = strlen(value);
432 
433 	if (SUCCEED != zbx_suffixed_number_parse(value, &num_len) || num_len != len)
434 		return FAIL;
435 
436 	if (NULL != suffix)
437 		*suffix = value[len - 1];
438 
439 	return SUCCEED;
440 }
441 
442 /******************************************************************************
443  *                                                                            *
444  * Function: eval_execute_push_value                                          *
445  *                                                                            *
446  * Purpose: push value in output stack                                        *
447  *                                                                            *
448  * Parameters: ctx      - [IN] the evaluation context                         *
449  *             token    - [IN] the value token                                *
450  *             output   - [IN/OUT] the output value stack                     *
451  *             error    - [OUT] the error message in the case of failure      *
452  *                                                                            *
453  * Return value: SUCCEED - the value was pushed successfully                  *
454  *               FAIL    - otherwise                                          *
455  *                                                                            *
456  ******************************************************************************/
eval_execute_push_value(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)457 static int	eval_execute_push_value(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
458 		zbx_vector_var_t *output, char **error)
459 {
460 	zbx_variant_t	value;
461 	char		*dst;
462 	const char	*src;
463 
464 	if (ZBX_VARIANT_NONE == token->value.type)
465 	{
466 		if (ZBX_EVAL_TOKEN_VAR_NUM == token->type)
467 		{
468 			zbx_uint64_t	ui64;
469 
470 			if (SUCCEED == is_uint64_n(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1,
471 					&ui64))
472 			{
473 				zbx_variant_set_ui64(&value, ui64);
474 			}
475 			else
476 			{
477 				zbx_variant_set_dbl(&value, atof(ctx->expression + token->loc.l) *
478 						suffix2factor(ctx->expression[token->loc.r]));
479 			}
480 		}
481 		else
482 		{
483 			dst = zbx_malloc(NULL, token->loc.r - token->loc.l + 2);
484 			zbx_variant_set_str(&value, dst);
485 
486 			if (ZBX_EVAL_TOKEN_VAR_STR == token->type)
487 			{
488 				for (src = ctx->expression + token->loc.l + 1; src < ctx->expression + token->loc.r;
489 						src++)
490 				{
491 					if ('\\' == *src)
492 						src++;
493 					*dst++ = *src;
494 				}
495 			}
496 			else
497 			{
498 				memcpy(dst, ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1);
499 				dst += token->loc.r - token->loc.l + 1;
500 			}
501 
502 			*dst = '\0';
503 		}
504 	}
505 	else
506 	{
507 		if (ZBX_VARIANT_ERR == token->value.type && 0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR))
508 		{
509 			*error = zbx_strdup(*error, token->value.data.err);
510 			return FAIL;
511 		}
512 
513 		/* Expanded user macro token variables can contain suffixed numbers. */
514 		/* Try to convert them and just copy the expanded value if failed.   */
515 		if (ZBX_EVAL_TOKEN_VAR_USERMACRO != token->type ||
516 				SUCCEED != variant_convert_suffixed_num(&value, &token->value))
517 		{
518 			zbx_variant_copy(&value, &token->value);
519 		}
520 
521 	}
522 
523 	zbx_vector_var_append_ptr(output, &value);
524 
525 	return SUCCEED;
526 }
527 
528 /******************************************************************************
529  *                                                                            *
530  * Function: eval_execute_push_null                                           *
531  *                                                                            *
532  * Purpose: push null value in output stack                                   *
533  *                                                                            *
534  * Parameters: output   - [IN/OUT] the output value stack                     *
535  *                                                                            *
536  ******************************************************************************/
eval_execute_push_null(zbx_vector_var_t * output)537 static void	eval_execute_push_null(zbx_vector_var_t *output)
538 {
539 	zbx_variant_t	value;
540 
541 	zbx_variant_set_none(&value);
542 	zbx_vector_var_append_ptr(output, &value);
543 }
544 
545 /******************************************************************************
546  *                                                                            *
547  * Function: eval_compare_token                                               *
548  *                                                                            *
549  * Purpose: check if expression fragment matches the specified text           *
550  *                                                                            *
551  * Parameters: ctx  - [IN] the evaluation context                             *
552  *             loc  - [IN] the expression fragment location                   *
553  *             text - [IN] the text to compare with                           *
554  *             len  - [IN] the text length                                    *
555  *                                                                            *
556  * Return value: SUCCEED - the expression fragment matches the text           *
557  *               FAIL    - otherwise                                          *
558  *                                                                            *
559  ******************************************************************************/
eval_compare_token(const zbx_eval_context_t * ctx,const zbx_strloc_t * loc,const char * text,size_t len)560 int	eval_compare_token(const zbx_eval_context_t *ctx, const zbx_strloc_t *loc, const char *text,
561 		size_t len)
562 {
563 	if (loc->r - loc->l + 1 != len)
564 		return FAIL;
565 
566 	if (0 != memcmp(ctx->expression + loc->l, text, len))
567 		return FAIL;
568 
569 	return SUCCEED;
570 }
571 
572 /******************************************************************************
573  *                                                                            *
574  * Function: eval_function_return                                             *
575  *                                                                            *
576  * Purpose: handle function return                                            *
577  *                                                                            *
578  * Parameters: args_num - [IN] the number of function arguments               *
579  *             value    - [IN] the return value                               *
580  *             output   - [IN/OUT] the output value stack                     *
581  *                                                                            *
582  * Comments: The function arguments on output stack are replaced with the     *
583  *           return value.                                                    *
584  *                                                                            *
585  ******************************************************************************/
eval_function_return(zbx_uint32_t args_num,zbx_variant_t * value,zbx_vector_var_t * output)586 static void	eval_function_return(zbx_uint32_t args_num, zbx_variant_t *value, zbx_vector_var_t *output)
587 {
588 	int	i;
589 
590 	for (i = output->values_num - (int)args_num; i < output->values_num; i++)
591 		zbx_variant_clear(&output->values[i]);
592 
593 	output->values_num -= (int)args_num;
594 
595 	zbx_vector_var_append_ptr(output, value);
596 }
597 
598 /******************************************************************************
599  *                                                                            *
600  * Function: eval_validate_function_args                                      *
601  *                                                                            *
602  * Purpose: validate function arguments                                       *
603  *                                                                            *
604  * Parameters: ctx    - [IN] the evaluation context                           *
605  *             token  - [IN] the function token                               *
606  *             output - [IN/OUT] the output value stack                       *
607  *             error  - [OUT] the error message in the case of failure        *
608  *                                                                            *
609  * Return value: SUCCEED - function arguments contain error values - the      *
610  *                         first error is returned as function value without  *
611  *                         evaluating the function                            *
612  *               FAIL    - argument validation failed                         *
613  *               UNKNOWN - argument validation succeeded, function result is  *
614  *                         unknown at the moment, function must be evaluated  *
615  *                         with the prepared arguments                        *
616  *                                                                            *
617  ******************************************************************************/
eval_validate_function_args(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)618 static int	eval_validate_function_args(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
619 		zbx_vector_var_t *output, char **error)
620 {
621 	int	i;
622 
623 	if (output->values_num < (int)token->opt)
624 	{
625 		*error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"",
626 				ctx->expression + token->loc.l);
627 		return FAIL;
628 	}
629 
630 	for (i = output->values_num - token->opt; i < output->values_num; i++)
631 	{
632 		if (ZBX_VARIANT_ERR == output->values[i].type)
633 		{
634 			zbx_variant_t	value = output->values[i];
635 
636 			/* first error argument is used as function return value */
637 			zbx_variant_set_none(&output->values[i]);
638 			eval_function_return(token->opt, &value, output);
639 
640 			return SUCCEED;
641 		}
642 	}
643 
644 	return UNKNOWN;
645 }
646 
eval_type_desc(unsigned char type)647 static const char	*eval_type_desc(unsigned char type)
648 {
649 	switch (type)
650 	{
651 		case ZBX_VARIANT_DBL:
652 			return "a numeric";
653 		case ZBX_VARIANT_UI64:
654 			return "an unsigned integer";
655 		case ZBX_VARIANT_STR:
656 			return "a string";
657 		default:
658 			return zbx_get_variant_type_desc(type);
659 	}
660 }
661 
662 /******************************************************************************
663  *                                                                            *
664  * Function: eval_convert_function_arg                                        *
665  *                                                                            *
666  * Purpose: convert function argument to the specified type                   *
667  *                                                                            *
668  * Parameters: ctx    - [IN] the evaluation context                           *
669  *             token  - [IN] the function token                               *
670  *             type   - [IN] the required type                                *
671  *             arg    - [IN/OUT] the argument to convert                      *
672  *             error  - [OUT] the error message in the case of failure        *
673  *                                                                            *
674  * Return value: SUCCEED - argument was converted successfully                *
675  *               FAIL    - otherwise                                          *
676  *                                                                            *
677  ******************************************************************************/
eval_convert_function_arg(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,unsigned char type,zbx_variant_t * arg,char ** error)678 static int	eval_convert_function_arg(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
679 		unsigned char type, zbx_variant_t *arg, char **error)
680 {
681 	zbx_variant_t	value;
682 
683 	if (ZBX_VARIANT_DBL == type && SUCCEED == variant_convert_suffixed_num(&value, arg))
684 	{
685 		zbx_variant_clear(arg);
686 		*arg = value;
687 		return SUCCEED;
688 	}
689 
690 	if (SUCCEED == zbx_variant_convert(arg, type))
691 		return SUCCEED;
692 
693 	*error = zbx_dsprintf(*error, "function argument \"%s\" is not %s value at \"%s\"",
694 			zbx_variant_value_desc(arg),  eval_type_desc(type), ctx->expression + token->loc.l);
695 
696 	return FAIL;
697 }
698 
699 /******************************************************************************
700  *                                                                            *
701  * Function: eval_prepare_math_function_args                                  *
702  *                                                                            *
703  * Purpose: validate and prepare (convert to floating values) math function   *
704  *          arguments                                                         *
705  *                                                                            *
706  * Parameters: ctx    - [IN] the evaluation context                           *
707  *             token  - [IN] the function token                               *
708  *             output - [IN/OUT] the output value stack                       *
709  *             error  - [OUT] the error message in the case of failure        *
710  *                                                                            *
711  * Return value: SUCCEED - function arguments contain error values - the      *
712  *                         first error is returned as function value without  *
713  *                         evaluating the function                            *
714  *               FAIL    - argument validation/conversion failed              *
715  *               UNKNOWN - argument conversion succeeded, function result is  *
716  *                         unknown at the moment, function must be evaluated  *
717  *                         with the prepared arguments                        *
718  *                                                                            *
719  * Comments: Math function accepts either 1+ arguments that can be converted  *
720  *           to floating values or a single argument of non-zero length       *
721  *           floating value vector.                                           *
722  *                                                                            *
723  ******************************************************************************/
eval_prepare_math_function_args(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)724 static int	eval_prepare_math_function_args(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
725 		zbx_vector_var_t *output, char **error)
726 {
727 	int	i, ret;
728 
729 	if (0 == token->opt)
730 	{
731 		*error = zbx_dsprintf(*error, "no arguments for function at \"%s\"", ctx->expression + token->loc.l);
732 		return FAIL;
733 	}
734 
735 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
736 		return ret;
737 
738 	i = output->values_num - token->opt;
739 
740 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
741 	{
742 		for (; i < output->values_num; i++)
743 		{
744 			if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_DBL, &output->values[i], error))
745 				return FAIL;
746 		}
747 	}
748 	else
749 	{
750 		if (1 != token->opt)
751 		{
752 			*error = zbx_dsprintf(*error, "too many arguments for function at \"%s\"",
753 					ctx->expression + token->loc.l);
754 			return FAIL;
755 		}
756 
757 		if (0 == output->values[i].data.dbl_vector->values_num)
758 		{
759 			*error = zbx_dsprintf(*error, "empty vector argument for function at \"%s\"",
760 					ctx->expression + token->loc.l);
761 			return FAIL;
762 		}
763 	}
764 
765 	return UNKNOWN;
766 }
767 
768 /******************************************************************************
769  *                                                                            *
770  * Function: eval_execute_function_min                                        *
771  *                                                                            *
772  * Purpose: evaluate min() function                                           *
773  *                                                                            *
774  * Parameters: ctx    - [IN] the evaluation context                           *
775  *             token  - [IN] the function token                               *
776  *             output - [IN/OUT] the output value stack                       *
777  *             error  - [OUT] the error message in the case of failure        *
778  *                                                                            *
779  * Return value: SUCCEED - function evaluation succeeded                      *
780  *               FAIL    - otherwise                                          *
781  *                                                                            *
782  ******************************************************************************/
eval_execute_function_min(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)783 static int	eval_execute_function_min(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
784 		zbx_vector_var_t *output, char **error)
785 {
786 	int		i, ret;
787 	double		min;
788 	zbx_variant_t	value;
789 
790 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
791 		return ret;
792 
793 	i = output->values_num - token->opt;
794 
795 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
796 	{
797 		min = output->values[i++].data.dbl;
798 
799 		for (; i < output->values_num; i++)
800 		{
801 			if (min > output->values[i].data.dbl)
802 				min = output->values[i].data.dbl;
803 		}
804 	}
805 	else
806 	{
807 		zbx_vector_dbl_t	*dbl_vector = output->values[i].data.dbl_vector;
808 
809 		min = dbl_vector->values[0];
810 
811 		for (i = 1; i < dbl_vector->values_num; i++)
812 		{
813 			if (min > dbl_vector->values[i])
814 				min = dbl_vector->values[i];
815 		}
816 	}
817 
818 	zbx_variant_set_dbl(&value, min);
819 	eval_function_return(token->opt, &value, output);
820 
821 	return SUCCEED;
822 }
823 
824 /******************************************************************************
825  *                                                                            *
826  * Function: eval_execute_function_max                                        *
827  *                                                                            *
828  * Purpose: evaluate max() function                                           *
829  *                                                                            *
830  * Parameters: ctx    - [IN] the evaluation context                           *
831  *             token  - [IN] the function token                               *
832  *             output - [IN/OUT] the output value stack                       *
833  *             error  - [OUT] the error message in the case of failure        *
834  *                                                                            *
835  * Return value: SUCCEED - function evaluation succeeded                      *
836  *               FAIL    - otherwise                                          *
837  *                                                                            *
838  ******************************************************************************/
eval_execute_function_max(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)839 static int	eval_execute_function_max(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
840 		zbx_vector_var_t *output, char **error)
841 {
842 	int		i, ret;
843 	double		max;
844 	zbx_variant_t	value;
845 
846 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
847 		return ret;
848 
849 	i = output->values_num - token->opt;
850 
851 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
852 	{
853 		max = output->values[i++].data.dbl;
854 
855 		for (; i < output->values_num; i++)
856 		{
857 			if (max < output->values[i].data.dbl)
858 				max = output->values[i].data.dbl;
859 		}
860 	}
861 	else
862 	{
863 		zbx_vector_dbl_t	*dbl_vector = output->values[i].data.dbl_vector;
864 
865 		max = dbl_vector->values[0];
866 
867 		for (i = 1; i < dbl_vector->values_num; i++)
868 		{
869 			if (max < dbl_vector->values[i])
870 				max = dbl_vector->values[i];
871 		}
872 	}
873 
874 	zbx_variant_set_dbl(&value, max);
875 	eval_function_return(token->opt, &value, output);
876 
877 	return SUCCEED;
878 }
879 
880 /******************************************************************************
881  *                                                                            *
882  * Function: eval_execute_function_sum                                        *
883  *                                                                            *
884  * Purpose: evaluate sum() function                                           *
885  *                                                                            *
886  * Parameters: ctx    - [IN] the evaluation context                           *
887  *             token  - [IN] the function token                               *
888  *             output - [IN/OUT] the output value stack                       *
889  *             error  - [OUT] the error message in the case of failure        *
890  *                                                                            *
891  * Return value: SUCCEED - function evaluation succeeded                      *
892  *               FAIL    - otherwise                                          *
893  *                                                                            *
894  ******************************************************************************/
eval_execute_function_sum(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)895 static int	eval_execute_function_sum(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
896 		zbx_vector_var_t *output, char **error)
897 {
898 	int		i, ret;
899 	double		sum = 0;
900 	zbx_variant_t	value;
901 
902 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
903 		return ret;
904 
905 	i = output->values_num - token->opt;
906 
907 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
908 	{
909 		for (; i < output->values_num; i++)
910 			sum += output->values[i].data.dbl;
911 	}
912 	else
913 	{
914 		zbx_vector_dbl_t	*dbl_vector = output->values[i].data.dbl_vector;
915 
916 		for (i = 0; i < dbl_vector->values_num; i++)
917 			sum += dbl_vector->values[i];
918 	}
919 
920 	zbx_variant_set_dbl(&value, sum);
921 	eval_function_return(token->opt, &value, output);
922 
923 	return SUCCEED;
924 }
925 
926 /******************************************************************************
927  *                                                                            *
928  * Function: eval_execute_function_avg                                        *
929  *                                                                            *
930  * Purpose: evaluate avg() function                                           *
931  *                                                                            *
932  * Parameters: ctx    - [IN] the evaluation context                           *
933  *             token  - [IN] the function token                               *
934  *             output - [IN/OUT] the output value stack                       *
935  *             error  - [OUT] the error message in the case of failure        *
936  *                                                                            *
937  * Return value: SUCCEED - function evaluation succeeded                      *
938  *               FAIL    - otherwise                                          *
939  *                                                                            *
940  ******************************************************************************/
eval_execute_function_avg(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)941 static int	eval_execute_function_avg(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
942 		zbx_vector_var_t *output, char **error)
943 {
944 	int		i, ret;
945 	double		avg = 0;
946 	zbx_variant_t	value;
947 
948 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
949 		return ret;
950 
951 	i = output->values_num - token->opt;
952 
953 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
954 	{
955 		for (; i < output->values_num; i++)
956 			avg += output->values[i].data.dbl;
957 
958 		avg /= token->opt;
959 	}
960 	else
961 	{
962 		zbx_vector_dbl_t	*dbl_vector = output->values[i].data.dbl_vector;
963 
964 		for (i = 0; i < dbl_vector->values_num; i++)
965 			avg += dbl_vector->values[i];
966 
967 		avg /= dbl_vector->values_num;
968 	}
969 
970 	zbx_variant_set_dbl(&value, avg);
971 	eval_function_return(token->opt, &value, output);
972 
973 	return SUCCEED;
974 }
975 
976 /******************************************************************************
977  *                                                                            *
978  * Function: eval_execute_function_abs                                     *
979  *                                                                            *
980  * Purpose: evaluate abs() function                                        *
981  *                                                                            *
982  * Parameters: ctx    - [IN] the evaluation context                           *
983  *             token  - [IN] the function token                               *
984  *             output - [IN/OUT] the output value stack                       *
985  *             error  - [OUT] the error message in the case of failure        *
986  *                                                                            *
987  * Return value: SUCCEED - function evaluation succeeded                      *
988  *               FAIL    - otherwise                                          *
989  *                                                                            *
990  ******************************************************************************/
eval_execute_function_abs(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)991 static int	eval_execute_function_abs(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
992 		zbx_vector_var_t *output, char **error)
993 {
994 	int		ret;
995 	zbx_variant_t	*arg, value;
996 
997 	if (1 != token->opt)
998 	{
999 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1000 				ctx->expression + token->loc.l);
1001 		return FAIL;
1002 	}
1003 
1004 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
1005 		return ret;
1006 
1007 	arg = &output->values[output->values_num - 1];
1008 	zbx_variant_set_dbl(&value, fabs(arg->data.dbl));
1009 	eval_function_return(token->opt, &value, output);
1010 
1011 	return SUCCEED;
1012 }
1013 
1014 /******************************************************************************
1015  *                                                                            *
1016  * Function: eval_execute_function_length                                     *
1017  *                                                                            *
1018  * Purpose: evaluate length() function                                        *
1019  *                                                                            *
1020  * Parameters: ctx    - [IN] the evaluation context                           *
1021  *             token  - [IN] the function token                               *
1022  *             output - [IN/OUT] the output value stack                       *
1023  *             error  - [OUT] the error message in the case of failure        *
1024  *                                                                            *
1025  * Return value: SUCCEED - function evaluation succeeded                      *
1026  *               FAIL    - otherwise                                          *
1027  *                                                                            *
1028  ******************************************************************************/
eval_execute_function_length(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1029 static int	eval_execute_function_length(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1030 		zbx_vector_var_t *output, char **error)
1031 {
1032 	int		ret;
1033 	zbx_variant_t	*arg, value;
1034 
1035 	if (1 != token->opt)
1036 	{
1037 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1038 				ctx->expression + token->loc.l);
1039 		return FAIL;
1040 	}
1041 
1042 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1043 		return ret;
1044 
1045 	arg = &output->values[output->values_num - 1];
1046 
1047 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error))
1048 		return FAIL;
1049 
1050 	zbx_variant_set_dbl(&value, zbx_strlen_utf8(arg->data.str));
1051 	eval_function_return(1, &value, output);
1052 
1053 	return SUCCEED;
1054 }
1055 
1056 /******************************************************************************
1057  *                                                                            *
1058  * Function: eval_execute_function_date                                       *
1059  *                                                                            *
1060  * Purpose: evaluate date() function                                          *
1061  *                                                                            *
1062  * Parameters: ctx    - [IN] the evaluation context                           *
1063  *             token  - [IN] the function token                               *
1064  *             output - [IN/OUT] the output value stack                       *
1065  *             error  - [OUT] the error message in the case of failure        *
1066  *                                                                            *
1067  * Return value: SUCCEED - function evaluation succeeded                      *
1068  *               FAIL    - otherwise                                          *
1069  *                                                                            *
1070  ******************************************************************************/
eval_execute_function_date(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1071 static int	eval_execute_function_date(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1072 		zbx_vector_var_t *output, char **error)
1073 {
1074 	zbx_variant_t	value;
1075 	struct tm	*tm;
1076 	time_t		now;
1077 
1078 	if (0 != token->opt)
1079 	{
1080 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1081 				ctx->expression + token->loc.l);
1082 		return FAIL;
1083 	}
1084 
1085 	now = ctx->ts.sec;
1086 	if (NULL == (tm = localtime(&now)))
1087 	{
1088 		*error = zbx_dsprintf(*error, "cannot convert time for function at \"%s\": %s",
1089 				ctx->expression + token->loc.l, zbx_strerror(errno));
1090 		return FAIL;
1091 	}
1092 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%.4d%.2d%.2d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday));
1093 	eval_function_return(0, &value, output);
1094 
1095 	return SUCCEED;
1096 }
1097 
1098 /******************************************************************************
1099  *                                                                            *
1100  * Function: eval_execute_function_time                                       *
1101  *                                                                            *
1102  * Purpose: evaluate time() function                                          *
1103  *                                                                            *
1104  * Parameters: ctx    - [IN] the evaluation context                           *
1105  *             token  - [IN] the function token                               *
1106  *             output - [IN/OUT] the output value stack                       *
1107  *             error  - [OUT] the error message in the case of failure        *
1108  *                                                                            *
1109  * Return value: SUCCEED - function evaluation succeeded                      *
1110  *               FAIL    - otherwise                                          *
1111  *                                                                            *
1112  ******************************************************************************/
eval_execute_function_time(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1113 static int	eval_execute_function_time(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1114 		zbx_vector_var_t *output, char **error)
1115 {
1116 	zbx_variant_t	value;
1117 	struct tm	*tm;
1118 	time_t		now;
1119 
1120 	if (0 != token->opt)
1121 	{
1122 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1123 				ctx->expression + token->loc.l);
1124 		return FAIL;
1125 	}
1126 
1127 	now = ctx->ts.sec;
1128 	if (NULL == (tm = localtime(&now)))
1129 	{
1130 		*error = zbx_dsprintf(*error, "cannot convert time for function at \"%s\": %s",
1131 				ctx->expression + token->loc.l, zbx_strerror(errno));
1132 		return FAIL;
1133 	}
1134 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%.2d%.2d%.2d", tm->tm_hour, tm->tm_min, tm->tm_sec));
1135 	eval_function_return(0, &value, output);
1136 
1137 	return SUCCEED;
1138 }
1139 /******************************************************************************
1140  *                                                                            *
1141  * Function: eval_execute_function_now                                        *
1142  *                                                                            *
1143  * Purpose: evaluate now() function                                           *
1144  *                                                                            *
1145  * Parameters: ctx    - [IN] the evaluation context                           *
1146  *             token  - [IN] the function token                               *
1147  *             output - [IN/OUT] the output value stack                       *
1148  *             error  - [OUT] the error message in the case of failure        *
1149  *                                                                            *
1150  * Return value: SUCCEED - function evaluation succeeded                      *
1151  *               FAIL    - otherwise                                          *
1152  *                                                                            *
1153  ******************************************************************************/
eval_execute_function_now(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1154 static int	eval_execute_function_now(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1155 		zbx_vector_var_t *output, char **error)
1156 {
1157 	zbx_variant_t	value;
1158 
1159 	if (0 != token->opt)
1160 	{
1161 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1162 				ctx->expression + token->loc.l);
1163 		return FAIL;
1164 	}
1165 
1166 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%d", ctx->ts.sec));
1167 	eval_function_return(0, &value, output);
1168 
1169 	return SUCCEED;
1170 }
1171 /******************************************************************************
1172  *                                                                            *
1173  * Function: eval_execute_function_dayofweek                                  *
1174  *                                                                            *
1175  * Purpose: evaluate dayofweek() function                                     *
1176  *                                                                            *
1177  * Parameters: ctx    - [IN] the evaluation context                           *
1178  *             token  - [IN] the function token                               *
1179  *             output - [IN/OUT] the output value stack                       *
1180  *             error  - [OUT] the error message in the case of failure        *
1181  *                                                                            *
1182  * Return value: SUCCEED - function evaluation succeeded                      *
1183  *               FAIL    - otherwise                                          *
1184  *                                                                            *
1185  ******************************************************************************/
eval_execute_function_dayofweek(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1186 static int	eval_execute_function_dayofweek(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1187 		zbx_vector_var_t *output, char **error)
1188 {
1189 	zbx_variant_t	value;
1190 	struct tm	*tm;
1191 	time_t		now;
1192 
1193 	if (0 != token->opt)
1194 	{
1195 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1196 				ctx->expression + token->loc.l);
1197 		return FAIL;
1198 	}
1199 
1200 	now = ctx->ts.sec;
1201 	if (NULL == (tm = localtime(&now)))
1202 	{
1203 		*error = zbx_dsprintf(*error, "cannot convert time for function at \"%s\": %s",
1204 				ctx->expression + token->loc.l, zbx_strerror(errno));
1205 		return FAIL;
1206 	}
1207 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%d", 0 == tm->tm_wday ? 7 : tm->tm_wday));
1208 	eval_function_return(0, &value, output);
1209 
1210 	return SUCCEED;
1211 }
1212 
1213 /******************************************************************************
1214  *                                                                            *
1215  * Function: eval_execute_function_dayofmonth                                 *
1216  *                                                                            *
1217  * Purpose: evaluate dayofmonth() function                                    *
1218  *                                                                            *
1219  * Parameters: ctx    - [IN] the evaluation context                           *
1220  *             token  - [IN] the function token                               *
1221  *             output - [IN/OUT] the output value stack                       *
1222  *             error  - [OUT] the error message in the case of failure        *
1223  *                                                                            *
1224  * Return value: SUCCEED - function evaluation succeeded                      *
1225  *               FAIL    - otherwise                                          *
1226  *                                                                            *
1227  ******************************************************************************/
eval_execute_function_dayofmonth(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1228 static int	eval_execute_function_dayofmonth(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1229 		zbx_vector_var_t *output, char **error)
1230 {
1231 	zbx_variant_t	value;
1232 	struct tm	*tm;
1233 	time_t		now;
1234 
1235 	if (0 != token->opt)
1236 	{
1237 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1238 				ctx->expression + token->loc.l);
1239 		return FAIL;
1240 	}
1241 
1242 	now = ctx->ts.sec;
1243 	if (NULL == (tm = localtime(&now)))
1244 	{
1245 		*error = zbx_dsprintf(*error, "cannot convert time for function at \"%s\": %s",
1246 				ctx->expression + token->loc.l, zbx_strerror(errno));
1247 		return FAIL;
1248 	}
1249 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%d", tm->tm_mday));
1250 	eval_function_return(0, &value, output);
1251 
1252 	return SUCCEED;
1253 }
1254 
1255 /******************************************************************************
1256  *                                                                            *
1257  * Function: eval_execute_function_bitwise                                    *
1258  *                                                                            *
1259  * Purpose: evaluate bitand(), bitor(), bitxor(), bitlshift(),                *
1260  *          bitrshift() functions                                             *
1261  *                                                                            *
1262  * Parameters: ctx    - [IN] the evaluation context                           *
1263  *             token  - [IN] the function token                               *
1264  *             type   - [IN] the function type                                *
1265  *             output - [IN/OUT] the output value stack                       *
1266  *             error  - [OUT] the error message in the case of failure        *
1267  *                                                                            *
1268  * Return value: SUCCEED - function evaluation succeeded                      *
1269  *               FAIL    - otherwise                                          *
1270  *                                                                            *
1271  ******************************************************************************/
eval_execute_function_bitwise(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_function_bit_optype_t type,zbx_vector_var_t * output,char ** error)1272 static int	eval_execute_function_bitwise(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1273 		zbx_function_bit_optype_t type, zbx_vector_var_t *output, char **error)
1274 {
1275 	zbx_variant_t	value, *left, *right;
1276 	int		ret;
1277 
1278 	if (2 != token->opt)
1279 	{
1280 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1281 				ctx->expression + token->loc.l);
1282 		return FAIL;
1283 	}
1284 
1285 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1286 		return ret;
1287 
1288 	left = &output->values[output->values_num - 2];
1289 	right = &output->values[output->values_num - 1];
1290 
1291 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, left, error) ||
1292 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, right, error))
1293 	{
1294 		return FAIL;
1295 	}
1296 
1297 	switch (type)
1298 	{
1299 		case FUNCTION_OPTYPE_BIT_AND:
1300 			zbx_variant_set_ui64(&value, left->data.ui64 & right->data.ui64);
1301 			break;
1302 		case FUNCTION_OPTYPE_BIT_OR:
1303 			zbx_variant_set_ui64(&value, left->data.ui64 | right->data.ui64);
1304 			break;
1305 		case FUNCTION_OPTYPE_BIT_XOR:
1306 			zbx_variant_set_ui64(&value, left->data.ui64 ^ right->data.ui64);
1307 			break;
1308 		case FUNCTION_OPTYPE_BIT_LSHIFT:
1309 			zbx_variant_set_ui64(&value, left->data.ui64 << right->data.ui64);
1310 			break;
1311 		case FUNCTION_OPTYPE_BIT_RSHIFT:
1312 			zbx_variant_set_ui64(&value, left->data.ui64 >> right->data.ui64);
1313 	}
1314 
1315 	eval_function_return(2, &value, output);
1316 
1317 	return SUCCEED;
1318 }
1319 
1320 /******************************************************************************
1321  *                                                                            *
1322  * Function: eval_execute_function_bitnot                                     *
1323  *                                                                            *
1324  * Purpose: evaluate bitnot() function                                        *
1325  *                                                                            *
1326  * Parameters: ctx    - [IN] the evaluation context                           *
1327  *             token  - [IN] the function token                               *
1328  *             output - [IN/OUT] the output value stack                       *
1329  *             error  - [OUT] the error message in the case of failure        *
1330  *                                                                            *
1331  * Return value: SUCCEED - function evaluation succeeded                      *
1332  *               FAIL    - otherwise                                          *
1333  *                                                                            *
1334  ******************************************************************************/
eval_execute_function_bitnot(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1335 static int	eval_execute_function_bitnot(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1336 		zbx_vector_var_t *output, char **error)
1337 {
1338 	zbx_variant_t	value, *arg;
1339 	int		ret;
1340 
1341 	if (1 != token->opt)
1342 	{
1343 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1344 				ctx->expression + token->loc.l);
1345 		return FAIL;
1346 	}
1347 
1348 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1349 		return ret;
1350 
1351 	arg = &output->values[output->values_num - 1];
1352 
1353 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, arg, error))
1354 		return FAIL;
1355 
1356 	zbx_variant_set_ui64(&value, ~arg->data.ui64);
1357 	eval_function_return(1, &value, output);
1358 
1359 	return SUCCEED;
1360 }
1361 
1362 /******************************************************************************
1363  *                                                                            *
1364  * Function: eval_execute_function_left                                       *
1365  *                                                                            *
1366  * Purpose: evaluate left() function                                          *
1367  *                                                                            *
1368  * Parameters: ctx    - [IN] the evaluation context                           *
1369  *             token  - [IN] the function token                               *
1370  *             output - [IN/OUT] the output value stack                       *
1371  *             error  - [OUT] the error message in the case of failure        *
1372  *                                                                            *
1373  * Return value: SUCCEED - function evaluation succeeded                      *
1374  *               FAIL    - otherwise                                          *
1375  *                                                                            *
1376  ******************************************************************************/
eval_execute_function_left(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1377 static int	eval_execute_function_left(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1378 		zbx_vector_var_t *output, char **error)
1379 {
1380 	int		ret;
1381 	zbx_variant_t	*arg, *len, value;
1382 	size_t		sz;
1383 	char		*strval;
1384 
1385 	if (2 != token->opt)
1386 	{
1387 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1388 				ctx->expression + token->loc.l);
1389 		return FAIL;
1390 	}
1391 
1392 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1393 		return ret;
1394 
1395 	arg = &output->values[output->values_num - 2];
1396 	len = &output->values[output->values_num - 1];
1397 
1398 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) ||
1399 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error))
1400 	{
1401 		return FAIL;
1402 	}
1403 
1404 	sz = zbx_strlen_utf8_nchars(arg->data.str, (size_t)len->data.ui64) + 1;
1405 	strval = zbx_malloc(NULL, sz);
1406 	zbx_strlcpy_utf8(strval, arg->data.str, sz);
1407 
1408 	zbx_variant_set_str(&value, strval);
1409 	eval_function_return(2, &value, output);
1410 
1411 	return SUCCEED;
1412 }
1413 
eval_validate_statistical_function_args(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1414 static int	eval_validate_statistical_function_args(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1415 		zbx_vector_var_t *output, char **error)
1416 {
1417 	int	i, ret;
1418 
1419 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1420 		return ret;
1421 
1422 	if (1 != token->opt)
1423 	{
1424 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1425 				ctx->expression + token->loc.l);
1426 		return FAIL;
1427 	}
1428 
1429 	i = output->values_num - 1;
1430 
1431 	if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type)
1432 	{
1433 		*error = zbx_dsprintf(*error, "invalid argument type \"%s\" for function at \"%s\"",
1434 				zbx_variant_type_desc(&output->values[i]), ctx->expression + token->loc.l);
1435 		return FAIL;
1436 	}
1437 
1438 	if (0 == output->values[i].data.dbl_vector->values_num)
1439 	{
1440 		*error = zbx_dsprintf(*error, "empty vector argument for function at \"%s\"",
1441 				ctx->expression + token->loc.l);
1442 		return FAIL;
1443 	}
1444 
1445 	return UNKNOWN;
1446 }
1447 
1448 /******************************************************************************
1449  *                                                                            *
1450  * Function: eval_execute_statistical_function                                *
1451  *                                                                            *
1452  * Purpose: common operations for aggregate function calculation              *
1453  *                                                                            *
1454  * Parameters: ctx       - [IN] the evaluation context                        *
1455  *             token     - [IN] the function token                            *
1456  *             stat_func - [IN] pointer to aggregate function to be called    *
1457  *             output    - [IN/OUT] the output value stack                    *
1458  *             error     - [OUT] the error message in the case of failure     *
1459  *                                                                            *
1460  * Return value: SUCCEED - function evaluation succeeded                      *
1461  *               FAIL    - otherwise                                          *
1462  *                                                                            *
1463  ******************************************************************************/
eval_execute_statistical_function(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_statistical_func_t stat_func,zbx_vector_var_t * output,char ** error)1464 static int	eval_execute_statistical_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1465 		zbx_statistical_func_t stat_func, zbx_vector_var_t *output, char **error)
1466 {
1467 	int			ret;
1468 	double			result;
1469 	zbx_variant_t		value;
1470 	zbx_vector_dbl_t	*dbl_vector;
1471 
1472 	if (UNKNOWN != (ret = eval_validate_statistical_function_args(ctx, token, output, error)))
1473 		return ret;
1474 
1475 	dbl_vector = output->values[output->values_num - (int)token->opt].data.dbl_vector;
1476 
1477 	if (FAIL == stat_func(dbl_vector, &result, error))
1478 		return FAIL;
1479 
1480 	zbx_variant_set_dbl(&value, result);
1481 	eval_function_return((int)token->opt, &value, output);
1482 
1483 	return SUCCEED;
1484 }
1485 
1486 /******************************************************************************
1487  *                                                                            *
1488  * Function: eval_execute_function_right                                      *
1489  *                                                                            *
1490  * Purpose: evaluate right() function                                         *
1491  *                                                                            *
1492  * Parameters: ctx    - [IN] the evaluation context                           *
1493  *             token  - [IN] the function token                               *
1494  *             output - [IN/OUT] the output value stack                       *
1495  *             error  - [OUT] the error message in the case of failure        *
1496  *                                                                            *
1497  * Return value: SUCCEED - function evaluation succeeded                      *
1498  *               FAIL    - otherwise                                          *
1499  *                                                                            *
1500  ******************************************************************************/
eval_execute_function_right(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1501 static int	eval_execute_function_right(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1502 		zbx_vector_var_t *output, char **error)
1503 {
1504 	int		ret;
1505 	zbx_variant_t	*arg, *len, value;
1506 	size_t		sz, srclen;
1507 	char		*strval, *p;
1508 
1509 	if (2 != token->opt)
1510 	{
1511 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1512 				ctx->expression + token->loc.l);
1513 		return FAIL;
1514 	}
1515 
1516 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1517 		return ret;
1518 
1519 	arg = &output->values[output->values_num - 2];
1520 	len = &output->values[output->values_num - 1];
1521 
1522 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) ||
1523 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error))
1524 	{
1525 		return FAIL;
1526 	}
1527 
1528 	srclen = zbx_strlen_utf8(arg->data.str);
1529 
1530 	if (len->data.ui64 < srclen)
1531 	{
1532 		p = zbx_strshift_utf8(arg->data.str, srclen - len->data.ui64);
1533 		sz = zbx_strlen_utf8_nchars(p, (size_t)len->data.ui64) + 1;
1534 		strval = zbx_malloc(NULL, sz);
1535 		zbx_strlcpy_utf8(strval, p, sz);
1536 	}
1537 	else
1538 		strval = zbx_strdup(NULL, arg->data.str);
1539 
1540 	zbx_variant_set_str(&value, strval);
1541 	eval_function_return(2, &value, output);
1542 
1543 	return SUCCEED;
1544 }
1545 
1546 /******************************************************************************
1547  *                                                                            *
1548  * Function: eval_execute_function_mid                                        *
1549  *                                                                            *
1550  * Purpose: evaluate mid() function                                           *
1551  *                                                                            *
1552  * Parameters: ctx    - [IN] the evaluation context                           *
1553  *             token  - [IN] the function token                               *
1554  *             output - [IN/OUT] the output value stack                       *
1555  *             error  - [OUT] the error message in the case of failure        *
1556  *                                                                            *
1557  * Return value: SUCCEED - function evaluation succeeded                      *
1558  *               FAIL    - otherwise                                          *
1559  *                                                                            *
1560  ******************************************************************************/
eval_execute_function_mid(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1561 static int	eval_execute_function_mid(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1562 		zbx_vector_var_t *output, char **error)
1563 {
1564 	int		ret;
1565 	zbx_variant_t	*arg, *start, *len, value;
1566 	size_t		sz, srclen;
1567 	char		*strval, *p;
1568 
1569 	if (3 != token->opt)
1570 	{
1571 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1572 				ctx->expression + token->loc.l);
1573 		return FAIL;
1574 	}
1575 
1576 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1577 		return ret;
1578 
1579 	arg = &output->values[output->values_num - 3];
1580 	start = &output->values[output->values_num - 2];
1581 	len = &output->values[output->values_num - 1];
1582 
1583 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) ||
1584 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, start, error) ||
1585 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error))
1586 	{
1587 		return FAIL;
1588 	}
1589 
1590 	srclen = zbx_strlen_utf8(arg->data.str);
1591 
1592 	if (0 == start->data.ui64 || start->data.ui64 > srclen)
1593 	{
1594 		*error = zbx_dsprintf(*error, "invalid function second argument at \"%s\"",
1595 				ctx->expression + token->loc.l);
1596 		return FAIL;
1597 	}
1598 
1599 	p = zbx_strshift_utf8(arg->data.str, start->data.ui64 - 1);
1600 
1601 	if (srclen >= start->data.ui64 + len->data.ui64)
1602 	{
1603 		sz = zbx_strlen_utf8_nchars(p, len->data.ui64) + 1;
1604 		strval = zbx_malloc(NULL, sz);
1605 		zbx_strlcpy_utf8(strval, p, sz);
1606 	}
1607 	else
1608 		strval = zbx_strdup(NULL, p);
1609 
1610 	zbx_variant_set_str(&value, strval);
1611 	eval_function_return(3, &value, output);
1612 
1613 	return SUCCEED;
1614 }
1615 
1616 /******************************************************************************
1617  *                                                                            *
1618  * Function: eval_execute_function_trim                                       *
1619  *                                                                            *
1620  * Purpose: evaluate trim(), rtrim(), ltrim() functions                       *
1621  *                                                                            *
1622  * Parameters: ctx    - [IN] the evaluation context                           *
1623  *             token  - [IN] the function token                               *
1624  *             type   - [IN] the function type                                *
1625  *             output - [IN/OUT] the output value stack                       *
1626  *             error  - [OUT] the error message in the case of failure        *
1627  *                                                                            *
1628  * Return value: SUCCEED - function evaluation succeeded                      *
1629  *               FAIL    - otherwise                                          *
1630  *                                                                            *
1631  ******************************************************************************/
eval_execute_function_trim(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_function_trim_optype_t type,zbx_vector_var_t * output,char ** error)1632 static int	eval_execute_function_trim(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1633 		zbx_function_trim_optype_t type, zbx_vector_var_t *output, char **error)
1634 {
1635 	int		ret;
1636 	zbx_variant_t	*sym, *arg, value, sym_val;
1637 
1638 	if (1 > token->opt || 2 < token->opt)
1639 	{
1640 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1641 				ctx->expression + token->loc.l);
1642 		return FAIL;
1643 	}
1644 
1645 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1646 		return ret;
1647 
1648 	if (2 == token->opt)
1649 	{
1650 		arg = &output->values[output->values_num - 2];
1651 		sym = &output->values[output->values_num - 1];
1652 
1653 		if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, sym, error))
1654 			return FAIL;
1655 	}
1656 	else
1657 	{
1658 		arg = &output->values[output->values_num - 1];
1659 		zbx_variant_set_str(&sym_val, zbx_strdup(NULL, ZBX_WHITESPACE));
1660 		sym = &sym_val;
1661 	}
1662 
1663 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error))
1664 		return FAIL;
1665 
1666 	switch (type)
1667 	{
1668 		case FUNCTION_OPTYPE_TRIM_ALL:
1669 			zbx_ltrim_utf8(arg->data.str, sym->data.str);
1670 			zbx_rtrim_utf8(arg->data.str, sym->data.str);
1671 			break;
1672 		case FUNCTION_OPTYPE_TRIM_RIGHT:
1673 			zbx_rtrim_utf8(arg->data.str, sym->data.str);
1674 			break;
1675 		case FUNCTION_OPTYPE_TRIM_LEFT:
1676 			zbx_ltrim_utf8(arg->data.str, sym->data.str);
1677 			break;
1678 	}
1679 
1680 	if (2 != token->opt)
1681 		zbx_variant_clear(&sym_val);
1682 
1683 	zbx_variant_set_str(&value, zbx_strdup(NULL, arg->data.str));
1684 	eval_function_return(token->opt, &value, output);
1685 
1686 	return SUCCEED;
1687 }
1688 
1689 /******************************************************************************
1690  *                                                                            *
1691  * Function: eval_execute_function_concat                                     *
1692  *                                                                            *
1693  * Purpose: evaluate concat() function                                        *
1694  *                                                                            *
1695  * Parameters: ctx    - [IN] the evaluation context                           *
1696  *             token  - [IN] the function token                               *
1697  *             output - [IN/OUT] the output value stack                       *
1698  *             error  - [OUT] the error message in the case of failure        *
1699  *                                                                            *
1700  * Return value: SUCCEED - function evaluation succeeded                      *
1701  *               FAIL    - otherwise                                          *
1702  *                                                                            *
1703  ******************************************************************************/
eval_execute_function_concat(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1704 static int	eval_execute_function_concat(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1705 		zbx_vector_var_t *output, char **error)
1706 {
1707 	int		ret;
1708 	zbx_variant_t	*str1, *str2, value;
1709 	char		*strval;
1710 
1711 	if (2 != token->opt)
1712 	{
1713 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1714 				ctx->expression + token->loc.l);
1715 		return FAIL;
1716 	}
1717 
1718 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1719 		return ret;
1720 
1721 	str1 = &output->values[output->values_num - 2];
1722 	str2 = &output->values[output->values_num - 1];
1723 
1724 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str1, error) ||
1725 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str2, error))
1726 	{
1727 		return FAIL;
1728 	}
1729 
1730 	strval = zbx_strdup(NULL, str1->data.str);
1731 	zbx_variant_set_str(&value, zbx_strdcat(strval, str2->data.str));
1732 	eval_function_return(2, &value, output);
1733 
1734 	return SUCCEED;
1735 }
1736 
1737 /******************************************************************************
1738  *                                                                            *
1739  * Function: eval_execute_function_insert                                     *
1740  *                                                                            *
1741  * Purpose: evaluate insert() function                                        *
1742  *                                                                            *
1743  * Parameters: ctx    - [IN] the evaluation context                           *
1744  *             token  - [IN] the function token                               *
1745  *             output - [IN/OUT] the output value stack                       *
1746  *             error  - [OUT] the error message in the case of failure        *
1747  *                                                                            *
1748  * Return value: SUCCEED - function evaluation succeeded                      *
1749  *               FAIL    - otherwise                                          *
1750  *                                                                            *
1751  ******************************************************************************/
eval_execute_function_insert(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1752 static int	eval_execute_function_insert(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1753 		zbx_vector_var_t *output, char **error)
1754 {
1755 	int		ret;
1756 	zbx_variant_t	*arg, *start, *len, *replacement, value;
1757 	char		*strval, *p;
1758 	size_t		str_alloc, str_len, sz, src_len;
1759 
1760 	if (4 != token->opt)
1761 	{
1762 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1763 				ctx->expression + token->loc.l);
1764 		return FAIL;
1765 	}
1766 
1767 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1768 		return ret;
1769 
1770 	arg = &output->values[output->values_num - 4];
1771 	start = &output->values[output->values_num - 3];
1772 	len = &output->values[output->values_num - 2];
1773 	replacement = &output->values[output->values_num - 1];
1774 
1775 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) ||
1776 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, start, error) ||
1777 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error) ||
1778 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, replacement, error))
1779 	{
1780 		return FAIL;
1781 	}
1782 
1783 	src_len = zbx_strlen_utf8(arg->data.str);
1784 
1785 	if (0 == start->data.ui64 || start->data.ui64 > src_len)
1786 	{
1787 		*error = zbx_dsprintf(*error, "invalid function second argument at \"%s\"",
1788 				ctx->expression + token->loc.l);
1789 		return FAIL;
1790 	}
1791 
1792 	if (src_len < start->data.ui64 - 1 + len->data.ui64)
1793 	{
1794 		*error = zbx_dsprintf(*error, "invalid function third argument at \"%s\"",
1795 				ctx->expression + token->loc.l);
1796 		return FAIL;
1797 	}
1798 
1799 	strval = zbx_strdup(NULL, arg->data.str);
1800 	p = zbx_strshift_utf8(strval, start->data.ui64 - 1);
1801 	sz = zbx_strlen_utf8_nchars(p, len->data.ui64);
1802 
1803 	str_alloc = str_len = strlen(strval) + 1;
1804 	zbx_replace_mem_dyn(&strval, &str_alloc, &str_len, (size_t)(p - strval), sz, replacement->data.str,
1805 			strlen(replacement->data.str));
1806 
1807 	zbx_variant_set_str(&value, strval);
1808 	eval_function_return(4, &value, output);
1809 
1810 	return SUCCEED;
1811 }
1812 
1813 /******************************************************************************
1814  *                                                                            *
1815  * Function: eval_execute_function_replace                                    *
1816  *                                                                            *
1817  * Purpose: evaluate replace() function                                       *
1818  *                                                                            *
1819  * Parameters: ctx    - [IN] the evaluation context                           *
1820  *             token  - [IN] the function token                               *
1821  *             output - [IN/OUT] the output value stack                       *
1822  *             error  - [OUT] the error message in the case of failure        *
1823  *                                                                            *
1824  * Return value: SUCCEED - function evaluation succeeded                      *
1825  *               FAIL    - otherwise                                          *
1826  *                                                                            *
1827  ******************************************************************************/
eval_execute_function_replace(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1828 static int	eval_execute_function_replace(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1829 		zbx_vector_var_t *output, char **error)
1830 {
1831 	int		ret;
1832 	zbx_variant_t	*arg, *pattern, *replacement, value;
1833 	char		*strval, *p;
1834 	size_t		pattern_len, replacement_len;
1835 
1836 	if (3 != token->opt)
1837 	{
1838 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1839 				ctx->expression + token->loc.l);
1840 		return FAIL;
1841 	}
1842 
1843 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1844 		return ret;
1845 
1846 	arg = &output->values[output->values_num - 3];
1847 	pattern = &output->values[output->values_num - 2];
1848 	replacement = &output->values[output->values_num - 1];
1849 
1850 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) ||
1851 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, pattern, error) ||
1852 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, replacement, error))
1853 	{
1854 		return FAIL;
1855 	}
1856 
1857 	strval = zbx_strdup(NULL, arg->data.str);
1858 	pattern_len = strlen(pattern->data.str);
1859 
1860 	if (0 < pattern_len)
1861 	{
1862 		replacement_len = strlen(replacement->data.str);
1863 
1864 		while (NULL != (p = strstr(strval, pattern->data.str)))
1865 		{
1866 			size_t	str_alloc, str_len;
1867 
1868 			str_alloc = str_len = strlen(strval) + 1;
1869 			zbx_replace_mem_dyn(&strval, &str_alloc, &str_len, (size_t)(p - strval), pattern_len,
1870 					replacement->data.str, replacement_len);
1871 		}
1872 	}
1873 
1874 	zbx_variant_set_str(&value, strval);
1875 	eval_function_return(3, &value, output);
1876 
1877 	return SUCCEED;
1878 }
1879 
1880 /******************************************************************************
1881  *                                                                            *
1882  * Function: eval_execute_function_repeat                                     *
1883  *                                                                            *
1884  * Purpose: evaluate repeat() function                                        *
1885  *                                                                            *
1886  * Parameters: ctx    - [IN] the evaluation context                           *
1887  *             token  - [IN] the function token                               *
1888  *             output - [IN/OUT] the output value stack                       *
1889  *             error  - [OUT] the error message in the case of failure        *
1890  *                                                                            *
1891  * Return value: SUCCEED - function evaluation succeeded                      *
1892  *               FAIL    - otherwise                                          *
1893  *                                                                            *
1894  ******************************************************************************/
eval_execute_function_repeat(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1895 static int	eval_execute_function_repeat(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1896 		zbx_vector_var_t *output, char **error)
1897 {
1898 	int		ret;
1899 	zbx_variant_t	*str, *num, value;
1900 	char		*strval = NULL;
1901 	zbx_uint64_t	i;
1902 	size_t		len_utf8;
1903 
1904 	if (2 != token->opt)
1905 	{
1906 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1907 				ctx->expression + token->loc.l);
1908 		return FAIL;
1909 	}
1910 
1911 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1912 		return ret;
1913 
1914 	str = &output->values[output->values_num - 2];
1915 	num = &output->values[output->values_num - 1];
1916 
1917 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str, error) ||
1918 			SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, num, error))
1919 	{
1920 		return FAIL;
1921 	}
1922 
1923 	len_utf8 = zbx_strlen_utf8(str->data.str);
1924 
1925 	if (num->data.ui64 * len_utf8 >= MAX_STRING_LEN)
1926 	{
1927 		*error = zbx_dsprintf(*error, "maximum allowed string length (%d) exceeded: " ZBX_FS_UI64,
1928 				MAX_STRING_LEN, num->data.ui64 * len_utf8);
1929 		return FAIL;
1930 	}
1931 
1932 	for (i = num->data.ui64; i > 0; i--)
1933 		strval = zbx_strdcat(strval, str->data.str);
1934 
1935 	if (NULL == strval)
1936 		strval = zbx_strdup(NULL, "");
1937 
1938 	zbx_variant_set_str(&value, strval);
1939 	eval_function_return(2, &value, output);
1940 
1941 	return SUCCEED;
1942 }
1943 
1944 /******************************************************************************
1945  *                                                                            *
1946  * Function: eval_execute_function_bytelength                                 *
1947  *                                                                            *
1948  * Purpose: evaluate bytelength() function                                    *
1949  *                                                                            *
1950  * Parameters: ctx    - [IN] the evaluation context                           *
1951  *             token  - [IN] the function token                               *
1952  *             output - [IN/OUT] the output value stack                       *
1953  *             error  - [OUT] the error message in the case of failure        *
1954  *                                                                            *
1955  * Return value: SUCCEED - function evaluation succeeded                      *
1956  *               FAIL    - otherwise                                          *
1957  *                                                                            *
1958  ******************************************************************************/
eval_execute_function_bytelength(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)1959 static int	eval_execute_function_bytelength(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
1960 		zbx_vector_var_t *output, char **error)
1961 {
1962 	int		ret;
1963 	zbx_variant_t	*arg, value;
1964 
1965 	if (1 != token->opt)
1966 	{
1967 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
1968 				ctx->expression + token->loc.l);
1969 		return FAIL;
1970 	}
1971 
1972 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
1973 		return ret;
1974 
1975 	arg = &output->values[output->values_num - 1];
1976 
1977 	if (SUCCEED == zbx_variant_convert(arg, ZBX_VARIANT_UI64))
1978 	{
1979 		zbx_uint64_t	byte = __UINT64_C(0xFF00000000000000);
1980 		int		i;
1981 
1982 		for (i = 8; i > 0; i--)
1983 		{
1984 			if (byte & arg->data.ui64)
1985 				break;
1986 
1987 			byte = byte >> 8;
1988 		}
1989 
1990 		zbx_variant_set_dbl(&value, i);
1991 	}
1992 	else if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR))
1993 	{
1994 		*error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l);
1995 		return FAIL;
1996 	}
1997 	else
1998 		zbx_variant_set_dbl(&value, strlen(arg->data.str));
1999 
2000 	eval_function_return(1, &value, output);
2001 
2002 	return SUCCEED;
2003 }
2004 
2005 /******************************************************************************
2006  *                                                                            *
2007  * Function: eval_execute_function_bitlength                                  *
2008  *                                                                            *
2009  * Purpose: evaluate bitlength() function                                     *
2010  *                                                                            *
2011  * Parameters: ctx    - [IN] the evaluation context                           *
2012  *             token  - [IN] the function token                               *
2013  *             output - [IN/OUT] the output value stack                       *
2014  *             error  - [OUT] the error message in the case of failure        *
2015  *                                                                            *
2016  * Return value: SUCCEED - function evaluation succeeded                      *
2017  *               FAIL    - otherwise                                          *
2018  *                                                                            *
2019  ******************************************************************************/
eval_execute_function_bitlength(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2020 static int	eval_execute_function_bitlength(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2021 		zbx_vector_var_t *output, char **error)
2022 {
2023 	int		ret;
2024 	zbx_variant_t	*arg, value;
2025 
2026 	if (1 != token->opt)
2027 	{
2028 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2029 				ctx->expression + token->loc.l);
2030 		return FAIL;
2031 	}
2032 
2033 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
2034 		return ret;
2035 
2036 	arg = &output->values[output->values_num - 1];
2037 
2038 	if (SUCCEED == zbx_variant_convert(arg, ZBX_VARIANT_UI64))
2039 	{
2040 		int	i, bits;
2041 
2042 		bits = sizeof(uint64_t) * 8;
2043 
2044 		for (i = bits - 1; i >= 0; i--)
2045 		{
2046 			if (__UINT64_C(1) << i & arg->data.ui64)
2047 				break;
2048 		}
2049 
2050 		zbx_variant_set_dbl(&value, ++i);
2051 	}
2052 	else if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR))
2053 	{
2054 		*error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l);
2055 		return FAIL;
2056 	}
2057 	else
2058 		zbx_variant_set_dbl(&value, strlen(arg->data.str) * 8);
2059 
2060 	eval_function_return(1, &value, output);
2061 
2062 	return SUCCEED;
2063 }
2064 
2065 /******************************************************************************
2066  *                                                                            *
2067  * Function: eval_execute_function_char                                       *
2068  *                                                                            *
2069  * Purpose: evaluate char() function                                          *
2070  *                                                                            *
2071  * Parameters: ctx    - [IN] the evaluation context                           *
2072  *             token  - [IN] the function token                               *
2073  *             output - [IN/OUT] the output value stack                       *
2074  *             error  - [OUT] the error message in the case of failure        *
2075  *                                                                            *
2076  * Return value: SUCCEED - function evaluation succeeded                      *
2077  *               FAIL    - otherwise                                          *
2078  *                                                                            *
2079  ******************************************************************************/
eval_execute_function_char(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2080 static int	eval_execute_function_char(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2081 		zbx_vector_var_t *output, char **error)
2082 {
2083 	int		ret;
2084 	zbx_variant_t	*arg, value;
2085 
2086 	if (1 != token->opt)
2087 	{
2088 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2089 				ctx->expression + token->loc.l);
2090 		return FAIL;
2091 	}
2092 
2093 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
2094 		return ret;
2095 
2096 	arg = &output->values[output->values_num - 1];
2097 
2098 	if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, arg, error))
2099 		return FAIL;
2100 
2101 	if (255 < arg->data.ui64)
2102 	{
2103 		*error = zbx_dsprintf(*error, "function argument \"%s\" is out of allowed range at \"%s\"",
2104 				zbx_variant_value_desc(arg), ctx->expression + token->loc.l);
2105 		return FAIL;
2106 	}
2107 
2108 	zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%c", (char)arg->data.ui64));
2109 	eval_function_return(1, &value, output);
2110 
2111 	return SUCCEED;
2112 }
2113 
2114 /******************************************************************************
2115  *                                                                            *
2116  * Function: eval_execute_function_ascii                                      *
2117  *                                                                            *
2118  * Purpose: evaluate ascii() function                                         *
2119  *                                                                            *
2120  * Parameters: ctx    - [IN] the evaluation context                           *
2121  *             token  - [IN] the function token                               *
2122  *             output - [IN/OUT] the output value stack                       *
2123  *             error  - [OUT] the error message in the case of failure        *
2124  *                                                                            *
2125  * Return value: SUCCEED - function evaluation succeeded                      *
2126  *               FAIL    - otherwise                                          *
2127  *                                                                            *
2128  ******************************************************************************/
eval_execute_function_ascii(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2129 static int	eval_execute_function_ascii(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2130 		zbx_vector_var_t *output, char **error)
2131 {
2132 	int		ret;
2133 	zbx_variant_t	*arg, value;
2134 
2135 	if (1 != token->opt)
2136 	{
2137 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2138 				ctx->expression + token->loc.l);
2139 		return FAIL;
2140 	}
2141 
2142 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
2143 		return ret;
2144 
2145 	arg = &output->values[output->values_num - 1];
2146 
2147 	if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR) || 0 > *arg->data.str)
2148 	{
2149 		*error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l);
2150 		return FAIL;
2151 	}
2152 
2153 	zbx_variant_set_ui64(&value, (zbx_uint64_t)*arg->data.str);
2154 	eval_function_return(1, &value, output);
2155 
2156 	return SUCCEED;
2157 }
2158 
2159 /******************************************************************************
2160  *                                                                            *
2161  * Function: eval_execute_function_between                                    *
2162  *                                                                            *
2163  * Purpose: evaluate between() function                                       *
2164  *                                                                            *
2165  * Parameters: ctx    - [IN] the evaluation context                           *
2166  *             token  - [IN] the function token                               *
2167  *             output - [IN/OUT] the output value stack                       *
2168  *             error  - [OUT] the error message in the case of failure        *
2169  *                                                                            *
2170  * Return value: SUCCEED - function evaluation succeeded                      *
2171  *               FAIL    - otherwise                                          *
2172  *                                                                            *
2173  ******************************************************************************/
eval_execute_function_between(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2174 static int	eval_execute_function_between(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2175 		zbx_vector_var_t *output, char **error)
2176 {
2177 	int		i, ret;
2178 	double		between;
2179 	zbx_variant_t	value;
2180 
2181 	if (3 != token->opt)
2182 	{
2183 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2184 				ctx->expression + token->loc.l);
2185 		return FAIL;
2186 	}
2187 
2188 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
2189 		return ret;
2190 
2191 	i = output->values_num - token->opt;
2192 	between = output->values[i++].data.dbl;
2193 
2194 	if (output->values[i++].data.dbl <= between && between <= output->values[i].data.dbl)
2195 		zbx_variant_set_dbl(&value, 1);
2196 	else
2197 		zbx_variant_set_dbl(&value, 0);
2198 
2199 	eval_function_return(3, &value, output);
2200 
2201 	return SUCCEED;
2202 }
2203 
2204 /******************************************************************************
2205  *                                                                            *
2206  * Function: eval_execute_function_in                                         *
2207  *                                                                            *
2208  * Purpose: evaluate in() function                                            *
2209  *                                                                            *
2210  * Parameters: ctx    - [IN] the evaluation context                           *
2211  *             token  - [IN] the function token                               *
2212  *             output - [IN/OUT] the output value stack                       *
2213  *             error  - [OUT] the error message in the case of failure        *
2214  *                                                                            *
2215  * Return value: SUCCEED - function evaluation succeeded                      *
2216  *               FAIL    - otherwise                                          *
2217  *                                                                            *
2218  ******************************************************************************/
eval_execute_function_in(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2219 static int	eval_execute_function_in(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2220 		zbx_vector_var_t *output, char **error)
2221 {
2222 	int		i, arg_idx, found = 0, ret;
2223 	zbx_variant_t	value, *arg, *ref_str = NULL;
2224 	double		ref = 0;
2225 
2226 	if (2 > token->opt)
2227 	{
2228 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2229 				ctx->expression + token->loc.l);
2230 		return FAIL;
2231 	}
2232 
2233 	if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error)))
2234 		return ret;
2235 
2236 	zbx_variant_set_dbl(&value, 0);
2237 
2238 	for (i = arg_idx = output->values_num - token->opt; i < output->values_num; i++)
2239 	{
2240 		zbx_variant_t	val_copy;
2241 
2242 		if (SUCCEED != variant_convert_suffixed_num(&val_copy, &output->values[i]))
2243 		{
2244 			zbx_variant_copy(&val_copy, &output->values[i]);
2245 
2246 			if (SUCCEED != zbx_variant_convert(&val_copy, ZBX_VARIANT_DBL))
2247 			{
2248 				zbx_variant_clear(&val_copy);
2249 				break;
2250 			}
2251 		}
2252 
2253 		if (i == arg_idx)
2254 		{
2255 			ref = val_copy.data.dbl;
2256 			continue;
2257 		}
2258 
2259 		if (0 == found && SUCCEED == zbx_double_compare(ref, val_copy.data.dbl))
2260 			found = 1;
2261 	}
2262 
2263 	if (i == output->values_num)
2264 	{
2265 		if (1 == found)
2266 			zbx_variant_set_dbl(&value, 1);
2267 
2268 		goto out;
2269 	}
2270 
2271 	for (i = arg_idx; i < output->values_num; i++)
2272 	{
2273 		arg = &output->values[i];
2274 
2275 		if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error))
2276 			return FAIL;
2277 
2278 		if (i == arg_idx)
2279 		{
2280 			ref_str = arg;
2281 			continue;
2282 		}
2283 
2284 		if (0 == strcmp(ref_str->data.str, arg->data.str))
2285 		{
2286 			zbx_variant_set_dbl(&value, 1);
2287 			break;
2288 		}
2289 	}
2290 out:
2291 	eval_function_return(token->opt, &value, output);
2292 
2293 	return SUCCEED;
2294 }
2295 
2296 /******************************************************************************
2297  *                                                                            *
2298  * Function: eval_execute_cb_function                                         *
2299  *                                                                            *
2300  * Purpose: evaluate function by calling custom callback (if configured)      *
2301  *                                                                            *
2302  * Parameters: ctx         - [IN] the evaluation context                      *
2303  *             token       - [IN] the function token                          *
2304  *             function_cb - [IN] the callback function                       *
2305  *             output      - [IN/OUT] the output value stack                  *
2306  *             error       - [OUT] the error message in the case of failure   *
2307  *                                                                            *
2308  * Return value: SUCCEED - the function was executed successfully             *
2309  *               FAIL    - otherwise                                          *
2310  *                                                                            *
2311  ******************************************************************************/
eval_execute_cb_function(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_eval_function_cb_t function_cb,zbx_vector_var_t * output,char ** error)2312 static int	eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2313 		zbx_eval_function_cb_t function_cb, zbx_vector_var_t *output, char **error)
2314 {
2315 	zbx_variant_t	value, *args;
2316 	char		*errmsg = NULL;
2317 
2318 	args = (0 == token->opt ? NULL : &output->values[output->values_num - token->opt]);
2319 
2320 	if (SUCCEED != function_cb(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1,
2321 			token->opt, args, ctx->data_cb, &ctx->ts, &value, &errmsg))
2322 	{
2323 		*error = zbx_dsprintf(*error, "%s at \"%s\".", errmsg, ctx->expression + token->loc.l);
2324 		zbx_free(errmsg);
2325 
2326 		if (0 == (ctx->rules & ZBX_EVAL_PROCESS_ERROR))
2327 			return FAIL;
2328 
2329 		zbx_variant_set_error(&value, *error);
2330 		*error = NULL;
2331 	}
2332 
2333 	eval_function_return(token->opt, &value, output);
2334 
2335 	return SUCCEED;
2336 }
2337 
2338 #define ZBX_MATH_CONST_PI	3.141592653589793238463
2339 #define ZBX_MATH_CONST_E	2.7182818284590452354
2340 #define ZBX_MATH_RANDOM		0
2341 
eval_math_func_degrees(double radians)2342 static double	eval_math_func_degrees(double radians)
2343 {
2344 	return radians * (180.0 / ZBX_MATH_CONST_PI);
2345 }
2346 
eval_math_func_radians(double degrees)2347 static double	eval_math_func_radians(double degrees)
2348 {
2349 	return degrees * (ZBX_MATH_CONST_PI / 180);
2350 }
2351 
eval_math_func_cot(double x)2352 static double	eval_math_func_cot(double x)
2353 {
2354 	return cos(x) / sin(x);
2355 }
2356 
eval_math_func_signum(double x)2357 static double	eval_math_func_signum(double x)
2358 {
2359 	if (0 > x)
2360 		return -1;
2361 
2362 	if (0 == x)
2363 		return 0;
2364 
2365 	return 1;
2366 }
2367 
2368 /******************************************************************************
2369  *                                                                            *
2370  * Function: eval_execute_math_function_single_param                          *
2371  *                                                                            *
2372  * Purpose: evaluate mathematical function by calling passed function         *
2373  *          with 1 double argument                                            *
2374  *                                                                            *
2375  * Parameters: ctx        - [IN] the evaluation context                       *
2376  *             token      - [IN] the function token                           *
2377  *             output     - [IN/OUT] the output value stack                   *
2378  *             error      - [OUT] the error message in the case of failure    *
2379  *             func       - [IN] the pointer to math function                 *
2380  *                                                                            *
2381  * Return value: SUCCEED - function evaluation succeeded                      *
2382  *               FAIL    - otherwise                                          *
2383  *                                                                            *
2384  ******************************************************************************/
eval_execute_math_function_single_param(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error,double (* func)(double))2385 static int	eval_execute_math_function_single_param(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2386 		zbx_vector_var_t *output, char **error, double (*func)(double))
2387 {
2388 	int		ret;
2389 	double		result;
2390 	zbx_variant_t	*arg, value;
2391 
2392 	if (1 != token->opt)
2393 	{
2394 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2395 				ctx->expression + token->loc.l);
2396 		return FAIL;
2397 	}
2398 
2399 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
2400 		return ret;
2401 
2402 	arg = &output->values[output->values_num - 1];
2403 
2404 	if (((log == func || log10 == func) && 0 >= arg->data.dbl) || (sqrt == func && 0 > arg->data.dbl) ||
2405 			(eval_math_func_cot == func && 0 == arg->data.dbl))
2406 	{
2407 		*error = zbx_dsprintf(*error, "invalid argument for function at \"%s\"",
2408 				ctx->expression + token->loc.l);
2409 
2410 		return FAIL;
2411 	}
2412 
2413 	result = func(arg->data.dbl);
2414 
2415 	if (FP_ZERO != fpclassify(result) && FP_NORMAL != fpclassify(result))
2416 	{
2417 		*error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"",
2418 				ctx->expression + token->loc.l);
2419 		return FAIL;
2420 	}
2421 
2422 	zbx_variant_set_dbl(&value, result);
2423 
2424 	eval_function_return(token->opt, &value, output);
2425 
2426 	return SUCCEED;
2427 }
2428 
eval_math_func_round(double n,double decimal_points)2429 static double	eval_math_func_round(double n, double decimal_points)
2430 {
2431 	double	multiplier;
2432 
2433 	multiplier = pow(10.0, decimal_points);
2434 
2435 	return round(n * multiplier ) / multiplier;
2436 }
2437 
eval_math_func_truncate(double n,double decimal_points)2438 static double	eval_math_func_truncate(double n, double decimal_points)
2439 {
2440 	double	multiplier = 1;
2441 
2442 	if (0 < decimal_points)
2443 		multiplier = pow(10, decimal_points);
2444 
2445 	if (0 > n)
2446 		multiplier = -multiplier;
2447 
2448 	return floor(multiplier * n) / multiplier;
2449 }
2450 
2451 /******************************************************************************
2452  *                                                                            *
2453  * Function: eval_execute_math_function_double_param                          *
2454  *                                                                            *
2455  * Purpose: evaluate mathematical function by calling passed function         *
2456  *          with 2 double arguments                                           *
2457  *                                                                            *
2458  * Parameters: ctx        - [IN] the evaluation context                       *
2459  *             token      - [IN] the function token                           *
2460  *             output     - [IN/OUT] the output value stack                   *
2461  *             error      - [OUT] the error message in the case of failure    *
2462  *             func       - [IN] the pointer to math function                 *
2463  *                                                                            *
2464  * Return value: SUCCEED - function evaluation succeeded                      *
2465  *               FAIL    - otherwise                                          *
2466  *                                                                            *
2467  ******************************************************************************/
eval_execute_math_function_double_param(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error,double (* func)(double,double))2468 static int	eval_execute_math_function_double_param(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2469 		zbx_vector_var_t *output, char **error, double (*func)(double, double))
2470 {
2471 	int		ret;
2472 	double		result;
2473 	zbx_variant_t	*arg1, *arg2, value;
2474 
2475 	if (2 != token->opt)
2476 	{
2477 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2478 				ctx->expression + token->loc.l);
2479 		return FAIL;
2480 	}
2481 
2482 	if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error)))
2483 		return ret;
2484 
2485 	arg1 = &output->values[output->values_num - 2];
2486 	arg2 = &output->values[output->values_num - 1];
2487 
2488 	if (((eval_math_func_round == func || eval_math_func_truncate == func) && (0 > arg2->data.dbl ||
2489 			0.0 != fmod(arg2->data.dbl, 1))) || (fmod == func && 0.0 == arg2->data.dbl))
2490 	{
2491 		*error = zbx_dsprintf(*error, "invalid second argument for function at \"%s\"",
2492 				ctx->expression + token->loc.l);
2493 
2494 		return FAIL;
2495 	}
2496 
2497 	if (atan2 == func && 0.0 == arg1->data.dbl && 0.0 == arg2->data.dbl)
2498 	{
2499 		*error = zbx_dsprintf(*error, "undefined result for arguments (0,0) for function 'atan2' at \"%s\"",
2500 				ctx->expression + token->loc.l);
2501 
2502 		return FAIL;
2503 	}
2504 
2505 	result = func(arg1->data.dbl, arg2->data.dbl);
2506 
2507 	if (FP_ZERO != fpclassify(result) && FP_NORMAL != fpclassify(result))
2508 	{
2509 		*error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"",
2510 				ctx->expression + token->loc.l);
2511 		return FAIL;
2512 	}
2513 
2514 	zbx_variant_set_dbl(&value, result);
2515 
2516 	eval_function_return(token->opt, &value, output);
2517 
2518 	return SUCCEED;
2519 }
2520 
2521 /******************************************************************************
2522  *                                                                            *
2523  * Function: eval_execute_math_function_return_value                          *
2524  *                                                                            *
2525  * Purpose: evaluate mathematical function that returns constant value        *
2526  *                                                                            *
2527  * Parameters: ctx        - [IN] the evaluation context                       *
2528  *             token      - [IN] the function token                           *
2529  *             output     - [IN/OUT] the output value stack                   *
2530  *             error      - [OUT] the error message in the case of failure    *
2531  *             value      - [IN] the value to be returned                     *
2532  *                                                                            *
2533  * Return value: SUCCEED - function evaluation succeeded                      *
2534  *                                                                            *
2535  ******************************************************************************/
eval_execute_math_return_value(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error,double value)2536 static int	eval_execute_math_return_value(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2537 		zbx_vector_var_t *output, char **error, double value)
2538 {
2539 	zbx_variant_t	ret_value;
2540 
2541 	if (0 != token->opt)
2542 	{
2543 		*error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"",
2544 				ctx->expression + token->loc.l);
2545 		return FAIL;
2546 	}
2547 
2548 	if (ZBX_MATH_RANDOM == value)
2549 	{
2550 		struct timespec ts;
2551 
2552 		if (SUCCEED != clock_gettime(CLOCK_MONOTONIC, &ts))
2553 		{
2554 			*error = zbx_strdup(*error, "failed to generate seed for random number generator");
2555 			return FAIL;
2556 		}
2557 		else
2558 		{
2559 			srandom((unsigned int)(ts.tv_nsec ^ ts.tv_sec));
2560 			zbx_variant_set_dbl(&ret_value, random());
2561 		}
2562 	}
2563 	else
2564 		zbx_variant_set_dbl(&ret_value, value);
2565 
2566 	eval_function_return(0, &ret_value, output);
2567 
2568 	return SUCCEED;
2569 }
2570 
2571 /******************************************************************************
2572  *                                                                            *
2573  * Function: eval_execute_common_function                                     *
2574  *                                                                            *
2575  * Purpose: evaluate common function                                          *
2576  *                                                                            *
2577  * Parameters: ctx    - [IN] the evaluation context                           *
2578  *             token  - [IN] the function token                               *
2579  *             output - [IN/OUT] the output value stack                       *
2580  *             error  - [OUT] the error message in the case of failure        *
2581  *                                                                            *
2582  * Return value: SUCCEED - the function was executed successfully             *
2583  *               FAIL    - otherwise                                          *
2584  *                                                                            *
2585  ******************************************************************************/
eval_execute_common_function(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2586 static int	eval_execute_common_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2587 		zbx_vector_var_t *output, char **error)
2588 {
2589 	if ((zbx_uint32_t)output->values_num < token->opt)
2590 	{
2591 		*error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"",
2592 				ctx->expression + token->loc.l);
2593 		return FAIL;
2594 	}
2595 
2596 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "min", ZBX_CONST_STRLEN("min")))
2597 		return eval_execute_function_min(ctx, token, output, error);
2598 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "max", ZBX_CONST_STRLEN("max")))
2599 		return eval_execute_function_max(ctx, token, output, error);
2600 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "sum", ZBX_CONST_STRLEN("sum")))
2601 		return eval_execute_function_sum(ctx, token, output, error);
2602 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "avg", ZBX_CONST_STRLEN("avg")))
2603 		return eval_execute_function_avg(ctx, token, output, error);
2604 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "abs", ZBX_CONST_STRLEN("abs")))
2605 		return eval_execute_function_abs(ctx, token, output, error);
2606 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "length", ZBX_CONST_STRLEN("length")))
2607 		return eval_execute_function_length(ctx, token, output, error);
2608 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "date", ZBX_CONST_STRLEN("date")))
2609 		return eval_execute_function_date(ctx, token, output, error);
2610 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "time", ZBX_CONST_STRLEN("time")))
2611 		return eval_execute_function_time(ctx, token, output, error);
2612 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "now", ZBX_CONST_STRLEN("now")))
2613 		return eval_execute_function_now(ctx, token, output, error);
2614 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "dayofweek", ZBX_CONST_STRLEN("dayofweek")))
2615 		return eval_execute_function_dayofweek(ctx, token, output, error);
2616 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "dayofmonth", ZBX_CONST_STRLEN("dayofmonth")))
2617 		return eval_execute_function_dayofmonth(ctx, token, output, error);
2618 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitand", ZBX_CONST_STRLEN("bitand")))
2619 		return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_AND, output, error);
2620 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitor", ZBX_CONST_STRLEN("bitor")))
2621 		return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_OR, output, error);
2622 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitxor", ZBX_CONST_STRLEN("bitxor")))
2623 		return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_XOR, output, error);
2624 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitlshift", ZBX_CONST_STRLEN("bitlshift")))
2625 		return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_LSHIFT, output, error);
2626 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitrshift", ZBX_CONST_STRLEN("bitrshift")))
2627 		return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_RSHIFT, output, error);
2628 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitnot", ZBX_CONST_STRLEN("bitnot")))
2629 		return eval_execute_function_bitnot(ctx, token, output, error);
2630 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "between", ZBX_CONST_STRLEN("between")))
2631 		return eval_execute_function_between(ctx, token, output, error);
2632 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "in", ZBX_CONST_STRLEN("in")))
2633 		return eval_execute_function_in(ctx, token, output, error);
2634 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "ascii", ZBX_CONST_STRLEN("ascii")))
2635 		return eval_execute_function_ascii(ctx, token, output, error);
2636 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "char", ZBX_CONST_STRLEN("char")))
2637 		return eval_execute_function_char(ctx, token, output, error);
2638 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "left", ZBX_CONST_STRLEN("left")))
2639 		return eval_execute_function_left(ctx, token, output, error);
2640 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "right", ZBX_CONST_STRLEN("right")))
2641 		return eval_execute_function_right(ctx, token, output, error);
2642 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "mid", ZBX_CONST_STRLEN("mid")))
2643 		return eval_execute_function_mid(ctx, token, output, error);
2644 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitlength", ZBX_CONST_STRLEN("bitlength")))
2645 		return eval_execute_function_bitlength(ctx, token, output, error);
2646 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "bytelength", ZBX_CONST_STRLEN("bytelength")))
2647 		return eval_execute_function_bytelength(ctx, token, output, error);
2648 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "concat", ZBX_CONST_STRLEN("concat")))
2649 		return eval_execute_function_concat(ctx, token, output, error);
2650 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "insert", ZBX_CONST_STRLEN("insert")))
2651 		return eval_execute_function_insert(ctx, token, output, error);
2652 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "replace", ZBX_CONST_STRLEN("replace")))
2653 		return eval_execute_function_replace(ctx, token, output, error);
2654 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "repeat", ZBX_CONST_STRLEN("repeat")))
2655 		return eval_execute_function_repeat(ctx, token, output, error);
2656 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "ltrim", ZBX_CONST_STRLEN("ltrim")))
2657 		return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_LEFT, output, error);
2658 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "rtrim", ZBX_CONST_STRLEN("rtrim")))
2659 		return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_RIGHT, output, error);
2660 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "trim", ZBX_CONST_STRLEN("trim")))
2661 		return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_ALL, output, error);
2662 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "cbrt", ZBX_CONST_STRLEN("cbrt")))
2663 		return eval_execute_math_function_single_param(ctx, token, output, error, cbrt);
2664 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "ceil", ZBX_CONST_STRLEN("ceil")))
2665 		return eval_execute_math_function_single_param(ctx, token, output, error, ceil);
2666 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "exp", ZBX_CONST_STRLEN("exp")))
2667 		return eval_execute_math_function_single_param(ctx, token, output, error, exp);
2668 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "expm1", ZBX_CONST_STRLEN("expm1")))
2669 		return eval_execute_math_function_single_param(ctx, token, output, error, expm1);
2670 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "floor", ZBX_CONST_STRLEN("floor")))
2671 		return eval_execute_math_function_single_param(ctx, token, output, error, floor);
2672 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "signum", ZBX_CONST_STRLEN("signum")))
2673 		return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_signum);
2674 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "degrees", ZBX_CONST_STRLEN("degrees")))
2675 		return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_degrees);
2676 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "radians", ZBX_CONST_STRLEN("radians")))
2677 		return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_radians);
2678 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "acos", ZBX_CONST_STRLEN("acos")))
2679 		return eval_execute_math_function_single_param(ctx, token, output, error, acos);
2680 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "asin", ZBX_CONST_STRLEN("asin")))
2681 		return eval_execute_math_function_single_param(ctx, token, output, error, asin);
2682 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "atan", ZBX_CONST_STRLEN("atan")))
2683 		return eval_execute_math_function_single_param(ctx, token, output, error, atan);
2684 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "cos", ZBX_CONST_STRLEN("cos")))
2685 		return eval_execute_math_function_single_param(ctx, token, output, error, cos);
2686 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "cosh", ZBX_CONST_STRLEN("cosh")))
2687 		return eval_execute_math_function_single_param(ctx, token, output, error, cosh);
2688 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "cot", ZBX_CONST_STRLEN("cot")))
2689 		return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_cot);
2690 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "sin", ZBX_CONST_STRLEN("sin")))
2691 		return eval_execute_math_function_single_param(ctx, token, output, error, sin);
2692 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "sinh", ZBX_CONST_STRLEN("sinh")))
2693 		return eval_execute_math_function_single_param(ctx, token, output, error, sinh);
2694 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "tan", ZBX_CONST_STRLEN("tan")))
2695 		return eval_execute_math_function_single_param(ctx, token, output, error, tan);
2696 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "log", ZBX_CONST_STRLEN("log")))
2697 		return eval_execute_math_function_single_param(ctx, token, output, error, log);
2698 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "log10", ZBX_CONST_STRLEN("log10")))
2699 		return eval_execute_math_function_single_param(ctx, token, output, error, log10);
2700 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "sqrt", ZBX_CONST_STRLEN("sqrt")))
2701 		return eval_execute_math_function_single_param(ctx, token, output, error, sqrt);
2702 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "power", ZBX_CONST_STRLEN("power")))
2703 		return eval_execute_math_function_double_param(ctx, token, output, error, pow);
2704 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "round", ZBX_CONST_STRLEN("round")))
2705 		return eval_execute_math_function_double_param(ctx, token, output, error, eval_math_func_round);
2706 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "mod", ZBX_CONST_STRLEN("mod")))
2707 		return eval_execute_math_function_double_param(ctx, token, output, error, fmod);
2708 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "truncate", ZBX_CONST_STRLEN("truncate")))
2709 		return eval_execute_math_function_double_param(ctx, token, output, error, eval_math_func_truncate);
2710 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "atan2", ZBX_CONST_STRLEN("atan2")))
2711 		return eval_execute_math_function_double_param(ctx, token, output, error, atan2);
2712 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "pi", ZBX_CONST_STRLEN("pi")))
2713 		return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_CONST_PI);
2714 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "e", ZBX_CONST_STRLEN("e")))
2715 		return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_CONST_E);
2716 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "rand", ZBX_CONST_STRLEN("rand")))
2717 		return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_RANDOM);
2718 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "kurtosis", ZBX_CONST_STRLEN("kurtosis")))
2719 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_kurtosis, output, error);
2720 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "mad", ZBX_CONST_STRLEN("mad")))
2721 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_mad, output, error);
2722 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "skewness", ZBX_CONST_STRLEN("skewness")))
2723 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_skewness, output, error);
2724 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "stddevpop", ZBX_CONST_STRLEN("stddevpop")))
2725 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_stddevpop, output, error);
2726 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "stddevsamp", ZBX_CONST_STRLEN("stddevsamp")))
2727 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_stddevsamp, output, error);
2728 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "sumofsquares", ZBX_CONST_STRLEN("sumofsquares")))
2729 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_sumofsquares, output, error);
2730 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "varpop", ZBX_CONST_STRLEN("varpop")))
2731 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_varpop, output, error);
2732 	if (SUCCEED == eval_compare_token(ctx, &token->loc, "varsamp", ZBX_CONST_STRLEN("varsamp")))
2733 		return eval_execute_statistical_function(ctx, token, zbx_eval_calc_varsamp, output, error);
2734 
2735 	if (NULL != ctx->common_func_cb)
2736 		return eval_execute_cb_function(ctx, token, ctx->common_func_cb, output, error);
2737 
2738 	*error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l);
2739 	return FAIL;
2740 }
2741 
2742 /******************************************************************************
2743  *                                                                            *
2744  * Function: eval_execute_history_function                                    *
2745  *                                                                            *
2746  * Purpose: evaluate history function                                         *
2747  *                                                                            *
2748  * Parameters: ctx    - [IN] the evaluation context                           *
2749  *             token  - [IN] the function token                               *
2750  *             output - [IN/OUT] the output value stack                       *
2751  *             error  - [OUT] the error message in the case of failure        *
2752  *                                                                            *
2753  * Return value: SUCCEED - the function was executed successfully             *
2754  *               FAIL    - otherwise                                          *
2755  *                                                                            *
2756  ******************************************************************************/
eval_execute_history_function(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,zbx_vector_var_t * output,char ** error)2757 static int	eval_execute_history_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
2758 		zbx_vector_var_t *output, char **error)
2759 {
2760 	if ((zbx_uint32_t)output->values_num < token->opt)
2761 	{
2762 		*error = zbx_dsprintf(*error, "not enough arguments for function at \"%s\"",
2763 				ctx->expression + token->loc.l);
2764 		return FAIL;
2765 	}
2766 
2767 	if (NULL != ctx->history_func_cb)
2768 		return eval_execute_cb_function(ctx, token, ctx->history_func_cb, output, error);
2769 
2770 	*error = zbx_dsprintf(*error, "Unknown function at \"%s\".", ctx->expression + token->loc.l);
2771 	return FAIL;
2772 }
2773 
2774 /******************************************************************************
2775  *                                                                            *
2776  * Function: eval_throw_exception                                             *
2777  *                                                                            *
2778  * Purpose: throw exception by returning the specified error                  *
2779  *                                                                            *
2780  * Parameters: output - [IN/OUT] the output value stack                       *
2781  *             error  - [OUT] the error message in the case of failure        *
2782  *                                                                            *
2783  ******************************************************************************/
eval_throw_exception(zbx_vector_var_t * output,char ** error)2784 static void	eval_throw_exception(zbx_vector_var_t *output, char **error)
2785 {
2786 	zbx_variant_t	*arg;
2787 
2788 	if (0 == output->values_num)
2789 	{
2790 		*error = zbx_strdup(*error, "exception must have one argument");
2791 		return;
2792 	}
2793 
2794 	arg = &output->values[output->values_num - 1];
2795 	zbx_variant_convert(arg, ZBX_VARIANT_STR);
2796 	*error = arg->data.str;
2797 	zbx_variant_set_none(arg);
2798 }
2799 
2800 /******************************************************************************
2801  *                                                                            *
2802  * Function: eval_execute                                                     *
2803  *                                                                            *
2804  * Purpose: evaluate pre-parsed expression                                    *
2805  *                                                                            *
2806  * Parameters: ctx   - [IN] the evaluation context                            *
2807  *             value - [OUT] the resulting value                              *
2808  *             error - [OUT] the error message in the case of failure         *
2809  *                                                                            *
2810  * Return value: SUCCEED - the expression was evaluated successfully          *
2811  *               FAIL    - otherwise                                          *
2812  *                                                                            *
2813  ******************************************************************************/
eval_execute(const zbx_eval_context_t * ctx,zbx_variant_t * value,char ** error)2814 static int	eval_execute(const zbx_eval_context_t *ctx, zbx_variant_t *value, char **error)
2815 {
2816 	zbx_vector_var_t	output;
2817 	int			i, ret = FAIL;
2818 	char			*errmsg = NULL;
2819 
2820 	zbx_vector_var_create(&output);
2821 
2822 	for (i = 0; i < ctx->stack.values_num; i++)
2823 	{
2824 		zbx_eval_token_t	*token = &ctx->stack.values[i];
2825 
2826 		if (0 != (token->type & ZBX_EVAL_CLASS_OPERATOR1))
2827 		{
2828 			if (SUCCEED != eval_execute_op_unary(ctx, token, &output, &errmsg))
2829 				goto out;
2830 		}
2831 		else if (0 != (token->type & ZBX_EVAL_CLASS_OPERATOR2))
2832 		{
2833 			if (SUCCEED != eval_execute_op_binary(ctx, token, &output, &errmsg))
2834 				goto out;
2835 		}
2836 		else
2837 		{
2838 			switch (token->type)
2839 			{
2840 				case ZBX_EVAL_TOKEN_NOP:
2841 					break;
2842 				case ZBX_EVAL_TOKEN_VAR_NUM:
2843 				case ZBX_EVAL_TOKEN_VAR_STR:
2844 				case ZBX_EVAL_TOKEN_VAR_MACRO:
2845 				case ZBX_EVAL_TOKEN_VAR_USERMACRO:
2846 					if (SUCCEED != eval_execute_push_value(ctx, token, &output, &errmsg))
2847 						goto out;
2848 					break;
2849 				case ZBX_EVAL_TOKEN_ARG_QUERY:
2850 				case ZBX_EVAL_TOKEN_ARG_PERIOD:
2851 					if (SUCCEED != eval_execute_push_value(ctx, token, &output, &errmsg))
2852 						goto out;
2853 					break;
2854 				case ZBX_EVAL_TOKEN_ARG_NULL:
2855 					eval_execute_push_null(&output);
2856 					break;
2857 				case ZBX_EVAL_TOKEN_FUNCTION:
2858 					if (SUCCEED != eval_execute_common_function(ctx, token, &output, &errmsg))
2859 						goto out;
2860 					break;
2861 				case ZBX_EVAL_TOKEN_HIST_FUNCTION:
2862 					if (SUCCEED != eval_execute_history_function(ctx, token, &output, &errmsg))
2863 						goto out;
2864 					break;
2865 				case ZBX_EVAL_TOKEN_FUNCTIONID:
2866 					if (ZBX_VARIANT_NONE == token->value.type)
2867 					{
2868 						errmsg = zbx_strdup(errmsg, "trigger history functions must be"
2869 								" pre-calculated");
2870 						goto out;
2871 					}
2872 					if (SUCCEED != eval_execute_push_value(ctx, token, &output, &errmsg))
2873 						goto out;
2874 					break;
2875 				case ZBX_EVAL_TOKEN_EXCEPTION:
2876 					eval_throw_exception(&output, &errmsg);
2877 					goto out;
2878 				default:
2879 					errmsg = zbx_dsprintf(errmsg, "unknown token at \"%s\"",
2880 							ctx->expression + token->loc.l);
2881 					goto out;
2882 			}
2883 		}
2884 	}
2885 
2886 	if (1 != output.values_num)
2887 	{
2888 		errmsg = zbx_strdup(errmsg, "output stack after expression execution must contain one value");
2889 		goto out;
2890 	}
2891 
2892 	if (ZBX_VARIANT_ERR == output.values[0].type)
2893 	{
2894 		errmsg = zbx_strdup(errmsg, output.values[0].data.err);
2895 		goto out;
2896 	}
2897 
2898 	*value = output.values[0];
2899 	output.values_num = 0;
2900 
2901 	ret = SUCCEED;
2902 out:
2903 	if (SUCCEED != ret)
2904 	{
2905 		if (0 != islower(*errmsg))
2906 		{
2907 			*error = zbx_dsprintf(NULL, "Cannot evaluate expression: %s", errmsg);
2908 			zbx_free(errmsg);
2909 		}
2910 		else
2911 			*error = errmsg;
2912 	}
2913 
2914 	for (i = 0; i < output.values_num; i++)
2915 		zbx_variant_clear(&output.values[i]);
2916 
2917 	zbx_vector_var_destroy(&output);
2918 
2919 	return ret;
2920 }
2921 
2922 /******************************************************************************
2923  *                                                                            *
2924  * Function: eval_init_execute_context                                        *
2925  *                                                                            *
2926  * Purpose: initialize execution context                                      *
2927  *                                                                            *
2928  * Parameters: ctx             - [IN] the evaluation context                  *
2929  *             ts              - [IN] the timestamp of the execution time     *
2930  *             common_func_cb  - [IN] the common function callback (optional) *
2931  *             history_func_cb - [IN] the history function callback (optional)*
2932  *             data_cb         - [IN] the caller data to be passed to callback*
2933  *                                    functions                               *
2934  *                                                                            *
2935  ******************************************************************************/
eval_init_execute_context(zbx_eval_context_t * ctx,const zbx_timespec_t * ts,zbx_eval_function_cb_t common_func_cb,zbx_eval_function_cb_t history_func_cb,void * data_cb)2936 static void	eval_init_execute_context(zbx_eval_context_t *ctx, const zbx_timespec_t *ts,
2937 		zbx_eval_function_cb_t common_func_cb, zbx_eval_function_cb_t history_func_cb, void *data_cb)
2938 {
2939 	ctx->common_func_cb = common_func_cb;
2940 	ctx->history_func_cb = history_func_cb;
2941 	ctx->data_cb = data_cb;
2942 
2943 	if (NULL == ts)
2944 		ctx->ts.sec = ctx->ts.ns = 0;
2945 	else
2946 		ctx->ts = *ts;
2947 }
2948 
2949 /******************************************************************************
2950  *                                                                            *
2951  * Function: zbx_eval_execute                                                 *
2952  *                                                                            *
2953  * Purpose: evaluate parsed expression                                        *
2954  *                                                                            *
2955  * Parameters: ctx   - [IN] the evaluation context                            *
2956  *             ts    - [IN] the timestamp of the execution time               *
2957  *             value - [OUT] the resulting value                              *
2958  *             error - [OUT] the error message in the case of failure         *
2959  *                                                                            *
2960  * Return value: SUCCEED - the expression was evaluated successfully          *
2961  *               FAIL    - otherwise                                          *
2962  *                                                                            *
2963  ******************************************************************************/
zbx_eval_execute(zbx_eval_context_t * ctx,const zbx_timespec_t * ts,zbx_variant_t * value,char ** error)2964 int	zbx_eval_execute(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_variant_t *value, char **error)
2965 {
2966 	eval_init_execute_context(ctx, ts, NULL, NULL, NULL);
2967 
2968 	return eval_execute(ctx, value, error);
2969 }
2970 
2971 /******************************************************************************
2972  *                                                                            *
2973  * Function: zbx_eval_execute_ext                                             *
2974  *                                                                            *
2975  * Purpose: evaluate parsed expression with callback for custom function      *
2976  *          processing                                                        *
2977  *                                                                            *
2978  * Parameters: ctx             - [IN] the evaluation context                  *
2979  *             ts              - [IN] the timestamp of the execution time     *
2980  *             common_func_cb  - [IN] the common function callback (optional) *
2981  *             history_func_cb - [IN] the history function callback (optional)*
2982  *             value           - [OUT] the resulting value                    *
2983  *             error           - [OUT] the error message                      *
2984  *                                                                            *
2985  * Return value: SUCCEED - the expression was evaluated successfully          *
2986  *               FAIL    - otherwise                                          *
2987  *                                                                            *
2988  * Comments: The callback will be called for unsupported math and all history *
2989  *           functions.                                                       *
2990  *                                                                            *
2991  ******************************************************************************/
zbx_eval_execute_ext(zbx_eval_context_t * ctx,const zbx_timespec_t * ts,zbx_eval_function_cb_t common_func_cb,zbx_eval_function_cb_t history_func_cb,void * data,zbx_variant_t * value,char ** error)2992 int	zbx_eval_execute_ext(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, zbx_eval_function_cb_t common_func_cb,
2993 		zbx_eval_function_cb_t history_func_cb, void *data, zbx_variant_t *value, char **error)
2994 {
2995 	eval_init_execute_context(ctx, ts, common_func_cb, history_func_cb, data);
2996 
2997 	return eval_execute(ctx, value, error);
2998 }
2999