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 "zbxalgo.h"
22
23 #include "log.h"
24
25 /******************************************************************************
26 * *
27 * Module for evaluating expressions *
28 * --------------------------------------- *
29 * *
30 * Global variables are used for efficiency reasons so that arguments do not *
31 * have to be passed to each of evaluate_termX() functions. For this reason, *
32 * too, this module is isolated into a separate file. *
33 * *
34 * The priority of supported operators is as follows: *
35 * *
36 * - (unary) evaluate_term8() *
37 * not evaluate_term7() *
38 * * / evaluate_term6() *
39 * + - evaluate_term5() *
40 * < <= >= > evaluate_term4() *
41 * = <> evaluate_term3() *
42 * and evaluate_term2() *
43 * or evaluate_term1() *
44 * *
45 * Function evaluate_term9() is used for parsing tokens on the lowest level: *
46 * those can be suffixed numbers like "12.345K" or parenthesized expressions. *
47 * *
48 ******************************************************************************/
49
50 static const char *ptr; /* character being looked at */
51 static int level; /* expression nesting level */
52
53 static char *buffer; /* error message buffer */
54 static size_t max_buffer_len; /* error message buffer size */
55
56 /******************************************************************************
57 * *
58 * Purpose: check whether the character delimits a numeric token *
59 * *
60 ******************************************************************************/
is_number_delimiter(char c)61 static int is_number_delimiter(char c)
62 {
63 return 0 == isdigit(c) && '.' != c && 0 == isalpha(c) ? SUCCEED : FAIL;
64 }
65
66 /******************************************************************************
67 * *
68 * Purpose: check whether the character delimits a symbolic operator token *
69 * *
70 ******************************************************************************/
is_operator_delimiter(char c)71 static int is_operator_delimiter(char c)
72 {
73 return ' ' == c || '(' == c || '\r' == c || '\n' == c || '\t' == c || ')' == c || '\0' == c ? SUCCEED : FAIL;
74 }
75
76 /******************************************************************************
77 * *
78 * Purpose: evaluate a suffixed number like "12.345K" *
79 * *
80 ******************************************************************************/
evaluate_number(int * unknown_idx)81 static double evaluate_number(int *unknown_idx)
82 {
83 double result;
84 int len;
85
86 /* Is it a special token of unknown value (e.g. ZBX_UNKNOWN0, ZBX_UNKNOWN1) ? */
87 if (0 == strncmp(ZBX_UNKNOWN_STR, ptr, ZBX_UNKNOWN_STR_LEN))
88 {
89 const char *p0, *p1;
90
91 p0 = ptr + ZBX_UNKNOWN_STR_LEN;
92 p1 = p0;
93
94 /* extract the message number which follows after 'ZBX_UNKNOWN' */
95 while (0 != isdigit((unsigned char)*p1))
96 p1++;
97
98 if (p0 < p1 && SUCCEED == is_number_delimiter(*p1))
99 {
100 ptr = p1;
101
102 /* return 'unknown' and corresponding message number about its origin */
103 *unknown_idx = atoi(p0);
104 return ZBX_UNKNOWN;
105 }
106
107 ptr = p0;
108
109 return ZBX_INFINITY;
110 }
111
112 if (SUCCEED == zbx_suffixed_number_parse(ptr, &len) && SUCCEED == is_number_delimiter(*(ptr + len)))
113 {
114 result = atof(ptr) * suffix2factor(*(ptr + len - 1));
115 ptr += len;
116 }
117 else
118 result = ZBX_INFINITY;
119
120 return result;
121 }
122
123 static double evaluate_term1(int *unknown_idx);
124
125 /******************************************************************************
126 * *
127 * Purpose: evaluate a suffixed number or a parenthesized expression *
128 * *
129 ******************************************************************************/
evaluate_term9(int * unknown_idx)130 static double evaluate_term9(int *unknown_idx)
131 {
132 double result;
133
134 while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
135 ptr++;
136
137 if ('\0' == *ptr)
138 {
139 zbx_strlcpy(buffer, "Cannot evaluate expression: unexpected end of expression.", max_buffer_len);
140 return ZBX_INFINITY;
141 }
142
143 if ('(' == *ptr)
144 {
145 ptr++;
146
147 if (ZBX_INFINITY == (result = evaluate_term1(unknown_idx)))
148 return ZBX_INFINITY;
149
150 /* if evaluate_term1() returns ZBX_UNKNOWN then continue as with regular number */
151
152 if (')' != *ptr)
153 {
154 zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
155 " expected closing parenthesis at \"%s\".", ptr);
156 return ZBX_INFINITY;
157 }
158
159 ptr++;
160 }
161 else
162 {
163 if (ZBX_INFINITY == (result = evaluate_number(unknown_idx)))
164 {
165 zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
166 " expected numeric token at \"%s\".", ptr);
167 return ZBX_INFINITY;
168 }
169 }
170
171 while ('\0' != *ptr && (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr))
172 ptr++;
173
174 return result;
175 }
176
177 /******************************************************************************
178 * *
179 * Purpose: evaluate "-" (unary) *
180 * *
181 * -0.0 -> -0.0 *
182 * -1.2 -> -1.2 *
183 * -Unknown -> Unknown *
184 * *
185 ******************************************************************************/
evaluate_term8(int * unknown_idx)186 static double evaluate_term8(int *unknown_idx)
187 {
188 double result;
189
190 while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
191 ptr++;
192
193 if ('-' == *ptr)
194 {
195 ptr++;
196
197 if (ZBX_UNKNOWN == (result = evaluate_term9(unknown_idx)) || ZBX_INFINITY == result)
198 return result;
199
200 result = -result;
201 }
202 else
203 result = evaluate_term9(unknown_idx);
204
205 return result;
206 }
207
208 /******************************************************************************
209 * *
210 * Purpose: evaluate "not" *
211 * *
212 * not 0.0 -> 1.0 *
213 * not 1.2 -> 0.0 *
214 * not Unknown -> Unknown *
215 * *
216 ******************************************************************************/
evaluate_term7(int * unknown_idx)217 static double evaluate_term7(int *unknown_idx)
218 {
219 double result;
220
221 while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
222 ptr++;
223
224 if ('n' == ptr[0] && 'o' == ptr[1] && 't' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3]))
225 {
226 ptr += 3;
227
228 if (ZBX_UNKNOWN == (result = evaluate_term8(unknown_idx)) || ZBX_INFINITY == result)
229 return result;
230
231 result = (SUCCEED == zbx_double_compare(result, 0.0) ? 1.0 : 0.0);
232 }
233 else
234 result = evaluate_term8(unknown_idx);
235
236 return result;
237 }
238
239 /******************************************************************************
240 * *
241 * Purpose: evaluate "*" and "/" *
242 * *
243 * 0.0 * Unknown -> Unknown (yes, not 0 as we don't want to lose *
244 * Unknown in arithmetic operations) *
245 * 1.2 * Unknown -> Unknown *
246 * 0.0 / 1.2 -> 0.0 *
247 * 1.2 / 0.0 -> error (ZBX_INFINITY) *
248 * Unknown / 0.0 -> error (ZBX_INFINITY) *
249 * Unknown / 1.2 -> Unknown *
250 * Unknown / Unknown -> Unknown *
251 * 0.0 / Unknown -> Unknown *
252 * 1.2 / Unknown -> Unknown *
253 * *
254 ******************************************************************************/
evaluate_term6(int * unknown_idx)255 static double evaluate_term6(int *unknown_idx)
256 {
257 char op;
258 double result, operand;
259 int res_idx = -1, oper_idx = -2; /* set invalid values to catch errors */
260
261 if (ZBX_INFINITY == (result = evaluate_term7(&res_idx)))
262 return ZBX_INFINITY;
263
264 if (ZBX_UNKNOWN == result)
265 *unknown_idx = res_idx;
266
267 /* if evaluate_term7() returns ZBX_UNKNOWN then continue as with regular number */
268
269 while ('*' == *ptr || '/' == *ptr)
270 {
271 op = *ptr++;
272
273 /* 'ZBX_UNKNOWN' in multiplication and division produces 'ZBX_UNKNOWN'. */
274 /* Even if 1st operand is Unknown we evaluate 2nd operand too to catch fatal errors in it. */
275
276 if (ZBX_INFINITY == (operand = evaluate_term7(&oper_idx)))
277 return ZBX_INFINITY;
278
279 if ('*' == op)
280 {
281 if (ZBX_UNKNOWN == operand) /* (anything) * Unknown */
282 {
283 *unknown_idx = oper_idx;
284 res_idx = oper_idx;
285 result = ZBX_UNKNOWN;
286 }
287 else if (ZBX_UNKNOWN == result) /* Unknown * known */
288 {
289 *unknown_idx = res_idx;
290 }
291 else
292 result *= operand;
293 }
294 else
295 {
296 /* catch division by 0 even if 1st operand is Unknown */
297
298 if (ZBX_UNKNOWN != operand && SUCCEED == zbx_double_compare(operand, 0.0))
299 {
300 zbx_strlcpy(buffer, "Cannot evaluate expression: division by zero.", max_buffer_len);
301 return ZBX_INFINITY;
302 }
303
304 if (ZBX_UNKNOWN == operand) /* (anything) / Unknown */
305 {
306 *unknown_idx = oper_idx;
307 res_idx = oper_idx;
308 result = ZBX_UNKNOWN;
309 }
310 else if (ZBX_UNKNOWN == result) /* Unknown / known */
311 {
312 *unknown_idx = res_idx;
313 }
314 else
315 result /= operand;
316 }
317 }
318
319 return result;
320 }
321
322 /******************************************************************************
323 * *
324 * Purpose: evaluate "+" and "-" *
325 * *
326 * 0.0 +/- Unknown -> Unknown *
327 * 1.2 +/- Unknown -> Unknown *
328 * Unknown +/- Unknown -> Unknown *
329 * *
330 ******************************************************************************/
evaluate_term5(int * unknown_idx)331 static double evaluate_term5(int *unknown_idx)
332 {
333 char op;
334 double result, operand;
335 int res_idx = -3, oper_idx = -4; /* set invalid values to catch errors */
336
337 if (ZBX_INFINITY == (result = evaluate_term6(&res_idx)))
338 return ZBX_INFINITY;
339
340 if (ZBX_UNKNOWN == result)
341 *unknown_idx = res_idx;
342
343 /* if evaluate_term6() returns ZBX_UNKNOWN then continue as with regular number */
344
345 while ('+' == *ptr || '-' == *ptr)
346 {
347 op = *ptr++;
348
349 /* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
350
351 if (ZBX_INFINITY == (operand = evaluate_term6(&oper_idx)))
352 return ZBX_INFINITY;
353
354 if (ZBX_UNKNOWN == operand) /* (anything) +/- Unknown */
355 {
356 *unknown_idx = oper_idx;
357 res_idx = oper_idx;
358 result = ZBX_UNKNOWN;
359 }
360 else if (ZBX_UNKNOWN == result) /* Unknown +/- known */
361 {
362 *unknown_idx = res_idx;
363 }
364 else
365 {
366 if ('+' == op)
367 result += operand;
368 else
369 result -= operand;
370 }
371 }
372
373 return result;
374 }
375
376 /******************************************************************************
377 * *
378 * Purpose: evaluate "<", "<=", ">=", ">" *
379 * *
380 * 0.0 < Unknown -> Unknown *
381 * 1.2 < Unknown -> Unknown *
382 * Unknown < Unknown -> Unknown *
383 * *
384 ******************************************************************************/
evaluate_term4(int * unknown_idx)385 static double evaluate_term4(int *unknown_idx)
386 {
387 char op;
388 double result, operand;
389 int res_idx = -5, oper_idx = -6; /* set invalid values to catch errors */
390
391 if (ZBX_INFINITY == (result = evaluate_term5(&res_idx)))
392 return ZBX_INFINITY;
393
394 if (ZBX_UNKNOWN == result)
395 *unknown_idx = res_idx;
396
397 /* if evaluate_term5() returns ZBX_UNKNOWN then continue as with regular number */
398
399 while (1)
400 {
401 if ('<' == ptr[0] && '=' == ptr[1])
402 {
403 op = 'l';
404 ptr += 2;
405 }
406 else if ('>' == ptr[0] && '=' == ptr[1])
407 {
408 op = 'g';
409 ptr += 2;
410 }
411 else if (('<' == ptr[0] && '>' != ptr[1]) || '>' == ptr[0])
412 {
413 op = *ptr++;
414 }
415 else
416 break;
417
418 /* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
419
420 if (ZBX_INFINITY == (operand = evaluate_term5(&oper_idx)))
421 return ZBX_INFINITY;
422
423 if (ZBX_UNKNOWN == operand) /* (anything) < Unknown */
424 {
425 *unknown_idx = oper_idx;
426 res_idx = oper_idx;
427 result = ZBX_UNKNOWN;
428 }
429 else if (ZBX_UNKNOWN == result) /* Unknown < known */
430 {
431 *unknown_idx = res_idx;
432 }
433 else
434 {
435 if ('<' == op)
436 result = (result < operand - ZBX_DOUBLE_EPSILON);
437 else if ('l' == op)
438 result = (result <= operand + ZBX_DOUBLE_EPSILON);
439 else if ('g' == op)
440 result = (result >= operand - ZBX_DOUBLE_EPSILON);
441 else
442 result = (result > operand + ZBX_DOUBLE_EPSILON);
443 }
444 }
445
446 return result;
447 }
448
449 /******************************************************************************
450 * *
451 * Purpose: evaluate "=" and "<>" *
452 * *
453 * 0.0 = Unknown -> Unknown *
454 * 1.2 = Unknown -> Unknown *
455 * Unknown = Unknown -> Unknown *
456 * 0.0 <> Unknown -> Unknown *
457 * 1.2 <> Unknown -> Unknown *
458 * Unknown <> Unknown -> Unknown *
459 * *
460 ******************************************************************************/
evaluate_term3(int * unknown_idx)461 static double evaluate_term3(int *unknown_idx)
462 {
463 char op;
464 double result, operand;
465 int res_idx = -7, oper_idx = -8; /* set invalid values to catch errors */
466
467 if (ZBX_INFINITY == (result = evaluate_term4(&res_idx)))
468 return ZBX_INFINITY;
469
470 if (ZBX_UNKNOWN == result)
471 *unknown_idx = res_idx;
472
473 /* if evaluate_term4() returns ZBX_UNKNOWN then continue as with regular number */
474
475 while (1)
476 {
477 if ('=' == *ptr)
478 {
479 op = *ptr++;
480 }
481 else if ('<' == ptr[0] && '>' == ptr[1])
482 {
483 op = '#';
484 ptr += 2;
485 }
486 else
487 break;
488
489 /* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
490
491 if (ZBX_INFINITY == (operand = evaluate_term4(&oper_idx)))
492 return ZBX_INFINITY;
493
494 if (ZBX_UNKNOWN == operand) /* (anything) = Unknown, (anything) <> Unknown */
495 {
496 *unknown_idx = oper_idx;
497 res_idx = oper_idx;
498 result = ZBX_UNKNOWN;
499 }
500 else if (ZBX_UNKNOWN == result) /* Unknown = known, Unknown <> known */
501 {
502 *unknown_idx = res_idx;
503 }
504 else if ('=' == op)
505 {
506 result = (SUCCEED == zbx_double_compare(result, operand));
507 }
508 else
509 result = (SUCCEED != zbx_double_compare(result, operand));
510 }
511
512 return result;
513 }
514
515 /******************************************************************************
516 * *
517 * Purpose: evaluate "and" *
518 * *
519 * 0.0 and Unknown -> 0.0 *
520 * Unknown and 0.0 -> 0.0 *
521 * 1.0 and Unknown -> Unknown *
522 * Unknown and 1.0 -> Unknown *
523 * Unknown and Unknown -> Unknown *
524 * *
525 ******************************************************************************/
evaluate_term2(int * unknown_idx)526 static double evaluate_term2(int *unknown_idx)
527 {
528 double result, operand;
529 int res_idx = -9, oper_idx = -10; /* set invalid values to catch errors */
530
531 if (ZBX_INFINITY == (result = evaluate_term3(&res_idx)))
532 return ZBX_INFINITY;
533
534 if (ZBX_UNKNOWN == result)
535 *unknown_idx = res_idx;
536
537 /* if evaluate_term3() returns ZBX_UNKNOWN then continue as with regular number */
538
539 while ('a' == ptr[0] && 'n' == ptr[1] && 'd' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3]))
540 {
541 ptr += 3;
542
543 if (ZBX_INFINITY == (operand = evaluate_term3(&oper_idx)))
544 return ZBX_INFINITY;
545
546 if (ZBX_UNKNOWN == result)
547 {
548 if (ZBX_UNKNOWN == operand) /* Unknown and Unknown */
549 {
550 *unknown_idx = oper_idx;
551 res_idx = oper_idx;
552 result = ZBX_UNKNOWN;
553 }
554 else if (SUCCEED == zbx_double_compare(operand, 0.0)) /* Unknown and 0 */
555 {
556 result = 0.0;
557 }
558 else /* Unknown and 1 */
559 *unknown_idx = res_idx;
560 }
561 else if (ZBX_UNKNOWN == operand)
562 {
563 if (SUCCEED == zbx_double_compare(result, 0.0)) /* 0 and Unknown */
564 {
565 result = 0.0;
566 }
567 else /* 1 and Unknown */
568 {
569 *unknown_idx = oper_idx;
570 res_idx = oper_idx;
571 result = ZBX_UNKNOWN;
572 }
573 }
574 else
575 {
576 result = (SUCCEED != zbx_double_compare(result, 0.0) &&
577 SUCCEED != zbx_double_compare(operand, 0.0));
578 }
579 }
580
581 return result;
582 }
583
584 /******************************************************************************
585 * *
586 * Purpose: evaluate "or" *
587 * *
588 * 1.0 or Unknown -> 1.0 *
589 * Unknown or 1.0 -> 1.0 *
590 * 0.0 or Unknown -> Unknown *
591 * Unknown or 0.0 -> Unknown *
592 * Unknown or Unknown -> Unknown *
593 * *
594 ******************************************************************************/
evaluate_term1(int * unknown_idx)595 static double evaluate_term1(int *unknown_idx)
596 {
597 double result, operand;
598 int res_idx = -11, oper_idx = -12; /* set invalid values to catch errors */
599
600 level++;
601
602 if (32 < level)
603 {
604 zbx_strlcpy(buffer, "Cannot evaluate expression: nesting level is too deep.", max_buffer_len);
605 return ZBX_INFINITY;
606 }
607
608 if (ZBX_INFINITY == (result = evaluate_term2(&res_idx)))
609 return ZBX_INFINITY;
610
611 if (ZBX_UNKNOWN == result)
612 *unknown_idx = res_idx;
613
614 /* if evaluate_term2() returns ZBX_UNKNOWN then continue as with regular number */
615
616 while ('o' == ptr[0] && 'r' == ptr[1] && SUCCEED == is_operator_delimiter(ptr[2]))
617 {
618 ptr += 2;
619
620 if (ZBX_INFINITY == (operand = evaluate_term2(&oper_idx)))
621 return ZBX_INFINITY;
622
623 if (ZBX_UNKNOWN == result)
624 {
625 if (ZBX_UNKNOWN == operand) /* Unknown or Unknown */
626 {
627 *unknown_idx = oper_idx;
628 res_idx = oper_idx;
629 result = ZBX_UNKNOWN;
630 }
631 else if (SUCCEED != zbx_double_compare(operand, 0.0)) /* Unknown or 1 */
632 {
633 result = 1;
634 }
635 else /* Unknown or 0 */
636 *unknown_idx = res_idx;
637 }
638 else if (ZBX_UNKNOWN == operand)
639 {
640 if (SUCCEED != zbx_double_compare(result, 0.0)) /* 1 or Unknown */
641 {
642 result = 1;
643 }
644 else /* 0 or Unknown */
645 {
646 *unknown_idx = oper_idx;
647 res_idx = oper_idx;
648 result = ZBX_UNKNOWN;
649 }
650 }
651 else
652 {
653 result = (SUCCEED != zbx_double_compare(result, 0.0) ||
654 SUCCEED != zbx_double_compare(operand, 0.0));
655 }
656 }
657
658 level--;
659
660 return result;
661 }
662
663 /******************************************************************************
664 * *
665 * Purpose: evaluate an expression like "(26.416>10) or (0=1)" *
666 * *
667 ******************************************************************************/
evaluate(double * value,const char * expression,char * error,size_t max_error_len,zbx_vector_ptr_t * unknown_msgs)668 int evaluate(double *value, const char *expression, char *error, size_t max_error_len,
669 zbx_vector_ptr_t *unknown_msgs)
670 {
671 const char *__function_name = "evaluate";
672 int unknown_idx = -13; /* index of message in 'unknown_msgs' vector, set to invalid value */
673 /* to catch errors */
674
675 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, expression);
676
677 ptr = expression;
678 level = 0;
679
680 buffer = error;
681 max_buffer_len = max_error_len;
682
683 *value = evaluate_term1(&unknown_idx);
684
685 if ('\0' != *ptr && ZBX_INFINITY != *value)
686 {
687 zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unexpected token at \"%s\".", ptr);
688 *value = ZBX_INFINITY;
689 }
690
691 if (ZBX_UNKNOWN == *value)
692 {
693 /* Map Unknown result to error. Callers currently do not operate with ZBX_UNKNOWN. */
694 if (NULL != unknown_msgs)
695 {
696 if (0 > unknown_idx)
697 {
698 THIS_SHOULD_NEVER_HAPPEN;
699 zabbix_log(LOG_LEVEL_WARNING, "%s() internal error: " ZBX_UNKNOWN_STR " index:%d"
700 " expression:'%s'", __function_name, unknown_idx, expression);
701 zbx_snprintf(error, max_error_len, "Internal error: " ZBX_UNKNOWN_STR " index %d."
702 " Please report this to Zabbix developers.", unknown_idx);
703 }
704 else if (unknown_msgs->values_num > unknown_idx)
705 {
706 zbx_snprintf(error, max_error_len, "Cannot evaluate expression: \"%s\".",
707 (char *)(unknown_msgs->values[unknown_idx]));
708 }
709 else
710 {
711 zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unsupported "
712 ZBX_UNKNOWN_STR "%d value.", unknown_idx);
713 }
714 }
715 else
716 {
717 THIS_SHOULD_NEVER_HAPPEN;
718 /* do not leave garbage in error buffer, write something helpful */
719 zbx_snprintf(error, max_error_len, "%s(): internal error: no message for unknown result",
720 __function_name);
721 }
722
723 *value = ZBX_INFINITY;
724 }
725
726 if (ZBX_INFINITY == *value)
727 {
728 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() error:'%s'", __function_name, error);
729 return FAIL;
730 }
731
732 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:" ZBX_FS_DBL, __function_name, *value);
733
734 return SUCCEED;
735 }
736
737 /******************************************************************************
738 * *
739 * Function: evaluate_unknown *
740 * *
741 * Purpose: evaluate an expression like "(26.416>10) and not(0=ZBX_UNKNOWN0)" *
742 * *
743 * Parameters: expression - [IN] expression to evaluate *
744 * value - [OUT] expression evaluation result *
745 * error - [OUT] error message buffer *
746 * max_error_len - [IN] error buffer size *
747 * *
748 * Return value: SUCCEED - expression evaluated successfully, *
749 * or evaluation result is undefined (ZBX_UNKNOWN) *
750 * FAIL - expression evaluation failed *
751 * *
752 ******************************************************************************/
evaluate_unknown(const char * expression,double * value,char * error,size_t max_error_len)753 int evaluate_unknown(const char *expression, double *value, char *error, size_t max_error_len)
754 {
755 const char *__function_name = "evaluate_with_unknown";
756 int unknown_idx = -13; /* index of message in 'unknown_msgs' vector, set to invalid value */
757 /* to catch errors */
758
759 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, expression);
760
761 ptr = expression;
762 level = 0;
763
764 buffer = error;
765 max_buffer_len = max_error_len;
766
767 *value = evaluate_term1(&unknown_idx);
768
769 if ('\0' != *ptr && ZBX_INFINITY != *value)
770 {
771 zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unexpected token at \"%s\".", ptr);
772 *value = ZBX_INFINITY;
773 }
774
775 if (ZBX_INFINITY == *value)
776 {
777 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() error:'%s'", __function_name, error);
778 return FAIL;
779 }
780
781 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:" ZBX_FS_DBL, __function_name, *value);
782
783 return SUCCEED;
784 }
785