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