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

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislavs Sokurenko <vladislavs.sokurenko@zabbix.com>2022-11-09 15:18:54 +0300
committerVladislavs Sokurenko <vladislavs.sokurenko@zabbix.com>2022-11-09 15:18:54 +0300
commitdb421a90914101fc3da46b8041b65c7170d1b2ec (patch)
tree458c0df49e589f8aef7127312c7fb0d01d7de1bf
parent63d14f431d1d6f00d8b15e3609360abe8076a29b (diff)
........S. [ZBX-21825] improved history syncer performance
-rw-r--r--src/libs/zbxcommon/str.c6059
1 files changed, 0 insertions, 6059 deletions
diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c
deleted file mode 100644
index c4f474bda08..00000000000
--- a/src/libs/zbxcommon/str.c
+++ /dev/null
@@ -1,6059 +0,0 @@
-/*
-** Zabbix
-** Copyright (C) 2001-2022 Zabbix SIA
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**/
-
-#include "common.h"
-
-#include "zbxthreads.h"
-#include "module.h"
-
-#ifdef HAVE_ICONV
-# include <iconv.h>
-#endif
-
-static const char copyright_message[] =
- "Copyright (C) 2022 Zabbix SIA\n"
- "License GPLv2+: GNU GPL version 2 or later <https://www.gnu.org/licenses/>.\n"
- "This is free software: you are free to change and redistribute it according to\n"
- "the license. There is NO WARRANTY, to the extent permitted by law.";
-
-static const char help_message_footer[] =
- "Report bugs to: <https://support.zabbix.com>\n"
- "Zabbix home page: <http://www.zabbix.com>\n"
- "Documentation: <https://www.zabbix.com/documentation>";
-
-/******************************************************************************
- * *
- * Purpose: print version and compilation time of application on stdout *
- * by application request with parameter '-V' *
- * *
- * Comments: title_message - is global variable which must be initialized *
- * in each zabbix application *
- * *
- ******************************************************************************/
-void zbx_version(void)
-{
- printf("%s (Zabbix) %s\n", title_message, ZABBIX_VERSION);
- printf("Revision %s %s, compilation time: %s %s\n\n", ZABBIX_REVISION, ZABBIX_REVDATE, __DATE__, __TIME__);
- puts(copyright_message);
-}
-
-/******************************************************************************
- * *
- * Purpose: print application parameters on stdout with layout suitable for *
- * 80-column terminal *
- * *
- * Comments: usage_message - is global variable which must be initialized *
- * in each zabbix application *
- * *
- ******************************************************************************/
-void zbx_usage(void)
-{
-#define ZBX_MAXCOL 79
-#define ZBX_SPACE1 " " /* left margin for the first line */
-#define ZBX_SPACE2 " " /* left margin for subsequent lines */
- const char **p = usage_message;
-
- if (NULL != *p)
- printf("usage:\n");
-
- while (NULL != *p)
- {
- size_t pos;
-
- printf("%s%s", ZBX_SPACE1, progname);
- pos = ZBX_CONST_STRLEN(ZBX_SPACE1) + strlen(progname);
-
- while (NULL != *p)
- {
- size_t len;
-
- len = strlen(*p);
-
- if (ZBX_MAXCOL > pos + len)
- {
- pos += len + 1;
- printf(" %s", *p);
- }
- else
- {
- pos = ZBX_CONST_STRLEN(ZBX_SPACE2) + len + 1;
- printf("\n%s %s", ZBX_SPACE2, *p);
- }
-
- p++;
- }
-
- printf("\n");
- p++;
- }
-#undef ZBX_MAXCOL
-#undef ZBX_SPACE1
-#undef ZBX_SPACE2
-}
-
-/******************************************************************************
- * *
- * Purpose: print help of application parameters on stdout by application *
- * request with parameter '-h' *
- * *
- * Comments: help_message - is global variable which must be initialized *
- * in each zabbix application *
- * *
- ******************************************************************************/
-void zbx_help(void)
-{
- const char **p = help_message;
-
- zbx_usage();
- printf("\n");
-
- while (NULL != *p)
- printf("%s\n", *p++);
-
- printf("\n");
- puts(help_message_footer);
-}
-
-/******************************************************************************
- * *
- * Purpose: Print error text to the stderr *
- * *
- * Parameters: fmt - format of message *
- * *
- ******************************************************************************/
-void zbx_error(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
-
- fprintf(stderr, "%s [%li]: ", progname, zbx_get_thread_id());
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
- fflush(stderr);
-
- va_end(args);
-}
-
-/******************************************************************************
- * *
- * Purpose: Secure version of snprintf function. *
- * Add zero character at the end of string. *
- * *
- * Parameters: str - destination buffer pointer *
- * count - size of destination buffer *
- * fmt - format *
- * *
- ******************************************************************************/
-size_t zbx_snprintf(char *str, size_t count, const char *fmt, ...)
-{
- size_t written_len;
- va_list args;
-
- va_start(args, fmt);
- written_len = zbx_vsnprintf(str, count, fmt, args);
- va_end(args);
-
- return written_len;
-}
-
-/******************************************************************************
- * *
- * Purpose: Secure version of snprintf function. *
- * Add zero character at the end of string. *
- * Reallocs memory if not enough. *
- * *
- * Parameters: str - [IN/OUT] destination buffer pointer *
- * alloc_len - [IN/OUT] already allocated memory *
- * offset - [IN/OUT] offset for writing *
- * fmt - [IN] format *
- * *
- ******************************************************************************/
-void zbx_snprintf_alloc(char **str, size_t *alloc_len, size_t *offset, const char *fmt, ...)
-{
- va_list args;
- size_t avail_len, written_len;
-retry:
- if (NULL == *str)
- {
- /* zbx_vsnprintf() returns bytes actually written instead of bytes to write, */
- /* so we have to use the standard function */
- va_start(args, fmt);
- *alloc_len = vsnprintf(NULL, 0, fmt, args) + 2; /* '\0' + one byte to prevent the operation retry */
- va_end(args);
- *offset = 0;
- *str = (char *)zbx_malloc(*str, *alloc_len);
- }
-
- avail_len = *alloc_len - *offset;
- va_start(args, fmt);
- written_len = zbx_vsnprintf(*str + *offset, avail_len, fmt, args);
- va_end(args);
-
- if (written_len == avail_len - 1)
- {
- *alloc_len *= 2;
- *str = (char *)zbx_realloc(*str, *alloc_len);
-
- goto retry;
- }
-
- *offset += written_len;
-}
-
-/******************************************************************************
- * *
- * Purpose: Secure version of vsnprintf function. *
- * Add zero character at the end of string. *
- * *
- * Parameters: str - [IN/OUT] destination buffer pointer *
- * count - [IN] size of destination buffer *
- * fmt - [IN] format *
- * *
- * Return value: the number of characters in the output buffer *
- * (not including the trailing '\0') *
- * *
- ******************************************************************************/
-size_t zbx_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
-{
- int written_len = 0;
-
- if (0 < count)
- {
- if (0 > (written_len = vsnprintf(str, count, fmt, args)))
- written_len = (int)count - 1; /* count an output error as a full buffer */
- else
- written_len = MIN(written_len, (int)count - 1); /* result could be truncated */
- }
- str[written_len] = '\0'; /* always write '\0', even if buffer size is 0 or vsnprintf() error */
-
- return (size_t)written_len;
-}
-
-/******************************************************************************
- * *
- * Purpose: If there is no '\0' byte among the first n bytes of src, *
- * then all n bytes will be placed into the dest buffer. *
- * In other case only strlen() bytes will be placed there. *
- * Add zero character at the end of string. *
- * Reallocs memory if not enough. *
- * *
- * Parameters: str - [IN/OUT] destination buffer pointer *
- * alloc_len - [IN/OUT] already allocated memory *
- * offset - [IN/OUT] offset for writing *
- * src - [IN] copied string *
- * n - [IN] maximum number of bytes to copy *
- * *
- ******************************************************************************/
-void zbx_strncpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src, size_t n)
-{
- if (NULL == *str)
- {
- *alloc_len = n + 1;
- *offset = 0;
- *str = (char *)zbx_malloc(*str, *alloc_len);
- }
- else if (*offset + n >= *alloc_len)
- {
- if (0 == *alloc_len)
- {
- THIS_SHOULD_NEVER_HAPPEN;
- exit(EXIT_FAILURE);
- }
-
- while (*offset + n >= *alloc_len)
- *alloc_len *= 2;
- *str = (char *)zbx_realloc(*str, *alloc_len);
- }
-
- while (0 != n && '\0' != *src)
- {
- (*str)[(*offset)++] = *src++;
- n--;
- }
-
- (*str)[*offset] = '\0';
-}
-
-void zbx_str_memcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src, size_t n)
-{
- if (NULL == *str)
- {
- *alloc_len = n + 1;
- *offset = 0;
- *str = (char *)zbx_malloc(*str, *alloc_len);
- }
- else if (*offset + n >= *alloc_len)
- {
- while (*offset + n >= *alloc_len)
- *alloc_len *= 2;
- *str = (char *)zbx_realloc(*str, *alloc_len);
- }
-
- memcpy(*str + *offset, src, n);
- *offset += n;
- (*str)[*offset] = '\0';
-}
-
-void zbx_strcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src)
-{
- zbx_strncpy_alloc(str, alloc_len, offset, src, strlen(src));
-}
-
-void zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c)
-{
- zbx_strncpy_alloc(str, alloc_len, offset, &c, 1);
-}
-
-void zbx_strquote_alloc(char **str, size_t *str_alloc, size_t *str_offset, const char *value_str)
-{
- size_t size;
- const char *src;
- char *dst;
-
- for (size = 2, src = value_str; '\0' != *src; src++)
- {
- switch (*src)
- {
- case '\\':
- case '"':
- size++;
- }
- size++;
- }
-
- if (*str_alloc <= *str_offset + size)
- {
- if (0 == *str_alloc)
- *str_alloc = size;
-
- do
- {
- *str_alloc *= 2;
- }
- while (*str_alloc - *str_offset <= size);
-
- *str = zbx_realloc(*str, *str_alloc);
- }
-
- dst = *str + *str_offset;
- *dst++ = '"';
-
- for (src = value_str; '\0' != *src; src++, dst++)
- {
- switch (*src)
- {
- case '\\':
- case '"':
- *dst++ = '\\';
- break;
- }
-
- *dst = *src;
- }
-
- *dst++ = '"';
- *dst = '\0';
- *str_offset += size;
-}
-
-/* Has to be rewritten to avoid malloc */
-char *string_replace(const char *str, const char *sub_str1, const char *sub_str2)
-{
- char *new_str = NULL;
- const char *p;
- const char *q;
- const char *r;
- char *t;
- long len, diff, count = 0;
-
- assert(str);
- assert(sub_str1);
- assert(sub_str2);
-
- len = (long)strlen(sub_str1);
-
- /* count the number of occurrences of sub_str1 */
- for ( p=str; (p = strstr(p, sub_str1)); p+=len, count++ );
-
- if (0 == count)
- return zbx_strdup(NULL, str);
-
- diff = (long)strlen(sub_str2) - len;
-
- /* allocate new memory */
- new_str = (char *)zbx_malloc(new_str, (size_t)(strlen(str) + count*diff + 1)*sizeof(char));
-
- for (q=str,t=new_str,p=str; (p = strstr(p, sub_str1)); )
- {
- /* copy until next occurrence of sub_str1 */
- for ( ; q < p; *t++ = *q++);
- q += len;
- p = q;
- for ( r = sub_str2; (*t++ = *r++); );
- --t;
- }
- /* copy the tail of str */
- for( ; *q ; *t++ = *q++ );
-
- *t = '\0';
-
- return new_str;
-}
-
-/******************************************************************************
- * *
- * Purpose: delete all right '0' and '.' for the string *
- * *
- * Parameters: s - string to trim '0' *
- * *
- * Return value: string without right '0' *
- * *
- * Comments: 10.0100 => 10.01, 10. => 10 *
- * *
- ******************************************************************************/
-void del_zeros(char *s)
-{
- int trim = 0;
- size_t len = 0;
-
- while ('\0' != s[len])
- {
- if ('e' == s[len] || 'E' == s[len])
- {
- /* don't touch numbers that are written in scientific notation */
- return;
- }
-
- if ('.' == s[len])
- {
- /* number has decimal part */
-
- if (1 == trim)
- {
- /* don't touch invalid numbers with more than one decimal separator */
- return;
- }
-
- trim = 1;
- }
-
- len++;
- }
-
- if (1 == trim)
- {
- size_t i;
-
- for (i = len - 1; ; i--)
- {
- if ('0' == s[i])
- {
- s[i] = '\0';
- }
- else if ('.' == s[i])
- {
- s[i] = '\0';
- break;
- }
- else
- {
- break;
- }
- }
- }
-}
-
-/******************************************************************************
- * *
- * Purpose: Strip characters from the end of a string *
- * *
- * Parameters: str - string for processing *
- * charlist - null terminated list of characters *
- * *
- * Return value: number of trimmed characters *
- * *
- ******************************************************************************/
-int zbx_rtrim(char *str, const char *charlist)
-{
- char *p;
- int count = 0;
-
- if (NULL == str || '\0' == *str)
- return count;
-
- for (p = str + strlen(str) - 1; p >= str && NULL != strchr(charlist, *p); p--)
- {
- *p = '\0';
- count++;
- }
-
- return count;
-}
-
-/******************************************************************************
- * *
- * Purpose: Strip characters from the beginning of a string *
- * *
- * Parameters: str - string for processing *
- * charlist - null terminated list of characters *
- * *
- ******************************************************************************/
-void zbx_ltrim(char *str, const char *charlist)
-{
- char *p;
-
- if (NULL == str || '\0' == *str)
- return;
-
- for (p = str; '\0' != *p && NULL != strchr(charlist, *p); p++)
- ;
-
- if (p == str)
- return;
-
- while ('\0' != *p)
- *str++ = *p++;
-
- *str = '\0';
-}
-
-/******************************************************************************
- * *
- * Purpose: Removes leading and trailing characters from the specified *
- * character string *
- * *
- * Parameters: str - [IN/OUT] string for processing *
- * charlist - [IN] null terminated list of characters *
- * *
- ******************************************************************************/
-void zbx_lrtrim(char *str, const char *charlist)
-{
- zbx_rtrim(str, charlist);
- zbx_ltrim(str, charlist);
-}
-
-/******************************************************************************
- * *
- * Purpose: Remove characters 'charlist' from the whole string *
- * *
- * Parameters: str - string for processing *
- * charlist - null terminated list of characters *
- * *
- ******************************************************************************/
-void zbx_remove_chars(char *str, const char *charlist)
-{
- char *p;
-
- if (NULL == str || NULL == charlist || '\0' == *str || '\0' == *charlist)
- return;
-
- for (p = str; '\0' != *p; p++)
- {
- if (NULL == strchr(charlist, *p))
- *str++ = *p;
- }
-
- *str = '\0';
-}
-
-/******************************************************************************
- * *
- * Purpose: converts text to printable string by converting special *
- * characters to escape sequences *
- * *
- * Parameters: text - [IN] the text to convert *
- * *
- * Return value: The text converted in printable format *
- * *
- ******************************************************************************/
-char *zbx_str_printable_dyn(const char *text)
-{
- size_t out_alloc = 0;
- const char *pin;
- char *out, *pout;
-
- for (pin = text; '\0' != *pin; pin++)
- {
- switch (*pin)
- {
- case '\n':
- case '\t':
- case '\r':
- out_alloc += 2;
- break;
- default:
- out_alloc++;
- break;
- }
- }
-
- out = zbx_malloc(NULL, ++out_alloc);
-
- for (pin = text, pout = out; '\0' != *pin; pin++)
- {
- switch (*pin)
- {
- case '\n':
- *pout++ = '\\';
- *pout++ = 'n';
- break;
- case '\t':
- *pout++ = '\\';
- *pout++ = 't';
- break;
- case '\r':
- *pout++ = '\\';
- *pout++ = 'r';
- break;
- default:
- *pout++ = *pin;
- break;
- }
- }
- *pout = '\0';
-
- return out;
-}
-
-/******************************************************************************
- * *
- * Purpose: Copy src to string dst of size siz. At most siz - 1 characters *
- * will be copied. Always null terminates (unless siz == 0). *
- * *
- * Return value: the number of characters copied (excluding the null byte) *
- * *
- ******************************************************************************/
-size_t zbx_strlcpy(char *dst, const char *src, size_t siz)
-{
- size_t len = strlen(src);
-
- if (len + 1 <= siz)
- {
- memcpy(dst, src, len + 1);
- return len;
- }
-
- if (0 == siz)
- return 0;
-
- memcpy(dst, src, siz - 1);
- dst[siz - 1] = '\0';
-
- return siz - 1;
-}
-
-/******************************************************************************
- * *
- * Purpose: Appends src to string dst of size siz (unlike strncat, size is *
- * the full size of dst, not space left). At most siz - 1 characters *
- * will be copied. Always null terminates (unless *
- * siz <= strlen(dst)). *
- * *
- ******************************************************************************/
-void zbx_strlcat(char *dst, const char *src, size_t siz)
-{
- while ('\0' != *dst)
- {
- dst++;
- siz--;
- }
-
- zbx_strlcpy(dst, src, siz);
-}
-
-/******************************************************************************
- * *
- * Purpose: copies utf-8 string + terminating zero character into specified *
- * buffer *
- * *
- * Return value: the number of copied bytes excluding terminating zero *
- * character. *
- * *
- * Comments: If the source string is larger than destination buffer then the *
- * string is truncated after last valid utf-8 character rather than *
- * byte. *
- * *
- ******************************************************************************/
-size_t zbx_strlcpy_utf8(char *dst, const char *src, size_t size)
-{
- size = zbx_strlen_utf8_nbytes(src, size - 1);
- memcpy(dst, src, size);
- dst[size] = '\0';
-
- return size;
-}
-
-/******************************************************************************
- * *
- * Purpose: dynamical formatted output conversion *
- * *
- * Return value: formatted string *
- * *
- * Comments: returns a pointer to allocated memory *
- * *
- ******************************************************************************/
-char *zbx_dvsprintf(char *dest, const char *f, va_list args)
-{
- char *string = NULL;
- int n, size = MAX_STRING_LEN >> 1;
-
- va_list curr;
-
- while (1)
- {
- string = (char *)zbx_malloc(string, size);
-
- va_copy(curr, args);
- n = vsnprintf(string, size, f, curr);
- va_end(curr);
-
- if (0 <= n && n < size)
- break;
-
- /* result was truncated */
- if (-1 == n)
- size = size * 3 / 2 + 1; /* the length is unknown */
- else
- size = n + 1; /* n bytes + trailing '\0' */
-
- zbx_free(string);
- }
-
- zbx_free(dest);
-
- return string;
-}
-
-/******************************************************************************
- * *
- * Purpose: dynamical formatted output conversion *
- * *
- * Return value: formatted string *
- * *
- * Comments: returns a pointer to allocated memory *
- * *
- ******************************************************************************/
-char *zbx_dsprintf(char *dest, const char *f, ...)
-{
- char *string;
- va_list args;
-
- va_start(args, f);
-
- string = zbx_dvsprintf(dest, f, args);
-
- va_end(args);
-
- return string;
-}
-
-/******************************************************************************
- * *
- * Purpose: dynamical cating of strings *
- * *
- * Return value: new pointer of string *
- * *
- * Comments: returns a pointer to allocated memory *
- * zbx_strdcat(NULL, "") will return "", not NULL! *
- * *
- ******************************************************************************/
-char *zbx_strdcat(char *dest, const char *src)
-{
- size_t len_dest, len_src;
-
- if (NULL == src)
- return dest;
-
- if (NULL == dest)
- return zbx_strdup(NULL, src);
-
- len_dest = strlen(dest);
- len_src = strlen(src);
-
- dest = (char *)zbx_realloc(dest, len_dest + len_src + 1);
-
- zbx_strlcpy(dest + len_dest, src, len_src + 1);
-
- return dest;
-}
-
-/******************************************************************************
- * *
- * Purpose: dynamical cating of formatted strings *
- * *
- * Return value: new pointer of string *
- * *
- * Comments: returns a pointer to allocated memory *
- * *
- ******************************************************************************/
-char *zbx_strdcatf(char *dest, const char *f, ...)
-{
- char *string, *result;
- va_list args;
-
- va_start(args, f);
- string = zbx_dvsprintf(NULL, f, args);
- va_end(args);
-
- result = zbx_strdcat(dest, string);
-
- zbx_free(string);
-
- return result;
-}
-
-/******************************************************************************
- * *
- * Purpose: check a byte stream for a valid hostname *
- * *
- * Parameters: hostname - pointer to the first char of hostname *
- * error - pointer to the error message (can be NULL) *
- * *
- * Return value: return SUCCEED if hostname is valid *
- * or FAIL if hostname contains invalid chars, is empty *
- * or is longer than ZBX_MAX_HOSTNAME_LEN *
- * *
- ******************************************************************************/
-int zbx_check_hostname(const char *hostname, char **error)
-{
- int len = 0;
-
- while ('\0' != hostname[len])
- {
- if (FAIL == is_hostname_char(hostname[len]))
- {
- if (NULL != error)
- *error = zbx_dsprintf(NULL, "name contains invalid character '%c'", hostname[len]);
- return FAIL;
- }
-
- len++;
- }
-
- if (0 == len)
- {
- if (NULL != error)
- *error = zbx_strdup(NULL, "name is empty");
- return FAIL;
- }
-
- if (ZBX_MAX_HOSTNAME_LEN < len)
- {
- if (NULL != error)
- *error = zbx_dsprintf(NULL, "name is too long (max %d characters)", ZBX_MAX_HOSTNAME_LEN);
- return FAIL;
- }
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: advances pointer to first invalid character in string *
- * ensuring that everything before it is a valid key *
- * *
- * e.g., system.run[cat /etc/passwd | awk -F: '{ print $1 }'] *
- * *
- * Parameters: exp - [IN/OUT] pointer to the first char of key *
- * *
- * e.g., {host:system.run[cat /etc/passwd | awk -F: '{ print $1 }'].last(0)} *
- * ^ *
- * Return value: returns FAIL only if no key is present (length 0), *
- * or the whole string is invalid. SUCCEED otherwise. *
- * *
- * Comments: the pointer is advanced to the first invalid character even if *
- * FAIL is returned (meaning there is a syntax error in item key). *
- * If necessary, the caller must keep a copy of pointer original *
- * value. *
- * *
- ******************************************************************************/
-int parse_key(const char **exp)
-{
- const char *s;
-
- for (s = *exp; SUCCEED == is_key_char(*s); s++)
- ;
-
- if (*exp == s) /* the key is empty */
- return FAIL;
-
- if ('[' == *s) /* for instance, net.tcp.port[,80] */
- {
- int state = 0; /* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
- int array = 0; /* array nest level */
-
- for (s++; '\0' != *s; s++)
- {
- switch (state)
- {
- /* init state */
- case 0:
- if (',' == *s)
- ;
- else if ('"' == *s)
- state = 1;
- else if ('[' == *s)
- {
- if (0 == array)
- array = 1;
- else
- goto fail; /* incorrect syntax: multi-level array */
- }
- else if (']' == *s && 0 != array)
- {
- array = 0;
- s++;
-
- while (' ' == *s) /* skip trailing spaces after closing ']' */
- s++;
-
- if (']' == *s)
- goto succeed;
-
- if (',' != *s)
- goto fail; /* incorrect syntax */
- }
- else if (']' == *s && 0 == array)
- goto succeed;
- else if (' ' != *s)
- state = 2;
- break;
- /* quoted */
- case 1:
- if ('"' == *s)
- {
- while (' ' == s[1]) /* skip trailing spaces after closing quotes */
- s++;
-
- if (0 == array && ']' == s[1])
- {
- s++;
- goto succeed;
- }
-
- if (',' != s[1] && !(0 != array && ']' == s[1]))
- {
- s++;
- goto fail; /* incorrect syntax */
- }
-
- state = 0;
- }
- else if ('\\' == *s && '"' == s[1])
- s++;
- break;
- /* unquoted */
- case 2:
- if (',' == *s || (']' == *s && 0 != array))
- {
- s--;
- state = 0;
- }
- else if (']' == *s && 0 == array)
- goto succeed;
- break;
- }
- }
-fail:
- *exp = s;
- return FAIL;
-succeed:
- s++;
- }
-
- *exp = s;
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: return hostname and key *
- * <hostname:>key *
- * *
- * Parameters: *
- * exp - pointer to the first char of hostname *
- * host:key[key params] *
- * ^ *
- * *
- * Return value: return SUCCEED or FAIL *
- * *
- ******************************************************************************/
-int parse_host_key(char *exp, char **host, char **key)
-{
- char *p, *s;
-
- if (NULL == exp || '\0' == *exp)
- return FAIL;
-
- for (p = exp, s = exp; '\0' != *p; p++) /* check for optional hostname */
- {
- if (':' == *p) /* hostname:vfs.fs.size[/,total]
- * --------^
- */
- {
- *p = '\0';
- *host = zbx_strdup(NULL, s);
- *p++ = ':';
-
- s = p;
- break;
- }
-
- if (SUCCEED != is_hostname_char(*p))
- break;
- }
-
- *key = zbx_strdup(NULL, s);
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: calculate the required size for the escaped string *
- * *
- * Parameters: src - [IN] null terminated source string *
- * charlist - [IN] null terminated to-be-escaped character list *
- * *
- * Return value: size of the escaped string *
- * *
- ******************************************************************************/
-size_t zbx_get_escape_string_len(const char *src, const char *charlist)
-{
- size_t sz = 0;
-
- for (; '\0' != *src; src++, sz++)
- {
- if (NULL != strchr(charlist, *src))
- sz++;
- }
-
- return sz;
-}
-
-/******************************************************************************
- * *
- * Purpose: escape characters in the source string *
- * *
- * Parameters: src - [IN] null terminated source string *
- * charlist - [IN] null terminated to-be-escaped character list *
- * *
- * Return value: the escaped string *
- * *
- ******************************************************************************/
-char *zbx_dyn_escape_string(const char *src, const char *charlist)
-{
- size_t sz;
- char *d, *dst = NULL;
-
- sz = zbx_get_escape_string_len(src, charlist) + 1;
-
- dst = (char *)zbx_malloc(dst, sz);
-
- for (d = dst; '\0' != *src; src++)
- {
- if (NULL != strchr(charlist, *src))
- *d++ = '\\';
-
- *d++ = *src;
- }
-
- *d = '\0';
-
- return dst;
-}
-
-/******************************************************************************
- * *
- * Purpose: escape characters in the source string to fixed output buffer *
- * *
- * Parameters: dst - [OUT] the output buffer *
- * len - [IN] the output buffer size *
- * src - [IN] null terminated source string *
- * charlist - [IN] null terminated to-be-escaped character list *
- * *
- * Return value: SUCCEED - the string was escaped successfully. *
- * FAIL - output buffer is too small. *
- * *
- ******************************************************************************/
-int zbx_escape_string(char *dst, size_t len, const char *src, const char *charlist)
-{
- for (; '\0' != *src; src++)
- {
- if (NULL != strchr(charlist, *src))
- {
- if (0 == --len)
- return FAIL;
- *dst++ = '\\';
- }
- else
- {
- if (0 == --len)
- return FAIL;
- }
-
- *dst++ = *src;
- }
-
- *dst = '\0';
-
- return SUCCEED;
-}
-
-char *zbx_age2str(int age)
-{
- size_t offset = 0;
- int days, hours, minutes, seconds;
- static char buffer[32];
-
- days = (int)((double)age / SEC_PER_DAY);
- hours = (int)((double)(age - days * SEC_PER_DAY) / SEC_PER_HOUR);
- minutes = (int)((double)(age - days * SEC_PER_DAY - hours * SEC_PER_HOUR) / SEC_PER_MIN);
- seconds = (int)((double)(age - days * SEC_PER_DAY - hours * SEC_PER_HOUR - minutes * SEC_PER_MIN));
-
- if (0 != days)
- offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dd ", days);
- if (0 != days || 0 != hours)
- offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dh ", hours);
- if (0 != days || 0 != hours || 0 != minutes)
- offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dm ", minutes);
-
- zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%ds", seconds);
-
- return buffer;
-}
-
-char *zbx_date2str(time_t date, const char *tz)
-{
- static char buffer[11];
- struct tm *tm;
-
- tm = zbx_localtime(&date, tz);
- zbx_snprintf(buffer, sizeof(buffer), "%.4d.%.2d.%.2d",
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday);
-
- return buffer;
-}
-
-char *zbx_time2str(time_t time, const char *tz)
-{
- static char buffer[9];
- struct tm *tm;
-
- tm = zbx_localtime(&time, tz);
- zbx_snprintf(buffer, sizeof(buffer), "%.2d:%.2d:%.2d",
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- return buffer;
-}
-
-int zbx_strncasecmp(const char *s1, const char *s2, size_t n)
-{
- if (NULL == s1 && NULL == s2)
- return 0;
-
- if (NULL == s1)
- return 1;
-
- if (NULL == s2)
- return -1;
-
- while (0 != n && '\0' != *s1 && '\0' != *s2 &&
- tolower((unsigned char)*s1) == tolower((unsigned char)*s2))
- {
- s1++;
- s2++;
- n--;
- }
-
- return 0 == n ? 0 : tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
-}
-
-char *zbx_strcasestr(const char *haystack, const char *needle)
-{
- size_t sz_h, sz_n;
- const char *p;
-
- if (NULL == needle || '\0' == *needle)
- return (char *)haystack;
-
- if (NULL == haystack || '\0' == *haystack)
- return NULL;
-
- sz_h = strlen(haystack);
- sz_n = strlen(needle);
- if (sz_h < sz_n)
- return NULL;
-
- for (p = haystack; p <= &haystack[sz_h - sz_n]; p++)
- {
- if (0 == zbx_strncasecmp(p, needle, sz_n))
- return (char *)p;
- }
-
- return NULL;
-}
-
-int cmp_key_id(const char *key_1, const char *key_2)
-{
- const char *p, *q;
-
- for (p = key_1, q = key_2; *p == *q && '\0' != *q && '[' != *q; p++, q++)
- ;
-
- return ('\0' == *p || '[' == *p) && ('\0' == *q || '[' == *q) ? SUCCEED : FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: Returns process name *
- * *
- * Parameters: proc_type - [IN] process type; ZBX_PROCESS_TYPE_* *
- * *
- * Comments: used in internals checks zabbix["process",...], process titles *
- * and log files *
- * *
- ******************************************************************************/
-const char *get_process_type_string(unsigned char proc_type)
-{
- switch (proc_type)
- {
- case ZBX_PROCESS_TYPE_POLLER:
- return "poller";
- case ZBX_PROCESS_TYPE_UNREACHABLE:
- return "unreachable poller";
- case ZBX_PROCESS_TYPE_IPMIPOLLER:
- return "ipmi poller";
- case ZBX_PROCESS_TYPE_PINGER:
- return "icmp pinger";
- case ZBX_PROCESS_TYPE_JAVAPOLLER:
- return "java poller";
- case ZBX_PROCESS_TYPE_HTTPPOLLER:
- return "http poller";
- case ZBX_PROCESS_TYPE_TRAPPER:
- return "trapper";
- case ZBX_PROCESS_TYPE_SNMPTRAPPER:
- return "snmp trapper";
- case ZBX_PROCESS_TYPE_PROXYPOLLER:
- return "proxy poller";
- case ZBX_PROCESS_TYPE_ESCALATOR:
- return "escalator";
- case ZBX_PROCESS_TYPE_HISTSYNCER:
- return "history syncer";
- case ZBX_PROCESS_TYPE_DISCOVERER:
- return "discoverer";
- case ZBX_PROCESS_TYPE_ALERTER:
- return "alerter";
- case ZBX_PROCESS_TYPE_TIMER:
- return "timer";
- case ZBX_PROCESS_TYPE_HOUSEKEEPER:
- return "housekeeper";
- case ZBX_PROCESS_TYPE_DATASENDER:
- return "data sender";
- case ZBX_PROCESS_TYPE_CONFSYNCER:
- return "configuration syncer";
- case ZBX_PROCESS_TYPE_HEARTBEAT:
- return "heartbeat sender";
- case ZBX_PROCESS_TYPE_SELFMON:
- return "self-monitoring";
- case ZBX_PROCESS_TYPE_VMWARE:
- return "vmware collector";
- case ZBX_PROCESS_TYPE_COLLECTOR:
- return "collector";
- case ZBX_PROCESS_TYPE_LISTENER:
- return "listener";
- case ZBX_PROCESS_TYPE_ACTIVE_CHECKS:
- return "active checks";
- case ZBX_PROCESS_TYPE_TASKMANAGER:
- return "task manager";
- case ZBX_PROCESS_TYPE_IPMIMANAGER:
- return "ipmi manager";
- case ZBX_PROCESS_TYPE_ALERTMANAGER:
- return "alert manager";
- case ZBX_PROCESS_TYPE_PREPROCMAN:
- return "preprocessing manager";
- case ZBX_PROCESS_TYPE_PREPROCESSOR:
- return "preprocessing worker";
- case ZBX_PROCESS_TYPE_LLDMANAGER:
- return "lld manager";
- case ZBX_PROCESS_TYPE_LLDWORKER:
- return "lld worker";
- case ZBX_PROCESS_TYPE_ALERTSYNCER:
- return "alert syncer";
- case ZBX_PROCESS_TYPE_HISTORYPOLLER:
- return "history poller";
- case ZBX_PROCESS_TYPE_AVAILMAN:
- return "availability manager";
- case ZBX_PROCESS_TYPE_REPORTMANAGER:
- return "report manager";
- case ZBX_PROCESS_TYPE_REPORTWRITER:
- return "report writer";
- case ZBX_PROCESS_TYPE_SERVICEMAN:
- return "service manager";
- case ZBX_PROCESS_TYPE_TRIGGERHOUSEKEEPER:
- return "trigger housekeeper";
- case ZBX_PROCESS_TYPE_HA_MANAGER:
- return "ha manager";
- case ZBX_PROCESS_TYPE_ODBCPOLLER:
- return "odbc poller";
- case ZBX_PROCESS_TYPE_MAIN:
- return "main";
- }
-
- THIS_SHOULD_NEVER_HAPPEN;
- exit(EXIT_FAILURE);
-}
-
-int get_process_type_by_name(const char *proc_type_str)
-{
- int i;
-
- for (i = 0; i < ZBX_PROCESS_TYPE_COUNT; i++)
- {
- if (0 == strcmp(proc_type_str, get_process_type_string((unsigned char)i)))
- return i;
- }
-
- for (i = ZBX_PROCESS_TYPE_EXT_FIRST; i <= ZBX_PROCESS_TYPE_EXT_LAST; i++)
- {
- if (0 == strcmp(proc_type_str, get_process_type_string((unsigned char)i)))
- return i;
- }
-
- return ZBX_PROCESS_TYPE_UNKNOWN;
-}
-
-const char *get_program_type_string(unsigned char program_type)
-{
- switch (program_type)
- {
- case ZBX_PROGRAM_TYPE_SERVER:
- return "server";
- case ZBX_PROGRAM_TYPE_PROXY_ACTIVE:
- case ZBX_PROGRAM_TYPE_PROXY_PASSIVE:
- return "proxy";
- case ZBX_PROGRAM_TYPE_AGENTD:
- return "agent";
- case ZBX_PROGRAM_TYPE_SENDER:
- return "sender";
- case ZBX_PROGRAM_TYPE_GET:
- return "get";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_permission_string(int perm)
-{
- switch (perm)
- {
- case PERM_DENY:
- return "dn";
- case PERM_READ:
- return "r";
- case PERM_READ_WRITE:
- return "rw";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_agent_type_string(zbx_item_type_t item_type)
-{
- switch (item_type)
- {
- case ITEM_TYPE_ZABBIX:
- return "Zabbix agent";
- case ITEM_TYPE_SNMP:
- return "SNMP agent";
- case ITEM_TYPE_IPMI:
- return "IPMI agent";
- case ITEM_TYPE_JMX:
- return "JMX agent";
- default:
- return "generic";
- }
-}
-
-const char *zbx_item_value_type_string(zbx_item_value_type_t value_type)
-{
- switch (value_type)
- {
- case ITEM_VALUE_TYPE_FLOAT:
- return "Numeric (float)";
- case ITEM_VALUE_TYPE_STR:
- return "Character";
- case ITEM_VALUE_TYPE_LOG:
- return "Log";
- case ITEM_VALUE_TYPE_UINT64:
- return "Numeric (unsigned)";
- case ITEM_VALUE_TYPE_TEXT:
- return "Text";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_interface_type_string(zbx_interface_type_t type)
-{
- switch (type)
- {
- case INTERFACE_TYPE_AGENT:
- return "Zabbix agent";
- case INTERFACE_TYPE_SNMP:
- return "SNMP";
- case INTERFACE_TYPE_IPMI:
- return "IPMI";
- case INTERFACE_TYPE_JMX:
- return "JMX";
- case INTERFACE_TYPE_OPT:
- return "optional";
- case INTERFACE_TYPE_ANY:
- return "any";
- case INTERFACE_TYPE_UNKNOWN:
- default:
- return "unknown";
- }
-}
-
-const char *zbx_sysinfo_ret_string(int ret)
-{
- switch (ret)
- {
- case SYSINFO_RET_OK:
- return "SYSINFO_SUCCEED";
- case SYSINFO_RET_FAIL:
- return "SYSINFO_FAIL";
- default:
- return "SYSINFO_UNKNOWN";
- }
-}
-
-const char *zbx_result_string(int result)
-{
- switch (result)
- {
- case SUCCEED:
- return "SUCCEED";
- case FAIL:
- return "FAIL";
- case CONFIG_ERROR:
- return "CONFIG_ERROR";
- case NOTSUPPORTED:
- return "NOTSUPPORTED";
- case NETWORK_ERROR:
- return "NETWORK_ERROR";
- case TIMEOUT_ERROR:
- return "TIMEOUT_ERROR";
- case AGENT_ERROR:
- return "AGENT_ERROR";
- case GATEWAY_ERROR:
- return "GATEWAY_ERROR";
- case SIG_ERROR:
- return "SIG_ERROR";
- case SYSINFO_RET_FAIL:
- return "SYSINFO_RET_FAIL";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_item_logtype_string(unsigned char logtype)
-{
- switch (logtype)
- {
- case ITEM_LOGTYPE_INFORMATION:
- return "Information";
- case ITEM_LOGTYPE_WARNING:
- return "Warning";
- case ITEM_LOGTYPE_ERROR:
- return "Error";
- case ITEM_LOGTYPE_FAILURE_AUDIT:
- return "Failure Audit";
- case ITEM_LOGTYPE_SUCCESS_AUDIT:
- return "Success Audit";
- case ITEM_LOGTYPE_CRITICAL:
- return "Critical";
- case ITEM_LOGTYPE_VERBOSE:
- return "Verbose";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_dservice_type_string(zbx_dservice_type_t service)
-{
- switch (service)
- {
- case SVC_SSH:
- return "SSH";
- case SVC_LDAP:
- return "LDAP";
- case SVC_SMTP:
- return "SMTP";
- case SVC_FTP:
- return "FTP";
- case SVC_HTTP:
- return "HTTP";
- case SVC_POP:
- return "POP";
- case SVC_NNTP:
- return "NNTP";
- case SVC_IMAP:
- return "IMAP";
- case SVC_TCP:
- return "TCP";
- case SVC_AGENT:
- return "Zabbix agent";
- case SVC_SNMPv1:
- return "SNMPv1 agent";
- case SVC_SNMPv2c:
- return "SNMPv2c agent";
- case SVC_SNMPv3:
- return "SNMPv3 agent";
- case SVC_ICMPPING:
- return "ICMP ping";
- case SVC_HTTPS:
- return "HTTPS";
- case SVC_TELNET:
- return "Telnet";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_alert_type_string(unsigned char type)
-{
- switch (type)
- {
- case ALERT_TYPE_MESSAGE:
- return "message";
- default:
- return "script";
- }
-}
-
-const char *zbx_alert_status_string(unsigned char type, unsigned char status)
-{
- switch (status)
- {
- case ALERT_STATUS_SENT:
- return (ALERT_TYPE_MESSAGE == type ? "sent" : "executed");
- case ALERT_STATUS_NOT_SENT:
- return "in progress";
- default:
- return "failed";
- }
-}
-
-const char *zbx_escalation_status_string(unsigned char status)
-{
- switch (status)
- {
- case ESCALATION_STATUS_ACTIVE:
- return "active";
- case ESCALATION_STATUS_SLEEP:
- return "sleep";
- case ESCALATION_STATUS_COMPLETED:
- return "completed";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_trigger_value_string(unsigned char value)
-{
- switch (value)
- {
- case TRIGGER_VALUE_PROBLEM:
- return "PROBLEM";
- case TRIGGER_VALUE_OK:
- return "OK";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_trigger_state_string(unsigned char state)
-{
- switch (state)
- {
- case TRIGGER_STATE_NORMAL:
- return "Normal";
- case TRIGGER_STATE_UNKNOWN:
- return "Unknown";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_item_state_string(unsigned char state)
-{
- switch (state)
- {
- case ITEM_STATE_NORMAL:
- return "Normal";
- case ITEM_STATE_NOTSUPPORTED:
- return "Not supported";
- default:
- return "unknown";
- }
-}
-
-const char *zbx_event_value_string(unsigned char source, unsigned char object, unsigned char value)
-{
- if (EVENT_SOURCE_TRIGGERS == source || EVENT_SOURCE_SERVICE == source)
- {
- switch (value)
- {
- case EVENT_STATUS_PROBLEM:
- return "PROBLEM";
- case EVENT_STATUS_RESOLVED:
- return "RESOLVED";
- default:
- return "unknown";
- }
- }
-
- if (EVENT_SOURCE_INTERNAL == source)
- {
- switch (object)
- {
- case EVENT_OBJECT_TRIGGER:
- return zbx_trigger_state_string(value);
- case EVENT_OBJECT_ITEM:
- case EVENT_OBJECT_LLDRULE:
- return zbx_item_state_string(value);
- }
- }
-
- return "unknown";
-}
-
-#if defined(_WINDOWS) || defined(__MINGW32__)
-/******************************************************************************
- * *
- * Parameters: encoding - [IN] non-empty string, code page identifier *
- * (as in libiconv or Windows SDK docs) *
- * codepage - [OUT] code page number *
- * *
- * Return value: SUCCEED on success *
- * FAIL on failure *
- * *
- ******************************************************************************/
-static int get_codepage(const char *encoding, unsigned int *codepage)
-{
- typedef struct
- {
- unsigned int codepage;
- const char *name;
- }
- codepage_t;
-
- int i;
- char buf[16];
- codepage_t cp[] = {{0, "ANSI"}, {37, "IBM037"}, {437, "IBM437"}, {500, "IBM500"}, {708, "ASMO-708"},
- {709, NULL}, {710, NULL}, {720, "DOS-720"}, {737, "IBM737"}, {775, "IBM775"}, {850, "IBM850"},
- {852, "IBM852"}, {855, "IBM855"}, {857, "IBM857"}, {858, "IBM00858"}, {860, "IBM860"},
- {861, "IBM861"}, {862, "DOS-862"}, {863, "IBM863"}, {864, "IBM864"}, {865, "IBM865"},
- {866, "CP866"}, {869, "IBM869"}, {870, "IBM870"}, {874, "WINDOWS-874"}, {875, "CP875"},
- {932, "SHIFT_JIS"}, {936, "GB2312"}, {949, "KS_C_5601-1987"}, {950, "BIG5"}, {1026, "IBM1026"},
- {1047, "IBM01047"}, {1140, "IBM01140"}, {1141, "IBM01141"}, {1142, "IBM01142"},
- {1143, "IBM01143"}, {1144, "IBM01144"}, {1145, "IBM01145"}, {1146, "IBM01146"},
- {1147, "IBM01147"}, {1148, "IBM01148"}, {1149, "IBM01149"}, {1200, "UTF-16"},
- {1201, "UNICODEFFFE"}, {1250, "WINDOWS-1250"}, {1251, "WINDOWS-1251"}, {1252, "WINDOWS-1252"},
- {1253, "WINDOWS-1253"}, {1254, "WINDOWS-1254"}, {1255, "WINDOWS-1255"}, {1256, "WINDOWS-1256"},
- {1257, "WINDOWS-1257"}, {1258, "WINDOWS-1258"}, {1361, "JOHAB"}, {10000, "MACINTOSH"},
- {10001, "X-MAC-JAPANESE"}, {10002, "X-MAC-CHINESETRAD"}, {10003, "X-MAC-KOREAN"},
- {10004, "X-MAC-ARABIC"}, {10005, "X-MAC-HEBREW"}, {10006, "X-MAC-GREEK"},
- {10007, "X-MAC-CYRILLIC"}, {10008, "X-MAC-CHINESESIMP"}, {10010, "X-MAC-ROMANIAN"},
- {10017, "X-MAC-UKRAINIAN"}, {10021, "X-MAC-THAI"}, {10029, "X-MAC-CE"},
- {10079, "X-MAC-ICELANDIC"}, {10081, "X-MAC-TURKISH"}, {10082, "X-MAC-CROATIAN"},
- {12000, "UTF-32"}, {12001, "UTF-32BE"}, {20000, "X-CHINESE_CNS"}, {20001, "X-CP20001"},
- {20002, "X_CHINESE-ETEN"}, {20003, "X-CP20003"}, {20004, "X-CP20004"}, {20005, "X-CP20005"},
- {20105, "X-IA5"}, {20106, "X-IA5-GERMAN"}, {20107, "X-IA5-SWEDISH"}, {20108, "X-IA5-NORWEGIAN"},
- {20127, "US-ASCII"}, {20261, "X-CP20261"}, {20269, "X-CP20269"}, {20273, "IBM273"},
- {20277, "IBM277"}, {20278, "IBM278"}, {20280, "IBM280"}, {20284, "IBM284"}, {20285, "IBM285"},
- {20290, "IBM290"}, {20297, "IBM297"}, {20420, "IBM420"}, {20423, "IBM423"}, {20424, "IBM424"},
- {20833, "X-EBCDIC-KOREANEXTENDED"}, {20838, "IBM-THAI"}, {20866, "KOI8-R"}, {20871, "IBM871"},
- {20880, "IBM880"}, {20905, "IBM905"}, {20924, "IBM00924"}, {20932, "EUC-JP"},
- {20936, "X-CP20936"}, {20949, "X-CP20949"}, {21025, "CP1025"}, {21027, NULL}, {21866, "KOI8-U"},
- {28591, "ISO-8859-1"}, {28592, "ISO-8859-2"}, {28593, "ISO-8859-3"}, {28594, "ISO-8859-4"},
- {28595, "ISO-8859-5"}, {28596, "ISO-8859-6"}, {28597, "ISO-8859-7"}, {28598, "ISO-8859-8"},
- {28599, "ISO-8859-9"}, {28603, "ISO-8859-13"}, {28605, "ISO-8859-15"}, {29001, "X-EUROPA"},
- {38598, "ISO-8859-8-I"}, {50220, "ISO-2022-JP"}, {50221, "CSISO2022JP"}, {50222, "ISO-2022-JP"},
- {50225, "ISO-2022-KR"}, {50227, "X-CP50227"}, {50229, NULL}, {50930, NULL}, {50931, NULL},
- {50933, NULL}, {50935, NULL}, {50936, NULL}, {50937, NULL}, {50939, NULL}, {51932, "EUC-JP"},
- {51936, "EUC-CN"}, {51949, "EUC-KR"}, {51950, NULL}, {52936, "HZ-GB-2312"}, {54936, "GB18030"},
- {57002, "X-ISCII-DE"}, {57003, "X-ISCII-BE"}, {57004, "X-ISCII-TA"}, {57005, "X-ISCII-TE"},
- {57006, "X-ISCII-AS"}, {57007, "X-ISCII-OR"}, {57008, "X-ISCII-KA"}, {57009, "X-ISCII-MA"},
- {57010, "X-ISCII-GU"}, {57011, "X-ISCII-PA"}, {65000, "UTF-7"}, {65001, "UTF-8"}, {0, NULL}};
-
- /* by name */
- for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
- {
- if (NULL == cp[i].name)
- continue;
-
- if (0 == strcmp(encoding, cp[i].name))
- {
- *codepage = cp[i].codepage;
- return SUCCEED;
- }
- }
-
- /* by number */
- for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
- {
- _itoa_s(cp[i].codepage, buf, sizeof(buf), 10);
- if (0 == strcmp(encoding, buf))
- {
- *codepage = cp[i].codepage;
- return SUCCEED;
- }
- }
-
- /* by 'cp' + number */
- for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
- {
- zbx_snprintf(buf, sizeof(buf), "cp%li", cp[i].codepage);
- if (0 == strcmp(encoding, buf))
- {
- *codepage = cp[i].codepage;
- return SUCCEED;
- }
- }
-
- return FAIL;
-}
-
-/* convert from selected code page to unicode */
-static wchar_t *zbx_to_unicode(unsigned int codepage, const char *cp_string)
-{
- wchar_t *wide_string = NULL;
- int wide_size;
-
- wide_size = MultiByteToWideChar(codepage, 0, cp_string, -1, NULL, 0);
- wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
-
- /* convert from cp_string to wide_string */
- MultiByteToWideChar(codepage, 0, cp_string, -1, wide_string, wide_size);
-
- return wide_string;
-}
-
-/* convert from Windows ANSI code page to unicode */
-wchar_t *zbx_acp_to_unicode(const char *acp_string)
-{
- return zbx_to_unicode(CP_ACP, acp_string);
-}
-
-/* convert from Windows OEM code page to unicode */
-wchar_t *zbx_oemcp_to_unicode(const char *oemcp_string)
-{
- return zbx_to_unicode(CP_OEMCP, oemcp_string);
-}
-
-int zbx_acp_to_unicode_static(const char *acp_string, wchar_t *wide_string, int wide_size)
-{
- /* convert from acp_string to wide_string */
- if (0 == MultiByteToWideChar(CP_ACP, 0, acp_string, -1, wide_string, wide_size))
- return FAIL;
-
- return SUCCEED;
-}
-
-/* convert from UTF-8 to unicode */
-wchar_t *zbx_utf8_to_unicode(const char *utf8_string)
-{
- return zbx_to_unicode(CP_UTF8, utf8_string);
-}
-
-/* convert from unicode to utf8 */
-char *zbx_unicode_to_utf8(const wchar_t *wide_string)
-{
- char *utf8_string = NULL;
- int utf8_size;
-
- utf8_size = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL);
- utf8_string = (char *)zbx_malloc(utf8_string, (size_t)utf8_size);
-
- /* convert from wide_string to utf8_string */
- WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_size, NULL, NULL);
-
- return utf8_string;
-}
-
-/* convert from unicode to utf8 */
-char *zbx_unicode_to_utf8_static(const wchar_t *wide_string, char *utf8_string, int utf8_size)
-{
- /* convert from wide_string to utf8_string */
- if (0 == WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_size, NULL, NULL))
- *utf8_string = '\0';
-
- return utf8_string;
-}
-#endif
-
-void zbx_strlower(char *str)
-{
- for (; '\0' != *str; str++)
- *str = tolower(*str);
-}
-
-void zbx_strupper(char *str)
-{
- for (; '\0' != *str; str++)
- *str = toupper(*str);
-}
-
-#if defined(_WINDOWS) || defined(__MINGW32__)
-#include "log.h"
-char *convert_to_utf8(char *in, size_t in_size, const char *encoding)
-{
-#define STATIC_SIZE 1024
- wchar_t wide_string_static[STATIC_SIZE], *wide_string = NULL;
- int wide_size;
- char *utf8_string = NULL;
- int utf8_size;
- unsigned int codepage;
- int bom_detected = 0;
-
- /* try to guess encoding using BOM if it exists */
- if (3 <= in_size && 0 == strncmp("\xef\xbb\xbf", in, 3))
- {
- bom_detected = 1;
-
- if ('\0' == *encoding)
- encoding = "UTF-8";
- }
- else if (2 <= in_size && 0 == strncmp("\xff\xfe", in, 2))
- {
- bom_detected = 1;
-
- if ('\0' == *encoding)
- encoding = "UTF-16";
- }
- else if (2 <= in_size && 0 == strncmp("\xfe\xff", in, 2))
- {
- bom_detected = 1;
-
- if ('\0' == *encoding)
- encoding = "UNICODEFFFE";
- }
-
- if ('\0' == *encoding || FAIL == get_codepage(encoding, &codepage))
- {
- utf8_size = (int)in_size + 1;
- utf8_string = zbx_malloc(utf8_string, utf8_size);
- memcpy(utf8_string, in, in_size);
- utf8_string[in_size] = '\0';
- return utf8_string;
- }
-
- zabbix_log(LOG_LEVEL_DEBUG, "convert_to_utf8() in_size:%d encoding:'%s' codepage:%u", in_size, encoding,
- codepage);
-
- if (65001 == codepage)
- {
- /* remove BOM */
- if (bom_detected)
- in += 3;
- }
-
- if (1200 == codepage) /* Unicode UTF-16, little-endian byte order */
- {
- wide_size = (int)in_size / 2;
-
- /* remove BOM */
- if (bom_detected)
- {
- in += 2;
- wide_size--;
- }
-
- wide_string = (wchar_t *)in;
-
- }
- else if (1201 == codepage) /* unicodeFFFE UTF-16, big-endian byte order */
- {
- wchar_t *wide_string_be;
- int i;
-
- wide_size = (int)in_size / 2;
-
- /* remove BOM */
- if (bom_detected)
- {
- in += 2;
- wide_size--;
- }
-
- wide_string_be = (wchar_t *)in;
-
- if (wide_size > STATIC_SIZE)
- wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
- else
- wide_string = wide_string_static;
-
- /* convert from big-endian 'in' to little-endian 'wide_string' */
- for (i = 0; i < wide_size; i++)
- wide_string[i] = ((wide_string_be[i] << 8) & 0xff00) | ((wide_string_be[i] >> 8) & 0xff);
- }
- else
- {
- wide_size = MultiByteToWideChar(codepage, 0, in, (int)in_size, NULL, 0);
-
- if (wide_size > STATIC_SIZE)
- wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
- else
- wide_string = wide_string_static;
-
- /* convert from 'in' to 'wide_string' */
- MultiByteToWideChar(codepage, 0, in, (int)in_size, wide_string, wide_size);
- }
-
- utf8_size = WideCharToMultiByte(CP_UTF8, 0, wide_string, wide_size, NULL, 0, NULL, NULL);
- utf8_string = (char *)zbx_malloc(utf8_string, (size_t)utf8_size + 1/* '\0' */);
-
- /* convert from 'wide_string' to 'utf8_string' */
- WideCharToMultiByte(CP_UTF8, 0, wide_string, wide_size, utf8_string, utf8_size, NULL, NULL);
- utf8_string[utf8_size] = '\0';
-
- if (wide_string != wide_string_static && wide_string != (wchar_t *)in)
- zbx_free(wide_string);
-
- return utf8_string;
-}
-#elif defined(HAVE_ICONV)
-char *convert_to_utf8(char *in, size_t in_size, const char *encoding)
-{
- iconv_t cd;
- size_t in_size_left, out_size_left, sz, out_alloc = 0;
- const char to_code[] = "UTF-8";
- char *out = NULL, *p;
-
- out_alloc = in_size + 1;
- p = out = (char *)zbx_malloc(out, out_alloc);
-
- /* try to guess encoding using BOM if it exists */
- if ('\0' == *encoding)
- {
- if (3 <= in_size && 0 == strncmp("\xef\xbb\xbf", in, 3))
- {
- encoding = "UTF-8";
- }
- else if (2 <= in_size && 0 == strncmp("\xff\xfe", in, 2))
- {
- encoding = "UTF-16LE";
- }
- else if (2 <= in_size && 0 == strncmp("\xfe\xff", in, 2))
- {
- encoding = "UTF-16BE";
- }
- }
-
- if ('\0' == *encoding || (iconv_t)-1 == (cd = iconv_open(to_code, encoding)))
- {
- memcpy(out, in, in_size);
- out[in_size] = '\0';
- return out;
- }
-
- in_size_left = in_size;
- out_size_left = out_alloc - 1;
-
- while ((size_t)(-1) == iconv(cd, &in, &in_size_left, &p, &out_size_left))
- {
- if (E2BIG != errno)
- break;
-
- sz = (size_t)(p - out);
- out_alloc += in_size;
- out_size_left += in_size;
- p = out = (char *)zbx_realloc(out, out_alloc);
- p += sz;
- }
-
- *p = '\0';
-
- iconv_close(cd);
-
- /* remove BOM */
- if (3 <= p - out && 0 == strncmp("\xef\xbb\xbf", out, 3))
- memmove(out, out + 3, (size_t)(p - out - 2));
-
- return out;
-}
-#endif /* HAVE_ICONV */
-
-size_t zbx_strlen_utf8(const char *text)
-{
- size_t n = 0;
-
- while ('\0' != *text)
- {
- if (0x80 != (0xc0 & *text++))
- n++;
- }
-
- return n;
-}
-
-char *zbx_strshift_utf8(char *text, size_t num)
-{
- while ('\0' != *text && 0 < num)
- {
- if (0x80 != (0xc0 & *(++text)))
- num--;
- }
-
- return text;
-}
-
-/******************************************************************************
- * *
- * Purpose: Returns the size (in bytes) of a UTF-8 encoded character or 0 *
- * if the character is not a valid UTF-8. *
- * *
- * Parameters: text - [IN] pointer to the 1st byte of UTF-8 character *
- * *
- ******************************************************************************/
-size_t zbx_utf8_char_len(const char *text)
-{
- if (0 == (*text & 0x80)) /* ASCII */
- return 1;
- else if (0xc0 == (*text & 0xe0)) /* 11000010-11011111 starts a 2-byte sequence */
- return 2;
- else if (0xe0 == (*text & 0xf0)) /* 11100000-11101111 starts a 3-byte sequence */
- return 3;
- else if (0xf0 == (*text & 0xf8)) /* 11110000-11110100 starts a 4-byte sequence */
- return 4;
-#if ZBX_MAX_BYTES_IN_UTF8_CHAR != 4
-# error "zbx_utf8_char_len() is not synchronized with ZBX_MAX_BYTES_IN_UTF8_CHAR"
-#endif
- return 0; /* not a valid UTF-8 character */
-}
-
-/******************************************************************************
- * *
- * Purpose: calculates number of bytes in utf8 text limited by utf8_maxlen *
- * characters *
- * *
- ******************************************************************************/
-size_t zbx_strlen_utf8_nchars(const char *text, size_t utf8_maxlen)
-{
- size_t sz = 0, csz = 0;
- const char *next;
-
- while ('\0' != *text && 0 < utf8_maxlen && 0 != (csz = zbx_utf8_char_len(text)))
- {
- next = text + csz;
- while (next > text)
- {
- if ('\0' == *text++)
- return sz;
- }
- sz += csz;
- utf8_maxlen--;
- }
-
- return sz;
-}
-
-/******************************************************************************
- * *
- * Purpose: calculates number of bytes in utf8 text limited by maxlen bytes *
- * *
- ******************************************************************************/
-size_t zbx_strlen_utf8_nbytes(const char *text, size_t maxlen)
-{
- size_t sz;
-
- sz = strlen(text);
-
- if (sz > maxlen)
- {
- sz = maxlen;
-
- /* ensure that the string is not cut in the middle of UTF-8 sequence */
- while (0x80 == (0xc0 & text[sz]) && 0 < sz)
- sz--;
- }
-
- return sz;
-}
-
-/******************************************************************************
- * *
- * Purpose: calculates number of chars in utf8 text limited by maxlen bytes *
- * *
- ******************************************************************************/
-size_t zbx_charcount_utf8_nbytes(const char *text, size_t maxlen)
-{
- size_t n = 0;
-
- maxlen = zbx_strlen_utf8_nbytes(text, maxlen);
-
- while ('\0' != *text && maxlen > 0)
- {
- if (0x80 != (0xc0 & *text++))
- n++;
-
- maxlen--;
- }
-
- return n;
-}
-
-/******************************************************************************
- * *
- * Purpose: check UTF-8 sequences *
- * *
- * Parameters: text - [IN] pointer to the string *
- * *
- * Return value: SUCCEED if string is valid or FAIL otherwise *
- * *
- ******************************************************************************/
-int zbx_is_utf8(const char *text)
-{
- unsigned int utf32;
- unsigned char *utf8;
- size_t i, mb_len, expecting_bytes = 0;
-
- while ('\0' != *text)
- {
- /* single ASCII character */
- if (0 == (*text & 0x80))
- {
- text++;
- continue;
- }
-
- /* unexpected continuation byte or invalid UTF-8 bytes '\xfe' & '\xff' */
- if (0x80 == (*text & 0xc0) || 0xfe == (*text & 0xfe))
- return FAIL;
-
- /* multibyte sequence */
-
- utf8 = (unsigned char *)text;
-
- if (0xc0 == (*text & 0xe0)) /* 2-bytes multibyte sequence */
- expecting_bytes = 1;
- else if (0xe0 == (*text & 0xf0)) /* 3-bytes multibyte sequence */
- expecting_bytes = 2;
- else if (0xf0 == (*text & 0xf8)) /* 4-bytes multibyte sequence */
- expecting_bytes = 3;
- else if (0xf8 == (*text & 0xfc)) /* 5-bytes multibyte sequence */
- expecting_bytes = 4;
- else if (0xfc == (*text & 0xfe)) /* 6-bytes multibyte sequence */
- expecting_bytes = 5;
-
- mb_len = expecting_bytes + 1;
- text++;
-
- for (; 0 != expecting_bytes; expecting_bytes--)
- {
- /* not a continuation byte */
- if (0x80 != (*text++ & 0xc0))
- return FAIL;
- }
-
- /* overlong sequence */
- if (0xc0 == (utf8[0] & 0xfe) ||
- (0xe0 == utf8[0] && 0x00 == (utf8[1] & 0x20)) ||
- (0xf0 == utf8[0] && 0x00 == (utf8[1] & 0x30)) ||
- (0xf8 == utf8[0] && 0x00 == (utf8[1] & 0x38)) ||
- (0xfc == utf8[0] && 0x00 == (utf8[1] & 0x3c)))
- {
- return FAIL;
- }
-
- utf32 = 0;
-
- if (0xc0 == (utf8[0] & 0xe0))
- utf32 = utf8[0] & 0x1f;
- else if (0xe0 == (utf8[0] & 0xf0))
- utf32 = utf8[0] & 0x0f;
- else if (0xf0 == (utf8[0] & 0xf8))
- utf32 = utf8[0] & 0x07;
- else if (0xf8 == (utf8[0] & 0xfc))
- utf32 = utf8[0] & 0x03;
- else if (0xfc == (utf8[0] & 0xfe))
- utf32 = utf8[0] & 0x01;
-
- for (i = 1; i < mb_len; i++)
- {
- utf32 <<= 6;
- utf32 += utf8[i] & 0x3f;
- }
-
- /* according to the Unicode standard the high and low
- * surrogate halves used by UTF-16 (U+D800 through U+DFFF)
- * and values above U+10FFFF are not legal
- */
- if (utf32 > 0x10ffff || 0xd800 == (utf32 & 0xf800))
- return FAIL;
- }
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: replace invalid UTF-8 sequences of bytes with '?' character *
- * *
- * Parameters: text - [IN/OUT] pointer to the first char *
- * *
- ******************************************************************************/
-void zbx_replace_invalid_utf8(char *text)
-{
- char *out = text;
-
- while ('\0' != *text)
- {
- if (0 == (*text & 0x80)) /* single ASCII character */
- *out++ = *text++;
- else if (0x80 == (*text & 0xc0) || /* unexpected continuation byte */
- 0xfe == (*text & 0xfe)) /* invalid UTF-8 bytes '\xfe' & '\xff' */
- {
- *out++ = ZBX_UTF8_REPLACE_CHAR;
- text++;
- }
- else /* multibyte sequence */
- {
- unsigned int utf32;
- unsigned char *utf8 = (unsigned char *)out;
- size_t i, mb_len, expecting_bytes = 0;
- int ret = SUCCEED;
-
- if (0xc0 == (*text & 0xe0)) /* 2-bytes multibyte sequence */
- expecting_bytes = 1;
- else if (0xe0 == (*text & 0xf0)) /* 3-bytes multibyte sequence */
- expecting_bytes = 2;
- else if (0xf0 == (*text & 0xf8)) /* 4-bytes multibyte sequence */
- expecting_bytes = 3;
- else if (0xf8 == (*text & 0xfc)) /* 5-bytes multibyte sequence */
- expecting_bytes = 4;
- else if (0xfc == (*text & 0xfe)) /* 6-bytes multibyte sequence */
- expecting_bytes = 5;
-
- *out++ = *text++;
-
- for (; 0 != expecting_bytes; expecting_bytes--)
- {
- if (0x80 != (*text & 0xc0)) /* not a continuation byte */
- {
- ret = FAIL;
- break;
- }
-
- *out++ = *text++;
- }
-
- mb_len = out - (char *)utf8;
-
- if (SUCCEED == ret)
- {
- if (0xc0 == (utf8[0] & 0xfe) || /* overlong sequence */
- (0xe0 == utf8[0] && 0x00 == (utf8[1] & 0x20)) ||
- (0xf0 == utf8[0] && 0x00 == (utf8[1] & 0x30)) ||
- (0xf8 == utf8[0] && 0x00 == (utf8[1] & 0x38)) ||
- (0xfc == utf8[0] && 0x00 == (utf8[1] & 0x3c)))
- {
- ret = FAIL;
- }
- }
-
- if (SUCCEED == ret)
- {
- utf32 = 0;
-
- if (0xc0 == (utf8[0] & 0xe0))
- utf32 = utf8[0] & 0x1f;
- else if (0xe0 == (utf8[0] & 0xf0))
- utf32 = utf8[0] & 0x0f;
- else if (0xf0 == (utf8[0] & 0xf8))
- utf32 = utf8[0] & 0x07;
- else if (0xf8 == (utf8[0] & 0xfc))
- utf32 = utf8[0] & 0x03;
- else if (0xfc == (utf8[0] & 0xfe))
- utf32 = utf8[0] & 0x01;
-
- for (i = 1; i < mb_len; i++)
- {
- utf32 <<= 6;
- utf32 += utf8[i] & 0x3f;
- }
-
- /* according to the Unicode standard the high and low
- * surrogate halves used by UTF-16 (U+D800 through U+DFFF)
- * and values above U+10FFFF are not legal
- */
- if (utf32 > 0x10ffff || 0xd800 == (utf32 & 0xf800))
- ret = FAIL;
- }
-
- if (SUCCEED != ret)
- {
- out -= mb_len;
- *out++ = ZBX_UTF8_REPLACE_CHAR;
- }
- }
- }
-
- *out = '\0';
-}
-
-void dos2unix(char *str)
-{
- char *o = str;
-
- while ('\0' != *str)
- {
- if ('\r' == str[0] && '\n' == str[1]) /* CR+LF (Windows) */
- str++;
- *o++ = *str++;
- }
- *o = '\0';
-}
-
-int is_ascii_string(const char *str)
-{
- while ('\0' != *str)
- {
- if (0 != ((1 << 7) & *str)) /* check for range 0..127 */
- return FAIL;
-
- str++;
- }
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: wrap long string at specified position with linefeeds *
- * *
- * Parameters: src - input string *
- * maxline - maximum length of a line *
- * delim - delimiter to use as linefeed (default "\n" if NULL) *
- * *
- * Return value: newly allocated copy of input string with linefeeds *
- * *
- * Comments: allocates memory *
- * *
- ******************************************************************************/
-char *str_linefeed(const char *src, size_t maxline, const char *delim)
-{
- size_t src_size, dst_size, delim_size, left;
- int feeds; /* number of feeds */
- char *dst = NULL; /* output with linefeeds */
- const char *p_src;
- char *p_dst;
-
- assert(NULL != src);
- assert(0 < maxline);
-
- /* default delimiter */
- if (NULL == delim)
- delim = "\n";
-
- src_size = strlen(src);
- delim_size = strlen(delim);
-
- /* make sure we don't feed the last line */
- feeds = (int)(src_size / maxline - (0 != src_size % maxline || 0 == src_size ? 0 : 1));
-
- left = src_size - feeds * maxline;
- dst_size = src_size + feeds * delim_size + 1;
-
- /* allocate memory for output */
- dst = (char *)zbx_malloc(dst, dst_size);
-
- p_src = src;
- p_dst = dst;
-
- /* copy chunks appending linefeeds */
- while (0 < feeds--)
- {
- memcpy(p_dst, p_src, maxline);
- p_src += maxline;
- p_dst += maxline;
-
- memcpy(p_dst, delim, delim_size);
- p_dst += delim_size;
- }
-
- if (0 < left)
- {
- /* copy what's left */
- memcpy(p_dst, p_src, left);
- p_dst += left;
- }
-
- *p_dst = '\0';
-
- return dst;
-}
-
-/******************************************************************************
- * *
- * Purpose: initialize dynamic string array *
- * *
- * Parameters: arr - a pointer to array of strings *
- * *
- * Comments: allocates memory, calls assert() if that fails *
- * *
- ******************************************************************************/
-void zbx_strarr_init(char ***arr)
-{
- *arr = (char **)zbx_malloc(*arr, sizeof(char *));
- **arr = NULL;
-}
-
-/******************************************************************************
- * *
- * Purpose: add a string to dynamic string array *
- * *
- * Parameters: arr - a pointer to array of strings *
- * entry - string to add *
- * *
- * Comments: allocates memory, calls assert() if that fails *
- * *
- ******************************************************************************/
-void zbx_strarr_add(char ***arr, const char *entry)
-{
- int i;
-
- assert(entry);
-
- for (i = 0; NULL != (*arr)[i]; i++)
- ;
-
- *arr = (char **)zbx_realloc(*arr, sizeof(char *) * (i + 2));
-
- (*arr)[i] = zbx_strdup((*arr)[i], entry);
- (*arr)[++i] = NULL;
-}
-
-/******************************************************************************
- * *
- * Purpose: free dynamic string array memory *
- * *
- * Parameters: arr - array of strings *
- * *
- ******************************************************************************/
-void zbx_strarr_free(char ***arr)
-{
- char **p;
-
- for (p = *arr; NULL != *p; p++)
- zbx_free(*p);
- zbx_free(*arr);
-}
-
-/******************************************************************************
- * *
- * Purpose: replace data block with 'value' *
- * *
- * Parameters: data - [IN/OUT] pointer to the string *
- * l - [IN] left position of the block *
- * r - [IN/OUT] right position of the block *
- * value - [IN] the string to replace the block with *
- * *
- ******************************************************************************/
-void zbx_replace_string(char **data, size_t l, size_t *r, const char *value)
-{
- size_t sz_data, sz_block, sz_value;
- char *src, *dst;
-
- sz_value = strlen(value);
- sz_block = *r - l + 1;
-
- if (sz_value != sz_block)
- {
- sz_data = *r + strlen(*data + *r);
- sz_data += sz_value - sz_block;
-
- if (sz_value > sz_block)
- *data = (char *)zbx_realloc(*data, sz_data + 1);
-
- src = *data + l + sz_block;
- dst = *data + l + sz_value;
-
- memmove(dst, src, sz_data - l - sz_value + 1);
-
- *r = l + sz_value - 1;
- }
-
- memcpy(&(*data)[l], value, sz_value);
-}
-
-/******************************************************************************
- * *
- * Purpose: remove whitespace surrounding a string list item delimiters *
- * *
- * Parameters: list - the list (a string containing items separated by *
- * delimiter) *
- * delimiter - the list delimiter *
- * *
- ******************************************************************************/
-void zbx_trim_str_list(char *list, char delimiter)
-{
- /* NB! strchr(3): "terminating null byte is considered part of the string" */
- const char *whitespace = " \t";
- char *out, *in;
-
- out = in = list;
-
- while ('\0' != *in)
- {
- /* trim leading spaces from list item */
- while ('\0' != *in && NULL != strchr(whitespace, *in))
- in++;
-
- /* copy list item */
- while (delimiter != *in && '\0' != *in)
- *out++ = *in++;
-
- /* trim trailing spaces from list item */
- if (out > list)
- {
- while (NULL != strchr(whitespace, *(--out)))
- ;
- out++;
- }
- if (delimiter == *in)
- *out++ = *in++;
- }
- *out = '\0';
-}
-
-/******************************************************************************
- * *
- * Purpose: *
- * compares two strings where any of them can be a NULL pointer *
- * *
- * Parameters: same as strcmp() except NULL values are allowed *
- * *
- * Return value: same as strcmp() *
- * *
- * Comments: NULL is less than any string *
- * *
- ******************************************************************************/
-int zbx_strcmp_null(const char *s1, const char *s2)
-{
- if (NULL == s1)
- return NULL == s2 ? 0 : -1;
-
- if (NULL == s2)
- return 1;
-
- return strcmp(s1, s2);
-}
-
-/******************************************************************************
- * *
- * Purpose: *
- * parses user macro and finds its end position and context location *
- * *
- * Parameters: *
- * macro - [IN] the macro to parse *
- * macro_r - [OUT] the position of ending '}' character *
- * context_l - [OUT] the position of context start character (first non *
- * space character after context separator ':') *
- * 0 if macro does not have context specified. *
- * context_r - [OUT] the position of context end character (either the *
- * ending '"' for quoted context values or the last *
- * character before the ending '}' character) *
- * 0 if macro does not have context specified. *
- * context_op - [OUT] the context matching operator (optional): *
- * CONDITION_OPERATOR_EQUAL *
- * CONDITION_OPERATOR_REGEXP *
- * *
- * Return value: *
- * SUCCEED - the macro was parsed successfully. *
- * FAIL - the macro parsing failed, the content of output variables *
- * is not defined. *
- * *
- ******************************************************************************/
-int zbx_user_macro_parse(const char *macro, int *macro_r, int *context_l, int *context_r, unsigned char *context_op)
-{
- int i;
-
- /* find the end of macro name by skipping {$ characters and iterating through */
- /* valid macro name characters */
- for (i = 2; SUCCEED == is_macro_char(macro[i]); i++)
- ;
-
- /* check for empty macro name */
- if (2 == i)
- return FAIL;
-
- if ('}' == macro[i])
- {
- /* no macro context specified, parsing done */
- *macro_r = i;
- *context_l = 0;
- *context_r = 0;
-
- if (NULL != context_op)
- *context_op = CONDITION_OPERATOR_EQUAL;
-
- return SUCCEED;
- }
-
- /* fail if the next character is not a macro context separator */
- if (':' != macro[i])
- return FAIL;
-
- i++;
- if (NULL != context_op)
- {
- if (0 == strncmp(macro + i, ZBX_MACRO_REGEX_PREFIX, ZBX_CONST_STRLEN(ZBX_MACRO_REGEX_PREFIX)))
- {
- *context_op = CONDITION_OPERATOR_REGEXP;
- i += ZBX_CONST_STRLEN(ZBX_MACRO_REGEX_PREFIX);
- }
- else
- *context_op = CONDITION_OPERATOR_EQUAL;
- }
-
- /* skip the whitespace after macro context separator */
- while (' ' == macro[i])
- i++;
-
- *context_l = i;
-
- if ('"' == macro[i])
- {
- i++;
-
- /* process quoted context */
- for (; '"' != macro[i]; i++)
- {
- if ('\0' == macro[i])
- return FAIL;
-
- if ('\\' == macro[i] && '"' == macro[i + 1])
- i++;
- }
-
- *context_r = i;
-
- while (' ' == macro[++i])
- ;
- }
- else
- {
- /* process unquoted context */
- for (; '}' != macro[i]; i++)
- {
- if ('\0' == macro[i])
- return FAIL;
- }
-
- *context_r = i - 1;
- }
-
- if ('}' != macro[i])
- return FAIL;
-
- *macro_r = i;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: *
- * parses user macro {$MACRO:<context>} into {$MACRO} and <context> *
- * strings *
- * *
- * Parameters: *
- * macro - [IN] the macro to parse *
- * name - [OUT] the macro name without context *
- * context - [OUT] the unquoted macro context, NULL for macros without *
- * context *
- * length - [OUT] the length of parsed macro (optional) *
- * context_op - [OUT] the context matching operator (optional): *
- * CONDITION_OPERATOR_EQUAL *
- * CONDITION_OPERATOR_REGEXP *
- * *
- * Return value: *
- * SUCCEED - the macro was parsed successfully *
- * FAIL - the macro parsing failed, invalid parameter syntax *
- * *
- ******************************************************************************/
-int zbx_user_macro_parse_dyn(const char *macro, char **name, char **context, int *length, unsigned char *context_op)
-{
- const char *ptr;
- int macro_r, context_l, context_r;
- size_t len;
-
- if (SUCCEED != zbx_user_macro_parse(macro, &macro_r, &context_l, &context_r, context_op))
- return FAIL;
-
- zbx_free(*context);
-
- if (0 != context_l)
- {
- ptr = macro + context_l;
-
- /* find the context separator ':' by stripping spaces before context */
- while (' ' == *(--ptr))
- ;
-
- /* remove regex: prefix from macro name for regex contexts */
- if (NULL != context_op && CONDITION_OPERATOR_REGEXP == *context_op)
- ptr -= ZBX_CONST_STRLEN(ZBX_MACRO_REGEX_PREFIX);
-
- /* extract the macro name and close with '}' character */
- len = ptr - macro + 1;
- *name = (char *)zbx_realloc(*name, len + 1);
- memcpy(*name, macro, len - 1);
- (*name)[len - 1] = '}';
- (*name)[len] = '\0';
-
- *context = zbx_user_macro_unquote_context_dyn(macro + context_l, context_r - context_l + 1);
- }
- else
- {
- *name = (char *)zbx_realloc(*name, macro_r + 2);
- zbx_strlcpy(*name, macro, macro_r + 2);
- }
-
- if (NULL != length)
- *length = macro_r + 1;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: *
- * extracts the macro context unquoting if necessary *
- * *
- * Parameters: *
- * context - [IN] the macro context inside a user macro *
- * len - [IN] the macro context length (including quotes for quoted *
- * contexts) *
- * *
- * Return value: *
- * A string containing extracted macro context. This string must be freed *
- * by the caller. *
- * *
- ******************************************************************************/
-char *zbx_user_macro_unquote_context_dyn(const char *context, int len)
-{
- int quoted = 0;
- char *buffer, *ptr;
-
- ptr = buffer = (char *)zbx_malloc(NULL, len + 1);
-
- if ('"' == *context)
- {
- quoted = 1;
- context++;
- len--;
- }
-
- while (0 < len)
- {
- if (1 == quoted && '\\' == *context && '"' == context[1])
- {
- context++;
- len--;
- }
-
- *ptr++ = *context++;
- len--;
- }
-
- if (1 == quoted)
- ptr--;
-
- *ptr = '\0';
-
- return buffer;
-}
-
-/******************************************************************************
- * *
- * Purpose: *
- * quotes user macro context if necessary *
- * *
- * Parameters: *
- * context - [IN] the macro context *
- * force_quote - [IN] if non zero then context quoting is enforced *
- * error - [OUT] the error message *
- * *
- * Return value: *
- * A string containing quoted macro context on success, NULL on error. *
- * *
- ******************************************************************************/
-char *zbx_user_macro_quote_context_dyn(const char *context, int force_quote, char **error)
-{
- int len, quotes = 0;
- char *buffer, *ptr_buffer;
- const char *ptr_context = context, *start = context;
-
- if ('"' == *ptr_context || ' ' == *ptr_context)
- force_quote = 1;
-
- for (; '\0' != *ptr_context; ptr_context++)
- {
- if ('}' == *ptr_context)
- force_quote = 1;
-
- if ('"' == *ptr_context)
- quotes++;
- }
-
- if (0 == force_quote)
- return zbx_strdup(NULL, context);
-
- len = (int)strlen(context) + 2 + quotes;
- ptr_buffer = buffer = (char *)zbx_malloc(NULL, len + 1);
-
- *ptr_buffer++ = '"';
-
- while ('\0' != *context)
- {
- if ('"' == *context)
- *ptr_buffer++ = '\\';
-
- *ptr_buffer++ = *context++;
- }
-
- if ('\\' == *(ptr_buffer - 1))
- {
- *error = zbx_dsprintf(*error, "quoted context \"%s\" cannot end with '\\' character", start);
- zbx_free(buffer);
- return NULL;
- }
-
- *ptr_buffer++ = '"';
- *ptr_buffer++ = '\0';
-
- return buffer;
-}
-
-/******************************************************************************
- * *
- * Purpose: escape single quote in shell command arguments *
- * *
- * Parameters: arg - [IN] the argument to escape *
- * *
- * Return value: The escaped argument. *
- * *
- ******************************************************************************/
-char *zbx_dyn_escape_shell_single_quote(const char *arg)
-{
- int len = 1; /* include terminating zero character */
- const char *pin;
- char *arg_esc, *pout;
-
- for (pin = arg; '\0' != *pin; pin++)
- {
- if ('\'' == *pin)
- len += 3;
- len++;
- }
-
- pout = arg_esc = (char *)zbx_malloc(NULL, len);
-
- for (pin = arg; '\0' != *pin; pin++)
- {
- if ('\'' == *pin)
- {
- *pout++ = '\'';
- *pout++ = '\\';
- *pout++ = '\'';
- *pout++ = '\'';
- }
- else
- *pout++ = *pin;
- }
-
- *pout = '\0';
-
- return arg_esc;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses function name *
- * *
- * Parameters: expr - [IN] the function expression: func(p1, p2,...) *
- * length - [OUT] the function name length or the amount of *
- * characters that can be safely skipped *
- * *
- * Return value: SUCCEED - the function name was successfully parsed *
- * FAIL - failed to parse function name *
- * *
- ******************************************************************************/
-static int function_parse_name(const char *expr, size_t *length)
-{
- const char *ptr;
-
- for (ptr = expr; SUCCEED == is_function_char(*ptr); ptr++)
- ;
-
- *length = ptr - expr;
-
- return ptr != expr && '(' == *ptr ? SUCCEED : FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses function parameter *
- * *
- * Parameters: expr - [IN] pre-validated function parameter list *
- * param_pos - [OUT] the parameter position, excluding leading *
- * whitespace *
- * length - [OUT] the parameter length including trailing *
- * whitespace for unquoted parameter *
- * sep_pos - [OUT] the parameter separator character *
- * (',' or '\0' or ')') position *
- * *
- ******************************************************************************/
-void zbx_function_param_parse(const char *expr, size_t *param_pos, size_t *length, size_t *sep_pos)
-{
- const char *ptr = expr;
-
- /* skip the leading whitespace */
- while (' ' == *ptr)
- ptr++;
-
- *param_pos = ptr - expr;
-
- if ('"' == *ptr) /* quoted parameter */
- {
- for (ptr++; '"' != *ptr || '\\' == *(ptr - 1); ptr++)
- ;
-
- *length = ++ptr - expr - *param_pos;
-
- /* skip trailing whitespace to find the next parameter */
- while (' ' == *ptr)
- ptr++;
- }
- else /* unquoted parameter */
- {
- for (ptr = expr; '\0' != *ptr && ')' != *ptr && ',' != *ptr; ptr++)
- ;
-
- *length = ptr - expr - *param_pos;
- }
-
- *sep_pos = ptr - expr;
-}
-
-/******************************************************************************
- * *
- * Purpose: unquotes function parameter *
- * *
- * Parameters: param - [IN] the parameter to unquote *
- * len - [IN] the parameter length *
- * quoted - [OUT] the flag that specifies whether parameter was *
- * quoted before extraction *
- * *
- * Return value: The unquoted parameter. This value must be freed by the *
- * caller. *
- * *
- ******************************************************************************/
-char *zbx_function_param_unquote_dyn(const char *param, size_t len, int *quoted)
-{
- char *out;
-
- out = (char *)zbx_malloc(NULL, len + 1);
-
- if (0 == (*quoted = (0 != len && '"' == *param)))
- {
- /* unquoted parameter - simply copy it */
- memcpy(out, param, len);
- out[len] = '\0';
- }
- else
- {
- /* quoted parameter - remove enclosing " and replace \" with " */
- const char *pin;
- char *pout = out;
-
- for (pin = param + 1; (size_t)(pin - param) < len - 1; pin++)
- {
- if ('\\' == pin[0] && '"' == pin[1])
- pin++;
-
- *pout++ = *pin;
- }
-
- *pout = '\0';
- }
-
- return out;
-}
-
-/******************************************************************************
- * *
- * Purpose: quotes function parameter *
- * *
- * Parameters: param - [IN/OUT] function parameter *
- * forced - [IN] 1 - enclose parameter in " even if it does not *
- * contain any special characters *
- * 0 - do nothing if the parameter does not *
- * contain any special characters *
- * *
- * Return value: SUCCEED - if parameter was successfully quoted or quoting *
- * was not necessary *
- * FAIL - if parameter needs to but cannot be quoted due to *
- * backslash in the end *
- * *
- ******************************************************************************/
-int zbx_function_param_quote(char **param, int forced)
-{
- size_t sz_src, sz_dst;
-
- if (0 == forced && '"' != **param && ' ' != **param && NULL == strchr(*param, ',') &&
- NULL == strchr(*param, ')'))
- {
- return SUCCEED;
- }
-
- if (0 != (sz_src = strlen(*param)) && '\\' == (*param)[sz_src - 1])
- return FAIL;
-
- sz_dst = zbx_get_escape_string_len(*param, "\"") + 3;
-
- *param = (char *)zbx_realloc(*param, sz_dst);
-
- (*param)[--sz_dst] = '\0';
- (*param)[--sz_dst] = '"';
-
- while (0 < sz_src)
- {
- (*param)[--sz_dst] = (*param)[--sz_src];
- if ('"' == (*param)[sz_src])
- (*param)[--sz_dst] = '\\';
- }
- (*param)[--sz_dst] = '"';
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: return parameter by index (Nparam) from parameter list (params) *
- * *
- * Parameters: *
- * params - [IN] parameter list *
- * Nparam - [IN] requested parameter index (from 1) *
- * *
- * Return value: *
- * NULL - requested parameter missing *
- * otherwise - requested parameter *
- * *
- ******************************************************************************/
-char *zbx_function_get_param_dyn(const char *params, int Nparam)
-{
- const char *ptr;
- size_t sep_pos, params_len;
- char *out = NULL;
- int idx = 0;
-
- params_len = strlen(params) + 1;
-
- for (ptr = params; ++idx <= Nparam && ptr < params + params_len; ptr += sep_pos + 1)
- {
- size_t param_pos, param_len;
- int quoted;
-
- zbx_function_param_parse(ptr, &param_pos, &param_len, &sep_pos);
-
- if (idx == Nparam)
- out = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, &quoted);
- }
-
- return out;
-}
-
-/******************************************************************************
- * *
- * Purpose: validate parameters and give position of terminator if found and *
- * not quoted *
- * *
- * Parameters: expr - [IN] string to parse that contains parameters *
- * *
- * terminator - [IN] use ')' if parameters end with *
- * parenthesis or '\0' if ends with NULL *
- * terminator *
- * par_r - [OUT] position of the terminator if found *
- * lpp_offset - [OUT] offset of the last parsed parameter *
- * lpp_len - [OUT] length of the last parsed parameter *
- * *
- * Return value: SUCCEED - closing parenthesis was found or other custom *
- * terminator and not quoted and return info about a *
- * last processed parameter. *
- * FAIL - does not look like a valid function parameter *
- * list and return info about a last processed *
- * parameter. *
- * *
- ******************************************************************************/
-static int function_validate_parameters(const char *expr, char terminator, size_t *par_r, size_t *lpp_offset,
- size_t *lpp_len)
-{
-#define ZBX_FUNC_PARAM_NEXT 0
-#define ZBX_FUNC_PARAM_QUOTED 1
-#define ZBX_FUNC_PARAM_UNQUOTED 2
-#define ZBX_FUNC_PARAM_POSTQUOTED 3
-
- const char *ptr;
- int state = ZBX_FUNC_PARAM_NEXT;
-
- *lpp_offset = 0;
-
- for (ptr = expr; '\0' != *ptr; ptr++)
- {
- if (terminator == *ptr && ZBX_FUNC_PARAM_QUOTED != state)
- {
- *par_r = ptr - expr;
- return SUCCEED;
- }
-
- switch (state)
- {
- case ZBX_FUNC_PARAM_NEXT:
- *lpp_offset = ptr - expr;
- if ('"' == *ptr)
- state = ZBX_FUNC_PARAM_QUOTED;
- else if (' ' != *ptr && ',' != *ptr)
- state = ZBX_FUNC_PARAM_UNQUOTED;
- break;
- case ZBX_FUNC_PARAM_QUOTED:
- if ('"' == *ptr && '\\' != *(ptr - 1))
- state = ZBX_FUNC_PARAM_POSTQUOTED;
- break;
- case ZBX_FUNC_PARAM_UNQUOTED:
- if (',' == *ptr)
- state = ZBX_FUNC_PARAM_NEXT;
- break;
- case ZBX_FUNC_PARAM_POSTQUOTED:
- if (',' == *ptr)
- {
- state = ZBX_FUNC_PARAM_NEXT;
- }
- else if (' ' != *ptr)
- {
- *lpp_len = ptr - (expr + *lpp_offset);
- return FAIL;
- }
- break;
- default:
- THIS_SHOULD_NEVER_HAPPEN;
- }
- }
-
- *lpp_len = ptr - (expr + *lpp_offset);
-
- if (terminator == *ptr && ZBX_FUNC_PARAM_QUOTED != state)
- {
- *par_r = ptr - expr;
- return SUCCEED;
- }
-
- return FAIL;
-
-#undef ZBX_FUNC_PARAM_NEXT
-#undef ZBX_FUNC_PARAM_QUOTED
-#undef ZBX_FUNC_PARAM_UNQUOTED
-#undef ZBX_FUNC_PARAM_POSTQUOTED
-}
-
-/******************************************************************************
- * *
- * Purpose: given the position of opening function parenthesis find the *
- * position of a closing one *
- * *
- * Parameters: expr - [IN] string to parse *
- * par_l - [IN] position of the opening parenthesis *
- * par_r - [OUT] position of the closing parenthesis *
- * lpp_offset - [OUT] offset of the last parsed parameter *
- * lpp_len - [OUT] length of the last parsed parameter *
- * *
- * Return value: SUCCEED - closing parenthesis was found *
- * FAIL - string after par_l does not look like a valid *
- * function parameter list *
- * *
- ******************************************************************************/
-static int function_match_parenthesis(const char *expr, size_t par_l, size_t *par_r, size_t *lpp_offset,
- size_t *lpp_len)
-{
- if (SUCCEED == function_validate_parameters(expr + par_l + 1, ')', par_r, lpp_offset, lpp_len))
- {
- *par_r += par_l + 1;
- return SUCCEED;
- }
-
- *lpp_offset += par_l + 1;
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: validate parameters that end with '\0' *
- * *
- * Parameters: expr - [IN] string to parse that contains parameters *
- * length - [OUT] length of parameters *
- * *
- * Return value: SUCCEED - null termination encountered when quotes are *
- * closed and no other error *
- * FAIL - does not look like a valid *
- * function parameter list *
- * *
- ******************************************************************************/
-int zbx_function_validate_parameters(const char *expr, size_t *length)
-{
- size_t offset, len;
-
- return function_validate_parameters(expr, '\0', length, &offset, &len);
-}
-
-/******************************************************************************
- * *
- * Purpose: check whether expression starts with a valid function *
- * *
- * Parameters: expr - [IN] string to parse *
- * par_l - [OUT] position of the opening parenthesis *
- * or the amount of characters to skip *
- * par_r - [OUT] position of the closing parenthesis *
- * error - [OUT] error message *
- * max_error_len - [IN] error size *
- * *
- * Return value: SUCCEED - string starts with a valid function *
- * FAIL - string does not start with a function and par_l *
- * characters can be safely skipped *
- * *
- ******************************************************************************/
-static int zbx_function_validate(const char *expr, size_t *par_l, size_t *par_r, char *error, int max_error_len)
-{
- size_t lpp_offset, lpp_len;
-
- /* try to validate function name */
- if (SUCCEED == function_parse_name(expr, par_l))
- {
- /* now we know the position of '(', try to find ')' */
- if (SUCCEED == function_match_parenthesis(expr, *par_l, par_r, &lpp_offset, &lpp_len))
- return SUCCEED;
-
- if (NULL != error && *par_l > *par_r)
- {
- zbx_snprintf(error, max_error_len, "Incorrect function '%.*s' expression. "
- "Check expression part starting from: %.*s",
- (int)*par_l, expr, (int)lpp_len, expr + lpp_offset);
-
- return FAIL;
- }
- }
-
- if (NULL != error)
- zbx_snprintf(error, max_error_len, "Incorrect function expression: %s", expr);
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: performs natural comparison of two strings *
- * *
- * Parameters: s1 - [IN] the first string *
- * s2 - [IN] the second string *
- * *
- * Return value: 0: the strings are equal *
- * <0: s1 < s2 *
- * >0: s1 > s2 *
- * *
- ******************************************************************************/
-int zbx_strcmp_natural(const char *s1, const char *s2)
-{
- int ret, value1, value2;
-
- for (;'\0' != *s1 && '\0' != *s2; s1++, s2++)
- {
- if (0 == isdigit(*s1) || 0 == isdigit(*s2))
- {
- if (0 != (ret = *s1 - *s2))
- return ret;
-
- continue;
- }
-
- value1 = 0;
- while (0 != isdigit(*s1))
- value1 = value1 * 10 + *s1++ - '0';
-
- value2 = 0;
- while (0 != isdigit(*s2))
- value2 = value2 * 10 + *s2++ - '0';
-
- if (0 != (ret = value1 - value2))
- return ret;
-
- if ('\0' == *s1 || '\0' == *s2)
- break;
- }
-
- return *s1 - *s2;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses user macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the user macro was parsed successfully *
- * FAIL - macro does not point at valid user macro *
- * *
- * Comments: If the macro points at valid user macro in the expression then *
- * the generic token fields are set and the token->data.user_macro *
- * structure is filled with user macro specific data. *
- * *
- ******************************************************************************/
-static int token_parse_user_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- size_t offset;
- int macro_r, context_l, context_r;
- zbx_token_user_macro_t *data;
-
- if (SUCCEED != zbx_user_macro_parse(macro, &macro_r, &context_l, &context_r, NULL))
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = ZBX_TOKEN_USER_MACRO;
- token->loc.l = offset;
- token->loc.r = offset + macro_r;
-
- /* initialize token data */
- data = &token->data.user_macro;
- data->name.l = offset + 2;
-
- if (0 != context_l)
- {
- const char *ptr = macro + context_l;
-
- /* find the context separator ':' by stripping spaces before context */
- while (' ' == *(--ptr))
- ;
-
- data->name.r = offset + (ptr - macro) - 1;
-
- data->context.l = offset + context_l;
- data->context.r = offset + context_r;
- }
- else
- {
- data->name.r = token->loc.r - 1;
- data->context.l = 0;
- data->context.r = 0;
- }
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses lld macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the lld macro was parsed successfully *
- * FAIL - macro does not point at valid lld macro *
- * *
- * Comments: If the macro points at valid lld macro in the expression then *
- * the generic token fields are set and the token->data.lld_macro *
- * structure is filled with lld macro specific data. *
- * *
- ******************************************************************************/
-static int token_parse_lld_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- const char *ptr;
- size_t offset;
- zbx_token_macro_t *data;
-
- /* find the end of lld macro by validating its name until the closing bracket } */
- for (ptr = macro + 2; '}' != *ptr; ptr++)
- {
- if ('\0' == *ptr)
- return FAIL;
-
- if (SUCCEED != is_macro_char(*ptr))
- return FAIL;
- }
-
- /* empty macro name */
- if (2 == ptr - macro)
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = ZBX_TOKEN_LLD_MACRO;
- token->loc.l = offset;
- token->loc.r = offset + (ptr - macro);
-
- /* initialize token data */
- data = &token->data.lld_macro;
- data->name.l = offset + 2;
- data->name.r = token->loc.r - 1;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses expression macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * simple_macro_find - [IN] pass simple macro flag to *
- * zbx_token_find() *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the expression macro was parsed successfully *
- * FAIL - macro does not point at valid expression macro *
- * *
- * Comments: If the macro points at valid expression macro in the expression *
- * then the generic token fields are set and the *
- * token->data.expression_macro structure is filled with expression *
- * macro specific data. *
- * Contents of macro are not validated because expression macro may *
- * contain user macro contexts and item keys with string arguments. *
- * *
- ******************************************************************************/
-static int token_parse_expression_macro(const char *expression, const char *macro, int simple_macro_find,
- zbx_token_t *token)
-{
- const char *ptr;
- size_t offset;
- zbx_token_expression_macro_t *data;
- int quoted = 0;
- zbx_token_search_t token_search = ZBX_TOKEN_SEARCH_BASIC;
-
- if (0 != simple_macro_find)
- token_search |= ZBX_TOKEN_SEARCH_SIMPLE_MACRO;
-
- for (ptr = macro + 2; '\0' != *ptr ; ptr++)
- {
- if (1 == quoted)
- {
- if ('\\' == *ptr)
- {
- if ('\0' == *(++ptr))
- break;
- continue;
- }
-
- if ('"' == *ptr)
- quoted = 0;
-
- continue;
- }
-
- if ('{' == *ptr)
- {
- zbx_token_t tmp;
-
- /* nested expression macros are not supported */
- if ('?' == ptr[1])
- continue;
-
- if (SUCCEED == zbx_token_find(ptr, 0, &tmp, token_search))
- {
- switch (tmp.type)
- {
- case ZBX_TOKEN_MACRO:
- case ZBX_TOKEN_LLD_MACRO:
- case ZBX_TOKEN_LLD_FUNC_MACRO:
- case ZBX_TOKEN_USER_MACRO:
- case ZBX_TOKEN_SIMPLE_MACRO:
- ptr += tmp.loc.r;
- break;
- }
- }
- }
- else if ('}' == *ptr)
- {
- /* empty macro */
- if (ptr == macro + 2)
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = ZBX_TOKEN_EXPRESSION_MACRO;
- token->loc.l = offset;
- token->loc.r = offset + (ptr - macro);
-
- /* initialize token data */
- data = &token->data.expression_macro;
- data->expression.l = offset + 2;
- data->expression.r = token->loc.r - 1;
-
- return SUCCEED;
- }
- else if ('"' == *ptr)
- quoted = 1;
- }
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses object id token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the object id was parsed successfully *
- * FAIL - macro does not point at valid object id *
- * *
- * Comments: If the macro points at valid object id in the expression then *
- * the generic token fields are set and the token->data.objectid *
- * structure is filled with object id specific data. *
- * *
- ******************************************************************************/
-static int token_parse_objectid(const char *expression, const char *macro, zbx_token_t *token)
-{
- const char *ptr;
- size_t offset;
- zbx_token_macro_t *data;
-
- /* find the end of object id by checking if it contains digits until the closing bracket } */
- for (ptr = macro + 1; '}' != *ptr; ptr++)
- {
- if ('\0' == *ptr)
- return FAIL;
-
- if (0 == isdigit(*ptr))
- return FAIL;
- }
-
- /* empty object id */
- if (1 == ptr - macro)
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = ZBX_TOKEN_OBJECTID;
- token->loc.l = offset;
- token->loc.r = offset + (ptr - macro);
-
- /* initialize token data */
- data = &token->data.objectid;
- data->name.l = offset + 1;
- data->name.r = token->loc.r - 1;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses macro name segment *
- * *
- * Parameters: expression - [IN] the expression *
- * segment - [IN] the segment start *
- * strict - [OUT] 1 - macro contains only standard characters *
- * (upper case alphanumeric characters, *
- * dots and underscores) *
- * 0 - the last segment contains lowercase or *
- * quoted characters *
- * next - [OUT] offset of the next character after the *
- * segment *
- * *
- * Return value: SUCCEED - the segment was parsed successfully *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int token_parse_macro_segment(const char *expression, const char *segment, int *strict, int *next)
-{
- const char *ptr = segment;
-
- if ('"' != *ptr)
- {
- for (*strict = 1; '\0' != *ptr; ptr++)
- {
- if (0 != isalpha((unsigned char)*ptr))
- {
- if (0 == isupper((unsigned char)*ptr))
- *strict = 0;
- continue;
- }
-
- if (0 != isdigit((unsigned char)*ptr))
- continue;
-
- if ('_' == *ptr)
- continue;
-
- break;
- }
-
- /* check for empty segment */
- if (ptr == segment)
- return FAIL;
-
- *next = ptr - expression;
- }
- else
- {
- for (*strict = 0, ptr++; '"' != *ptr; ptr++)
- {
- if ('\0' == *ptr)
- return FAIL;
-
- if ('\\' == *ptr)
- {
- ptr++;
- if ('\\' != *ptr && '"' != *ptr)
- return FAIL;
- }
- }
-
- /* check for empty segment */
- if (1 == ptr - segment)
- return FAIL;
-
- *next = ptr - expression + 1;
- }
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses macro name *
- * *
- * Parameters: expression - [IN] the expression *
- * ptr - [IN] the beginning of macro name *
- * loc - [OUT] the macro name location *
- * *
- * Return value: SUCCEED - the simple macro was parsed successfully *
- * FAIL - macro does not point at valid macro *
- * *
- * Comments: Note that the character following macro name must be inspected *
- * to draw any conclusions. For example for normal macros it must *
- * be '}' or it's not a valid macro. *
- * *
- ******************************************************************************/
-static int token_parse_macro_name(const char *expression, const char *ptr, zbx_strloc_t *loc)
-{
- int strict, offset, ret;
-
- loc->l = ptr - expression;
-
- while (SUCCEED == (ret = token_parse_macro_segment(expression, ptr, &strict, &offset)))
- {
- if (0 == strict && expression + loc->l == ptr)
- return FAIL;
-
- ptr = expression + offset;
-
- if ('.' != *ptr || 0 == strict)
- {
- loc->r = ptr - expression - 1;
- break;
- }
- ptr++;
- }
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses normal macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the simple macro was parsed successfully *
- * FAIL - macro does not point at valid macro *
- * *
- * Comments: If the macro points at valid macro in the expression then *
- * the generic token fields are set and the token->data.macro *
- * structure is filled with simple macro specific data. *
- * *
- ******************************************************************************/
-static int token_parse_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- zbx_strloc_t loc;
- zbx_token_macro_t *data;
-
- if (SUCCEED != token_parse_macro_name(expression, macro + 1, &loc))
- return FAIL;
-
- if ('}' != expression[loc.r + 1])
- return FAIL;
-
- /* initialize token */
- token->type = ZBX_TOKEN_MACRO;
- token->loc.l = loc.l - 1;
- token->loc.r = loc.r + 1;
-
- /* initialize token data */
- data = &token->data.macro;
- data->name = loc;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses function inside token *
- * *
- * Parameters: expression - [IN] the expression *
- * func - [IN] the beginning of the function *
- * func_loc - [OUT] the function location relative to the *
- * expression (including parameters) *
- * *
- * Return value: SUCCEED - the function was parsed successfully *
- * FAIL - func does not point at valid function *
- * *
- ******************************************************************************/
-static int token_parse_function(const char *expression, const char *func,
- zbx_strloc_t *func_loc, zbx_strloc_t *func_param)
-{
- size_t par_l, par_r;
-
- if (SUCCEED != zbx_function_validate(func, &par_l, &par_r, NULL, 0))
- return FAIL;
-
- func_loc->l = func - expression;
- func_loc->r = func_loc->l + par_r;
-
- func_param->l = func_loc->l + par_l;
- func_param->r = func_loc->l + par_r;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses function macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * func - [IN] the beginning of the macro function in the *
- * token *
- * token - [OUT] the token data *
- * token_type - [IN] type flag ZBX_TOKEN_FUNC_MACRO or *
- * ZBX_TOKEN_LLD_FUNC_MACRO *
- * *
- * Return value: SUCCEED - the function macro was parsed successfully *
- * FAIL - macro does not point at valid function macro *
- * *
- * Comments: If the macro points at valid function macro in the expression *
- * then the generic token fields are set and the *
- * token->data.func_macro or token->data.lld_func_macro structures *
- * depending on token type flag are filled with function macro *
- * specific data. *
- * *
- ******************************************************************************/
-static int token_parse_func_macro(const char *expression, const char *macro, const char *func,
- zbx_token_t *token, int token_type)
-{
- zbx_strloc_t func_loc, func_param;
- zbx_token_func_macro_t *data;
- const char *ptr;
- size_t offset;
-
- if ('\0' == *func)
- return FAIL;
-
- if (SUCCEED != token_parse_function(expression, func, &func_loc, &func_param))
- return FAIL;
-
- ptr = expression + func_loc.r + 1;
-
- /* skip trailing whitespace and verify that token ends with } */
-
- while (' ' == *ptr)
- ptr++;
-
- if ('}' != *ptr)
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = token_type;
- token->loc.l = offset;
- token->loc.r = ptr - expression;
-
- /* initialize token data */
- data = ZBX_TOKEN_FUNC_MACRO == token_type ? &token->data.func_macro : &token->data.lld_func_macro;
- data->macro.l = offset + 1;
- data->macro.r = func_loc.l - 2;
-
- data->func = func_loc;
- data->func_param = func_param;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses simple macro token with given key *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * key - [IN] the beginning of host key inside the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the function macro was parsed successfully *
- * FAIL - macro does not point at valid simple macro *
- * *
- * Comments: Simple macros have format {<host>:<key>.<func>(<params>)} *
- * {HOST.HOSTn} macro can be used for host name and {ITEM.KEYn} *
- * macro can be used for item key. *
- * *
- * If the macro points at valid simple macro in the expression *
- * then the generic token fields are set and the *
- * token->data.simple_macro structure is filled with simple macro *
- * specific data. *
- * *
- ******************************************************************************/
-static int token_parse_simple_macro_key(const char *expression, const char *macro, const char *key,
- zbx_token_t *token)
-{
- size_t offset;
- zbx_token_simple_macro_t *data;
- const char *ptr = key;
- zbx_strloc_t key_loc, func_loc, func_param;
-
- if (SUCCEED != parse_key(&ptr))
- {
- zbx_token_t key_token;
-
- if (SUCCEED != token_parse_macro(expression, key, &key_token))
- return FAIL;
-
- ptr = expression + key_token.loc.r + 1;
- }
-
- /* If the key is without parameters, then parse_key() will move cursor past function name - */
- /* at the start of its parameters. In this case move cursor back before function. */
- if ('(' == *ptr)
- {
- while ('.' != *(--ptr))
- ;
- }
-
- /* check for empty key */
- if (0 == ptr - key)
- return FAIL;
-
- if (SUCCEED != token_parse_function(expression, ptr + 1, &func_loc, &func_param))
- return FAIL;
-
- key_loc.l = key - expression;
- key_loc.r = ptr - expression - 1;
-
- ptr = expression + func_loc.r + 1;
-
- /* skip trailing whitespace and verify that token ends with } */
-
- while (' ' == *ptr)
- ptr++;
-
- if ('}' != *ptr)
- return FAIL;
-
- offset = macro - expression;
-
- /* initialize token */
- token->type = ZBX_TOKEN_SIMPLE_MACRO;
- token->loc.l = offset;
- token->loc.r = ptr - expression;
-
- /* initialize token data */
- data = &token->data.simple_macro;
- data->host.l = offset + 1;
- data->host.r = offset + (key - macro) - 2;
-
- data->key = key_loc;
- data->func = func_loc;
- data->func_param = func_param;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parses simple macro token *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the simple macro was parsed successfully *
- * FAIL - macro does not point at valid simple macro *
- * *
- * Comments: Simple macros have format {<host>:<key>.<func>(<params>)} *
- * {HOST.HOSTn} macro can be used for host name and {ITEM.KEYn} *
- * macro can be used for item key. *
- * *
- * If the macro points at valid simple macro in the expression *
- * then the generic token fields are set and the *
- * token->data.simple_macro structure is filled with simple macro *
- * specific data. *
- * *
- ******************************************************************************/
-static int token_parse_simple_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- const char *ptr;
-
- /* Find the end of host name by validating its name until the closing bracket }. */
- /* {HOST.HOSTn} macro usage in the place of host name is handled by nested macro parsing. */
- for (ptr = macro + 1; ':' != *ptr; ptr++)
- {
- if ('\0' == *ptr)
- return FAIL;
-
- if (SUCCEED != is_hostname_char(*ptr))
- return FAIL;
- }
-
- /* check for empty host name */
- if (1 == ptr - macro)
- return FAIL;
-
- return token_parse_simple_macro_key(expression, macro, ptr + 1, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: parses token with nested macros *
- * *
- * Parameters: expression - [IN] the expression *
- * macro - [IN] the beginning of the token *
- * simple_macro_find - [IN] pass simple macro flag to *
- * zbx_token_find() *
- * token - [OUT] the token data *
- * *
- * Return value: SUCCEED - the token was parsed successfully *
- * FAIL - macro does not point at valid function or simple *
- * macro *
- * *
- * Comments: This function parses token with a macro inside it. There are *
- * three types of nested macros - low-level discovery function *
- * macros, function macros and a specific case of simple macros *
- * where {HOST.HOSTn} macro is used as host name. *
- * *
- * If the macro points at valid macro in the expression then *
- * the generic token fields are set and either the *
- * token->data.lld_func_macro, token->data.func_macro or *
- * token->data.simple_macro (depending on token type) structure is *
- * filled with macro specific data. *
- * *
- ******************************************************************************/
-static int token_parse_nested_macro(const char *expression, const char *macro, int simple_macro_find,
- zbx_token_t *token)
-{
- const char *ptr;
-
- if ('#' == macro[2])
- {
- /* find the end of the nested macro by validating its name until the closing bracket '}' */
- for (ptr = macro + 3; '}' != *ptr; ptr++)
- {
- if ('\0' == *ptr)
- return FAIL;
-
- if (SUCCEED != is_macro_char(*ptr))
- return FAIL;
- }
-
- /* empty macro name */
- if (3 == ptr - macro)
- return FAIL;
- }
- else if ('?' == macro[2])
- {
- zbx_token_t expr_token;
- zbx_token_search_t token_search;
-
- token_search = ZBX_TOKEN_SEARCH_EXPRESSION_MACRO;
-
- if (0 != simple_macro_find)
- token_search |= ZBX_TOKEN_SEARCH_SIMPLE_MACRO;
-
- if (SUCCEED != zbx_token_find(macro, 1, &expr_token, token_search) ||
- ZBX_TOKEN_EXPRESSION_MACRO != expr_token.type ||
- 1 != expr_token.loc.l)
- {
- return FAIL;
- }
-
- ptr = macro + expr_token.loc.r;
- }
- else
- {
- zbx_strloc_t loc;
-
- if (SUCCEED != token_parse_macro_name(expression, macro + 2, &loc))
- return FAIL;
-
- if ('}' != expression[loc.r + 1])
- return FAIL;
-
- ptr = expression + loc.r + 1;
- }
-
- /* Determine the token type. */
- /* Nested macros formats: */
- /* low-level discovery function macros {{#MACRO}.function()} */
- /* function macros {{MACRO}.function()} */
- /* simple macros {{MACRO}:key.function()} */
- if ('.' == ptr[1])
- {
- return token_parse_func_macro(expression, macro, ptr + 2, token, '#' == macro[2] ?
- ZBX_TOKEN_LLD_FUNC_MACRO : ZBX_TOKEN_FUNC_MACRO);
- }
- else if (0 != simple_macro_find && '#' != macro[2] && ':' == ptr[1])
- return token_parse_simple_macro_key(expression, macro, ptr + 2, token);
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: finds token {} inside expression starting at specified position *
- * also searches for reference if requested *
- * *
- * Parameters: expression - [IN] the expression *
- * pos - [IN] the starting position *
- * token - [OUT] the token data *
- * token_search - [IN] specify if references will be searched *
- * *
- * Return value: SUCCEED - the token was parsed successfully *
- * FAIL - expression does not contain valid token. *
- * *
- * Comments: The token field locations are specified as offsets from the *
- * beginning of the expression. *
- * *
- * Simply iterating through tokens can be done with: *
- * *
- * zbx_token_t token = {0}; *
- * *
- * while (SUCCEED == zbx_token_find(expression, token.loc.r + 1, *
- * &token)) *
- * { *
- * process_token(expression, &token); *
- * } *
- * *
- ******************************************************************************/
-int zbx_token_find(const char *expression, int pos, zbx_token_t *token, zbx_token_search_t token_search)
-{
- int ret = FAIL;
- const char *ptr = expression + pos, *dollar = ptr;
-
- while (SUCCEED != ret)
- {
- int quoted = 0;
-
- /* skip macros in string constants when looking for functionid */
- for (; '{' != *ptr || 0 != quoted; ptr++)
- {
- if ('\0' == *ptr)
- break;
-
- if (0 != (token_search & ZBX_TOKEN_SEARCH_FUNCTIONID))
- {
- switch (*ptr)
- {
- case '\\':
- if (0 != quoted)
- {
- if ('\0' == *(++ptr))
- return FAIL;
- }
- break;
- case '"':
- quoted = !quoted;
- break;
- }
- }
- }
-
- if (0 != (token_search & ZBX_TOKEN_SEARCH_REFERENCES))
- {
- while (NULL != (dollar = strchr(dollar, '$')) && ptr > dollar)
- {
- if (0 == isdigit(dollar[1]))
- {
- dollar++;
- continue;
- }
-
- token->data.reference.index = dollar[1] - '0';
- token->type = ZBX_TOKEN_REFERENCE;
- token->loc.l = dollar - expression;
- token->loc.r = token->loc.l + 1;
- return SUCCEED;
- }
-
- if (NULL == dollar)
- token_search &= ~ZBX_TOKEN_SEARCH_REFERENCES;
- }
-
- if ('\0' == *ptr)
- return FAIL;
-
- if ('\0' == ptr[1])
- return FAIL;
-
- switch (ptr[1])
- {
- case '$':
- ret = token_parse_user_macro(expression, ptr, token);
- break;
- case '#':
- ret = token_parse_lld_macro(expression, ptr, token);
- break;
- case '?':
- if (0 != (token_search & ZBX_TOKEN_SEARCH_EXPRESSION_MACRO))
- ret = token_parse_expression_macro(expression, ptr,
- 0 != (token_search & ZBX_TOKEN_SEARCH_SIMPLE_MACRO) ? 1 : 0,
- token);
- break;
- case '{':
- ret = token_parse_nested_macro(expression, ptr,
- 0 != (token_search & ZBX_TOKEN_SEARCH_SIMPLE_MACRO) ? 1 : 0, token);
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (SUCCEED == (ret = token_parse_objectid(expression, ptr, token)))
- break;
- ZBX_FALLTHROUGH;
- default:
- if (SUCCEED != (ret = token_parse_macro(expression, ptr, token)) &&
- 0 != (token_search & ZBX_TOKEN_SEARCH_SIMPLE_MACRO))
- {
- ret = token_parse_simple_macro(expression, ptr, token);
- }
- }
-
- ptr++;
- }
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: public wrapper for token_parse_user_macro() function *
- * *
- ******************************************************************************/
-int zbx_token_parse_user_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- return token_parse_user_macro(expression, macro, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: public wrapper for token_parse_macro() function *
- * *
- ******************************************************************************/
-int zbx_token_parse_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- return token_parse_macro(expression, macro, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: public wrapper for token_parse_objectid() function *
- * *
- ******************************************************************************/
-int zbx_token_parse_objectid(const char *expression, const char *macro, zbx_token_t *token)
-{
- return token_parse_objectid(expression, macro, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: public wrapper for token_parse_lld_macro() function *
- * *
- ******************************************************************************/
-int zbx_token_parse_lld_macro(const char *expression, const char *macro, zbx_token_t *token)
-{
- return token_parse_lld_macro(expression, macro, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: public wrapper for token_parse_nested_macro() function *
- * *
- ******************************************************************************/
-int zbx_token_parse_nested_macro(const char *expression, const char *macro, int simple_macro_find,
- zbx_token_t *token)
-{
- return token_parse_nested_macro(expression, macro, simple_macro_find, token);
-}
-
-/******************************************************************************
- * *
- * Purpose: count calculated item (prototype) formula characters that can be *
- * skipped without the risk of missing a function *
- * *
- ******************************************************************************/
-static size_t zbx_no_function(const char *expr)
-{
- const char *ptr = expr;
- int inside_quote = 0, len, c_l, c_r;
- zbx_token_t token;
-
- while ('\0' != *ptr)
- {
- switch (*ptr)
- {
- case '\\':
- if (0 != inside_quote)
- ptr++;
- break;
- case '"':
- inside_quote = !inside_quote;
- ptr++;
- continue;
- }
-
- if (inside_quote)
- {
- if ('\0' == *ptr)
- break;
- ptr++;
- continue;
- }
-
- if ('{' == *ptr && '$' == *(ptr + 1) && SUCCEED == zbx_user_macro_parse(ptr, &len, &c_l, &c_r, NULL))
- {
- ptr += len + 1; /* skip to the position after user macro */
- }
- else if ('{' == *ptr && '{' == *(ptr + 1) && '#' == *(ptr + 2) &&
- SUCCEED == token_parse_nested_macro(ptr, ptr, 0, &token))
- {
- ptr += token.loc.r - token.loc.l + 1;
- }
- else if (SUCCEED != is_function_char(*ptr))
- {
- ptr++; /* skip one character which cannot belong to function name */
- }
- else if ((0 == strncmp("and", ptr, len = ZBX_CONST_STRLEN("and")) ||
- 0 == strncmp("not", ptr, len = ZBX_CONST_STRLEN("not")) ||
- 0 == strncmp("or", ptr, len = ZBX_CONST_STRLEN("or"))) &&
- NULL != strchr("()" ZBX_WHITESPACE, ptr[len]))
- {
- ptr += len; /* skip to the position after and/or/not operator */
- }
- else if (ptr > expr && 0 != isdigit(*(ptr - 1)) && NULL != strchr(ZBX_UNIT_SYMBOLS, *ptr))
- {
- ptr++; /* skip unit suffix symbol if it's preceded by a digit */
- }
- else
- break;
- }
-
- return ptr - expr;
-}
-
-/******************************************************************************
- * *
- * Purpose: find the location of the next function and its parameters in *
- * calculated item (prototype) formula *
- * *
- * Parameters: expr - [IN] string to parse *
- * func_pos - [OUT] function position in the string *
- * par_l - [OUT] position of the opening parenthesis *
- * par_r - [OUT] position of the closing parenthesis *
- * error - [OUT] error message *
- * max_error_len - [IN] error size *
- * *
- * Return value: SUCCEED - function was found at func_pos *
- * FAIL - there are no functions in the expression *
- * *
- ******************************************************************************/
-int zbx_function_find(const char *expr, size_t *func_pos, size_t *par_l, size_t *par_r, char *error,
- int max_error_len)
-{
- const char *ptr;
-
- for (ptr = expr; '\0' != *ptr; ptr += *par_l)
- {
- /* skip the part of expression that is definitely not a function */
- ptr += zbx_no_function(ptr);
- *par_r = 0;
-
- /* try to validate function candidate */
- if (SUCCEED != zbx_function_validate(ptr, par_l, par_r, error, max_error_len))
- {
- if (*par_l > *par_r)
- return FAIL;
-
- continue;
- }
-
- *func_pos = ptr - expr;
- *par_l += *func_pos;
- *par_r += *func_pos;
- return SUCCEED;
- }
-
- zbx_snprintf(error, max_error_len, "Incorrect function expression: %s", expr);
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: check if pattern matches the specified value *
- * *
- * Parameters: value - [IN] the value to match *
- * pattern - [IN] the pattern to match *
- * op - [IN] the matching operator *
- * *
- * Return value: SUCCEED - matches, FAIL - otherwise *
- * *
- ******************************************************************************/
-int zbx_strmatch_condition(const char *value, const char *pattern, unsigned char op)
-{
- int ret = FAIL;
-
- switch (op)
- {
- case CONDITION_OPERATOR_EQUAL:
- if (0 == strcmp(value, pattern))
- ret = SUCCEED;
- break;
- case CONDITION_OPERATOR_NOT_EQUAL:
- if (0 != strcmp(value, pattern))
- ret = SUCCEED;
- break;
- case CONDITION_OPERATOR_LIKE:
- if (NULL != strstr(value, pattern))
- ret = SUCCEED;
- break;
- case CONDITION_OPERATOR_NOT_LIKE:
- if (NULL == strstr(value, pattern))
- ret = SUCCEED;
- break;
- }
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: parse a number like "12.345" *
- * *
- * Parameters: number - [IN] start of number *
- * len - [OUT] length of parsed number *
- * *
- * Return value: SUCCEED - the number was parsed successfully *
- * FAIL - invalid number *
- * *
- * Comments: !!! Don't forget to sync the code with PHP !!! *
- * The token field locations are specified as offsets from the *
- * beginning of the expression. *
- * *
- ******************************************************************************/
-int zbx_number_parse(const char *number, int *len)
-{
- int digits = 0, dots = 0;
-
- *len = 0;
-
- while (1)
- {
- if (0 != isdigit(number[*len]))
- {
- (*len)++;
- digits++;
- continue;
- }
-
- if ('.' == number[*len])
- {
- (*len)++;
- dots++;
- continue;
- }
-
- if ('e' == number[*len] || 'E' == number[*len])
- {
- (*len)++;
-
- if ('-' == number[*len] || '+' == number[*len])
- (*len)++;
-
- if (0 == isdigit(number[*len]))
- return FAIL;
-
- while (0 != isdigit(number[++(*len)]));
-
- if ('.' == number[*len] ||'e' == number[*len] || 'E' == number[*len])
- return FAIL;
- }
-
- if (1 > digits || 1 < dots)
- return FAIL;
-
- return SUCCEED;
- }
-}
-
-/******************************************************************************
- * *
- * Purpose: parse a suffixed number like "12.345K" *
- * *
- * Parameters: number - [IN] start of number *
- * len - [OUT] length of parsed number *
- * *
- * Return value: SUCCEED - the number was parsed successfully *
- * FAIL - invalid number *
- * *
- * Comments: !!! Don't forget to sync the code with PHP !!! *
- * The token field locations are specified as offsets from the *
- * beginning of the expression. *
- * *
- ******************************************************************************/
-int zbx_suffixed_number_parse(const char *number, int *len)
-{
- if (FAIL == zbx_number_parse(number, len))
- return FAIL;
-
- if (0 != isalpha(number[*len]) && NULL != strchr(ZBX_UNIT_SYMBOLS, number[*len]))
- (*len)++;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: find number of parameters in parameter list *
- * *
- * Parameters: *
- * p - [IN] parameter list *
- * *
- * Return value: number of parameters (starting from 1) or *
- * 0 if syntax error *
- * *
- * Comments: delimiter for parameters is ','. Empty parameter list or a list *
- * containing only spaces is handled as having one empty parameter *
- * and 1 is returned. *
- * *
- ******************************************************************************/
-int num_param(const char *p)
-{
-/* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
- int ret = 1, state, array;
-
- if (p == NULL)
- return 0;
-
- for (state = 0, array = 0; '\0' != *p; p++)
- {
- switch (state) {
- /* Init state */
- case 0:
- if (',' == *p)
- {
- if (0 == array)
- ret++;
- }
- else if ('"' == *p)
- state = 1;
- else if ('[' == *p)
- {
- if (0 == array)
- array = 1;
- else
- return 0; /* incorrect syntax: multi-level array */
- }
- else if (']' == *p && 0 != array)
- {
- array = 0;
-
- while (' ' == p[1]) /* skip trailing spaces after closing ']' */
- p++;
-
- if (',' != p[1] && '\0' != p[1])
- return 0; /* incorrect syntax */
- }
- else if (']' == *p && 0 == array)
- return 0; /* incorrect syntax */
- else if (' ' != *p)
- state = 2;
- break;
- /* Quoted */
- case 1:
- if ('"' == *p)
- {
- while (' ' == p[1]) /* skip trailing spaces after closing quotes */
- p++;
-
- if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
- return 0; /* incorrect syntax */
-
- state = 0;
- }
- else if ('\\' == *p && '"' == p[1])
- p++;
- break;
- /* Unquoted */
- case 2:
- if (',' == *p || (']' == *p && 0 != array))
- {
- p--;
- state = 0;
- }
- else if (']' == *p && 0 == array)
- return 0; /* incorrect syntax */
- break;
- }
- }
-
- /* missing terminating '"' character */
- if (state == 1)
- return 0;
-
- /* missing terminating ']' character */
- if (array != 0)
- return 0;
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: return parameter by index (num) from parameter list (param) *
- * *
- * Parameters: *
- * p - [IN] parameter list *
- * num - [IN] requested parameter index *
- * buf - [OUT] pointer of output buffer *
- * max_len - [IN] size of output buffer *
- * type - [OUT] parameter type (may be NULL) *
- * *
- * Return value: *
- * 1 - requested parameter missing or buffer overflow *
- * 0 - requested parameter found (value - 'buf' can be empty string) *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-int get_param(const char *p, int num, char *buf, size_t max_len, zbx_request_parameter_type_t *type)
-{
-#define ZBX_ASSIGN_PARAM \
-{ \
- if (buf_i == max_len) \
- return 1; /* buffer overflow */ \
- buf[buf_i++] = *p; \
-}
-
- int state; /* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
- int array, idx = 1;
- size_t buf_i = 0;
-
- if (NULL != type)
- *type = REQUEST_PARAMETER_TYPE_UNDEFINED;
-
- if (0 == max_len)
- return 1; /* buffer overflow */
-
- max_len--; /* '\0' */
-
- for (state = 0, array = 0; '\0' != *p && idx <= num; p++)
- {
- switch (state)
- {
- /* init state */
- case 0:
- if (',' == *p)
- {
- if (0 == array)
- idx++;
- else if (idx == num)
- ZBX_ASSIGN_PARAM;
- }
- else if ('"' == *p)
- {
- state = 1;
-
- if (idx == num)
- {
- if (NULL != type && REQUEST_PARAMETER_TYPE_UNDEFINED == *type)
- *type = REQUEST_PARAMETER_TYPE_STRING;
-
- if (0 != array)
- ZBX_ASSIGN_PARAM;
- }
- }
- else if ('[' == *p)
- {
- if (idx == num)
- {
- if (NULL != type && REQUEST_PARAMETER_TYPE_UNDEFINED == *type)
- *type = REQUEST_PARAMETER_TYPE_ARRAY;
-
- if (0 != array)
- ZBX_ASSIGN_PARAM;
- }
- array++;
- }
- else if (']' == *p && 0 != array)
- {
- array--;
- if (0 != array && idx == num)
- ZBX_ASSIGN_PARAM;
-
- /* skip spaces */
- while (' ' == p[1])
- p++;
-
- if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
- return 1; /* incorrect syntax */
- }
- else if (' ' != *p)
- {
- if (idx == num)
- {
- if (NULL != type && REQUEST_PARAMETER_TYPE_UNDEFINED == *type)
- *type = REQUEST_PARAMETER_TYPE_STRING;
-
- ZBX_ASSIGN_PARAM;
- }
-
- state = 2;
- }
- break;
- case 1:
- /* quoted */
-
- if ('"' == *p)
- {
- if (0 != array && idx == num)
- ZBX_ASSIGN_PARAM;
-
- /* skip spaces */
- while (' ' == p[1])
- p++;
-
- if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
- return 1; /* incorrect syntax */
-
- state = 0;
- }
- else if ('\\' == *p && '"' == p[1])
- {
- if (idx == num && 0 != array)
- ZBX_ASSIGN_PARAM;
-
- p++;
-
- if (idx == num)
- ZBX_ASSIGN_PARAM;
- }
- else if (idx == num)
- ZBX_ASSIGN_PARAM;
- break;
- case 2:
- /* unquoted */
-
- if (',' == *p || (']' == *p && 0 != array))
- {
- p--;
- state = 0;
- }
- else if (idx == num)
- ZBX_ASSIGN_PARAM;
- break;
- }
-
- if (idx > num)
- break;
- }
-#undef ZBX_ASSIGN_PARAM
-
- /* missing terminating '"' character */
- if (1 == state)
- return 1;
-
- /* missing terminating ']' character */
- if (0 != array)
- return 1;
-
- buf[buf_i] = '\0';
-
- if (idx >= num)
- return 0;
-
- return 1;
-}
-
-/******************************************************************************
- * *
- * Purpose: return length of the parameter by index (num) *
- * from parameter list (param) *
- * *
- * Parameters: *
- * p - [IN] parameter list *
- * num - [IN] requested parameter index *
- * sz - [OUT] length of requested parameter *
- * *
- * Return value: *
- * 1 - requested parameter missing *
- * 0 - requested parameter found *
- * (for first parameter result is always 0) *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-static int get_param_len(const char *p, int num, size_t *sz)
-{
-/* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
- int state, array, idx = 1;
-
- *sz = 0;
-
- for (state = 0, array = 0; '\0' != *p && idx <= num; p++)
- {
- switch (state) {
- /* Init state */
- case 0:
- if (',' == *p)
- {
- if (0 == array)
- idx++;
- else if (idx == num)
- (*sz)++;
- }
- else if ('"' == *p)
- {
- state = 1;
- if (0 != array && idx == num)
- (*sz)++;
- }
- else if ('[' == *p)
- {
- if (0 != array && idx == num)
- (*sz)++;
- array++;
- }
- else if (']' == *p && 0 != array)
- {
- array--;
- if (0 != array && idx == num)
- (*sz)++;
-
- /* skip spaces */
- while (' ' == p[1])
- p++;
-
- if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
- return 1; /* incorrect syntax */
- }
- else if (' ' != *p)
- {
- if (idx == num)
- (*sz)++;
- state = 2;
- }
- break;
- /* Quoted */
- case 1:
- if ('"' == *p)
- {
- if (0 != array && idx == num)
- (*sz)++;
-
- /* skip spaces */
- while (' ' == p[1])
- p++;
-
- if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
- return 1; /* incorrect syntax */
-
- state = 0;
- }
- else if ('\\' == *p && '"' == p[1])
- {
- if (idx == num && 0 != array)
- (*sz)++;
-
- p++;
-
- if (idx == num)
- (*sz)++;
- }
- else if (idx == num)
- (*sz)++;
- break;
- /* Unquoted */
- case 2:
- if (',' == *p || (']' == *p && 0 != array))
- {
- p--;
- state = 0;
- }
- else if (idx == num)
- (*sz)++;
- break;
- }
-
- if (idx > num)
- break;
- }
-
- /* missing terminating '"' character */
- if (state == 1)
- return 1;
-
- /* missing terminating ']' character */
- if (array != 0)
- return 1;
-
- if (idx >= num)
- return 0;
-
- return 1;
-}
-
-/******************************************************************************
- * *
- * Purpose: return parameter by index (num) from parameter list (param) *
- * *
- * Parameters: *
- * p - [IN] parameter list *
- * num - [IN] requested parameter index *
- * type - [OUT] parameter type (may be NULL) *
- * *
- * Return value: *
- * NULL - requested parameter missing *
- * otherwise - requested parameter *
- * (for first parameter result is not NULL) *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-char *get_param_dyn(const char *p, int num, zbx_request_parameter_type_t *type)
-{
- char *buf = NULL;
- size_t sz;
-
- if (0 != get_param_len(p, num, &sz))
- return buf;
-
- buf = (char *)zbx_malloc(buf, sz + 1);
-
- if (0 != get_param(p, num, buf, sz + 1, type))
- zbx_free(buf);
-
- return buf;
-}
-
-/******************************************************************************
- * *
- * Purpose: replaces an item key, SNMP OID or their parameters when callback *
- * function returns a new string *
- * *
- * Comments: auxiliary function for replace_key_params_dyn() *
- * *
- ******************************************************************************/
-static int replace_key_param(char **data, int key_type, size_t l, size_t *r, int level, int num, int quoted,
- replace_key_param_f cb, void *cb_data)
-{
- char c = (*data)[*r], *param = NULL;
- int ret;
-
- (*data)[*r] = '\0';
- ret = cb(*data + l, key_type, level, num, quoted, cb_data, &param);
- (*data)[*r] = c;
-
- if (NULL != param)
- {
- (*r)--;
- zbx_replace_string(data, l, r, param);
- (*r)++;
-
- zbx_free(param);
- }
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: replaces an item key, SNMP OID or their parameters by using *
- * callback function *
- * *
- * Parameters: *
- * data - [IN/OUT] item key or SNMP OID *
- * key_type - [IN] ZBX_KEY_TYPE_* *
- * cb - [IN] callback function *
- * cb_data - [IN] callback function custom data *
- * error - [OUT] error message *
- * maxerrlen - [IN] error size *
- * *
- * Return value: SUCCEED - function executed successfully *
- * FAIL - otherwise, error will contain error message *
- * *
- ******************************************************************************/
-int replace_key_params_dyn(char **data, int key_type, replace_key_param_f cb, void *cb_data, char *error,
- size_t maxerrlen)
-{
- typedef enum
- {
- ZBX_STATE_NEW,
- ZBX_STATE_END,
- ZBX_STATE_UNQUOTED,
- ZBX_STATE_QUOTED
- }
- zbx_parser_state_t;
-
- size_t i = 0, l = 0;
- int level = 0, num = 0, ret = SUCCEED;
- zbx_parser_state_t state = ZBX_STATE_NEW;
-
- if (ZBX_KEY_TYPE_ITEM == key_type)
- {
- for (; SUCCEED == is_key_char((*data)[i]) && '\0' != (*data)[i]; i++)
- ;
-
- if (0 == i)
- goto clean;
-
- if ('[' != (*data)[i] && '\0' != (*data)[i])
- goto clean;
- }
- else
- {
- zbx_token_t token;
- int len, c_l, c_r;
-
- while ('\0' != (*data)[i])
- {
- if ('{' == (*data)[i] && '$' == (*data)[i + 1] &&
- SUCCEED == zbx_user_macro_parse(&(*data)[i], &len, &c_l, &c_r, NULL))
- {
- i += len + 1; /* skip to the position after user macro */
- }
- else if ('{' == (*data)[i] && '{' == (*data)[i + 1] && '#' == (*data)[i + 2] &&
- SUCCEED == token_parse_nested_macro(&(*data)[i], &(*data)[i], 0, &token))
- {
- i += token.loc.r - token.loc.l + 1;
- }
- else if ('[' != (*data)[i])
- {
- i++;
- }
- else
- break;
- }
- }
-
- ret = replace_key_param(data, key_type, 0, &i, level, num, 0, cb, cb_data);
-
- for (; '\0' != (*data)[i] && FAIL != ret; i++)
- {
- switch (state)
- {
- case ZBX_STATE_NEW: /* a new parameter started */
- switch ((*data)[i])
- {
- case ' ':
- break;
- case ',':
- ret = replace_key_param(data, key_type, i, &i, level, num, 0, cb,
- cb_data);
- if (1 == level)
- num++;
- break;
- case '[':
- if (2 == level)
- goto clean; /* incorrect syntax: multi-level array */
- level++;
- if (1 == level)
- num++;
- break;
- case ']':
- ret = replace_key_param(data, key_type, i, &i, level, num, 0, cb,
- cb_data);
- level--;
- state = ZBX_STATE_END;
- break;
- case '"':
- state = ZBX_STATE_QUOTED;
- l = i;
- break;
- default:
- state = ZBX_STATE_UNQUOTED;
- l = i;
- }
- break;
- case ZBX_STATE_END: /* end of parameter */
- switch ((*data)[i])
- {
- case ' ':
- break;
- case ',':
- state = ZBX_STATE_NEW;
- if (1 == level)
- num++;
- break;
- case ']':
- if (0 == level)
- goto clean; /* incorrect syntax: redundant ']' */
- level--;
- break;
- default:
- goto clean;
- }
- break;
- case ZBX_STATE_UNQUOTED: /* an unquoted parameter */
- if (']' == (*data)[i] || ',' == (*data)[i])
- {
- ret = replace_key_param(data, key_type, l, &i, level, num, 0, cb, cb_data);
-
- i--;
- state = ZBX_STATE_END;
- }
- break;
- case ZBX_STATE_QUOTED: /* a quoted parameter */
- if ('"' == (*data)[i] && '\\' != (*data)[i - 1])
- {
- i++;
- ret = replace_key_param(data, key_type, l, &i, level, num, 1, cb, cb_data);
- i--;
-
- state = ZBX_STATE_END;
- }
- break;
- }
- }
-clean:
- if (0 == i || '\0' != (*data)[i] || 0 != level)
- {
- if (NULL != error)
- {
- zbx_snprintf(error, maxerrlen, "Invalid %s at position " ZBX_FS_SIZE_T,
- (ZBX_KEY_TYPE_ITEM == key_type ? "item key" : "SNMP OID"), (zbx_fs_size_t)i);
- }
- ret = FAIL;
- }
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: remove parameter by index (num) from parameter list (param) *
- * *
- * Parameters: *
- * param - parameter list *
- * num - requested parameter index *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-void remove_param(char *param, int num)
-{
- int state = 0; /* 0 - unquoted parameter, 1 - quoted parameter */
- int idx = 1, skip_char = 0;
- char *p;
-
- for (p = param; '\0' != *p; p++)
- {
- switch (state)
- {
- case 0: /* in unquoted parameter */
- if (',' == *p)
- {
- if (1 == idx && 1 == num)
- skip_char = 1;
- idx++;
- }
- else if ('"' == *p)
- state = 1;
- break;
- case 1: /* in quoted parameter */
- if ('"' == *p && '\\' != *(p - 1))
- state = 0;
- break;
- }
- if (idx != num && 0 == skip_char)
- *param++ = *p;
-
- skip_char = 0;
- }
-
- *param = '\0';
-}
-
-/******************************************************************************
- * *
- * Purpose: check if string is contained in a list of delimited strings *
- * *
- * Parameters: list - [IN] strings a,b,ccc,ddd *
- * value - [IN] value *
- * len - [IN] value length *
- * delimiter - [IN] delimiter *
- * *
- * Return value: SUCCEED - string is in the list, FAIL - otherwise *
- * *
- ******************************************************************************/
-int str_n_in_list(const char *list, const char *value, size_t len, char delimiter)
-{
- const char *end;
- size_t token_len, next = 1;
-
- while ('\0' != *list)
- {
- if (NULL != (end = strchr(list, delimiter)))
- {
- token_len = end - list;
- next = 1;
- }
- else
- {
- token_len = strlen(list);
- next = 0;
- }
-
- if (len == token_len && 0 == memcmp(list, value, len))
- return SUCCEED;
-
- list += token_len + next;
- }
-
- if (1 == next && 0 == len)
- return SUCCEED;
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: check if string is contained in a list of delimited strings *
- * *
- * Parameters: list - strings a,b,ccc,ddd *
- * value - value *
- * delimiter - delimiter *
- * *
- * Return value: SUCCEED - string is in the list, FAIL - otherwise *
- * *
- ******************************************************************************/
-int str_in_list(const char *list, const char *value, char delimiter)
-{
- return str_n_in_list(list, value, strlen(value), delimiter);
-}
-
-/******************************************************************************
- * *
- * Purpose: return parameter by index (num) from parameter list (param) *
- * to be used for keys: key[param1,param2] *
- * *
- * Parameters: *
- * param - parameter list *
- * num - requested parameter index *
- * buf - pointer of output buffer *
- * max_len - size of output buffer *
- * *
- * Return value: *
- * 1 - requested parameter missing *
- * 0 - requested parameter found (value - 'buf' can be empty string) *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-int get_key_param(char *param, int num, char *buf, size_t max_len)
-{
- int ret;
- char *pl, *pr;
-
- pl = strchr(param, '[');
- pr = strrchr(param, ']');
-
- if (NULL == pl || NULL == pr || pl > pr)
- return 1;
-
- *pr = '\0';
- ret = get_param(pl + 1, num, buf, max_len, NULL);
- *pr = ']';
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: calculate count of parameters from parameter list (param) *
- * to be used for keys: key[param1,param2] *
- * *
- * Parameters: *
- * param - parameter list *
- * *
- * Return value: count of parameters *
- * *
- * Comments: delimiter for parameters is ',' *
- * *
- ******************************************************************************/
-int num_key_param(char *param)
-{
- int ret;
- char *pl, *pr;
-
- if (NULL == param)
- return 0;
-
- pl = strchr(param, '[');
- pr = strrchr(param, ']');
-
- if (NULL == pl || NULL == pr || pl > pr)
- return 0;
-
- *pr = '\0';
- ret = num_param(pl + 1);
- *pr = ']';
-
- return ret;
-}
-
-/******************************************************************************
- * *
- * Purpose: to replace memory block and allocate more memory if needed *
- * *
- * Parameters: data - [IN/OUT] allocated memory *
- * data_alloc - [IN/OUT] allocated memory size *
- * data_len - [IN/OUT] used memory size *
- * offset - [IN] offset of memory block to be replaced *
- * sz_to - [IN] size of block that need to be replaced *
- * from - [IN] what to replace with *
- * sz_from - [IN] size of new block *
- * *
- * Return value: once data is replaced offset can become less, bigger or *
- * remain unchanged *
- ******************************************************************************/
-int zbx_replace_mem_dyn(char **data, size_t *data_alloc, size_t *data_len, size_t offset, size_t sz_to,
- const char *from, size_t sz_from)
-{
- size_t sz_changed = sz_from - sz_to;
-
- if (0 != sz_changed)
- {
- char *to;
-
- *data_len += sz_changed;
-
- if (*data_len > *data_alloc)
- {
- while (*data_len > *data_alloc)
- *data_alloc *= 2;
-
- *data = (char *)zbx_realloc(*data, *data_alloc);
- }
-
- to = *data + offset;
- memmove(to + sz_from, to + sz_to, *data_len - (to - *data) - sz_from);
- }
-
- memcpy(*data + offset, from, sz_from);
-
- return (int)sz_changed;
-}
-
-/******************************************************************************
- * *
- * Purpose: splits string *
- * *
- * Parameters: src - [IN] source string *
- * delimiter - [IN] delimiter *
- * last - [IN] split after last delimiter *
- * left - [IN/OUT] first part of the string *
- * right - [IN/OUT] second part of the string or NULL, if *
- * delimiter was not found *
- * *
- ******************************************************************************/
-static void zbx_string_split(const char *src, char delimiter, unsigned char last, char **left, char **right)
-{
- char *delimiter_ptr;
-
- if (NULL == (delimiter_ptr = (0 == last ? strchr(src, delimiter) : strrchr(src, delimiter))))
- {
- *left = zbx_strdup(NULL, src);
- *right = NULL;
- }
- else
- {
- size_t left_size;
- size_t right_size;
-
- left_size = (size_t)(delimiter_ptr - src) + 1;
- right_size = strlen(src) - (size_t)(delimiter_ptr - src);
-
- *left = zbx_malloc(NULL, left_size);
- *right = zbx_malloc(NULL, right_size);
-
- memcpy(*left, src, left_size - 1);
- (*left)[left_size - 1] = '\0';
- memcpy(*right, delimiter_ptr + 1, right_size);
- }
-}
-
-void zbx_strsplit_first(const char *src, char delimiter, char **left, char **right)
-{
- zbx_string_split(src, delimiter, 0, left, right);
-}
-
-void zbx_strsplit_last(const char *src, char delimiter, char **left, char **right)
-{
- zbx_string_split(src, delimiter, 1, left, right);
-}
-
-/******************************************************************************
- * *
- * Purpose: Removes spaces from both ends of the string, then unquotes it if *
- * double quotation mark is present on both ends of the string. If *
- * strip_plus_sign is non-zero, then removes single "+" sign from *
- * the beginning of the trimmed and unquoted string. *
- * *
- * This function does not guarantee that the resulting string *
- * contains numeric value. It is meant to be used for removing *
- * "valid" characters from the value that is expected to be numeric *
- * before checking if value is numeric. *
- * *
- * Parameters: str - [IN/OUT] string for processing *
- * strip_plus_sign - [IN] non-zero if "+" should be stripped *
- * *
- ******************************************************************************/
-static void zbx_trim_number(char *str, int strip_plus_sign)
-{
- char *left = str; /* pointer to the first character */
- char *right = strchr(str, '\0') - 1; /* pointer to the last character, not including terminating null-char */
-
- if (left > right)
- {
- /* string is empty before any trimming */
- return;
- }
-
- while (' ' == *left)
- {
- left++;
- }
-
- while (' ' == *right && left < right)
- {
- right--;
- }
-
- if ('"' == *left && '"' == *right && left < right)
- {
- left++;
- right--;
- }
-
- if (0 != strip_plus_sign && '+' == *left)
- {
- left++;
- }
-
- if (left > right)
- {
- /* string is empty after trimming */
- *str = '\0';
- return;
- }
-
- if (str < left)
- {
- while (left <= right)
- {
- *str++ = *left++;
- }
- *str = '\0';
- }
- else
- {
- *(right + 1) = '\0';
- }
-}
-
-/******************************************************************************
- * *
- * Purpose: Removes spaces from both ends of the string, then unquotes it if *
- * double quotation mark is present on both ends of the string, then *
- * removes single "+" sign from the beginning of the trimmed and *
- * unquoted string. *
- * *
- * This function does not guarantee that the resulting string *
- * contains integer value. It is meant to be used for removing *
- * "valid" characters from the value that is expected to be numeric *
- * before checking if value is numeric. *
- * *
- * Parameters: str - [IN/OUT] string for processing *
- * *
- ******************************************************************************/
-void zbx_trim_integer(char *str)
-{
- zbx_trim_number(str, 1);
-}
-
-/******************************************************************************
- * *
- * Purpose: Removes spaces from both ends of the string, then unquotes it if *
- * double quotation mark is present on both ends of the string. *
- * *
- * This function does not guarantee that the resulting string *
- * contains floating-point number. It is meant to be used for *
- * removing "valid" characters from the value that is expected to be *
- * numeric before checking if value is numeric. *
- * *
- * Parameters: str - [IN/OUT] string for processing *
- * *
- ******************************************************************************/
-void zbx_trim_float(char *str)
-{
- zbx_trim_number(str, 0);
-}
-
-/******************************************************************************
- * *
- * Purpose: extracts protocol version from value *
- * *
- * Parameters: *
- * value - [IN] textual representation of version *
- * *
- * Return value: The protocol version if it was successfully extracted, *
- * otherwise -1 *
- * *
- ******************************************************************************/
-int zbx_get_component_version(char *value)
-{
- char *pminor, *ptr;
-
- if (NULL == (pminor = strchr(value, '.')))
- return FAIL;
-
- *pminor++ = '\0';
-
- if (NULL != (ptr = strchr(pminor, '.')))
- *ptr = '\0';
-
- return ZBX_COMPONENT_VERSION(atoi(value), atoi(pminor));
-}
-
-/******************************************************************************
- * *
- * Purpose: extracts value from a string, unquoting if necessary *
- * *
- * Parameters: *
- * text - [IN] the text containing value to extract *
- * len - [IN] length (in bytes) of the value to extract. *
- * It can be 0. It must not exceed length of 'text' string. *
- * value - [OUT] the extracted value *
- * *
- * Return value: SUCCEED - the value was extracted successfully *
- * FAIL - otherwise *
- * *
- * Comments: When unquoting value only " and \ character escapes are accepted.*
- * *
- ******************************************************************************/
-int zbx_str_extract(const char *text, size_t len, char **value)
-{
- char *tmp, *out;
- const char *in;
-
- tmp = zbx_malloc(NULL, len + 1);
-
- if (0 == len)
- {
- *tmp = '\0';
- *value = tmp;
- return SUCCEED;
- }
-
- if ('"' != *text)
- {
- memcpy(tmp, text, len);
- tmp[len] = '\0';
- *value = tmp;
- return SUCCEED;
- }
-
- if (2 > len)
- goto fail;
-
- for (out = tmp, in = text + 1; '"' != *in; in++)
- {
- if ((size_t)(in - text) >= len - 1)
- goto fail;
-
- if ('\\' == *in)
- {
- if ((size_t)(++in - text) >= len - 1)
- goto fail;
-
- if ('"' != *in && '\\' != *in)
- goto fail;
- }
- *out++ = *in;
- }
-
- if ((size_t)(in - text) != len - 1)
- goto fail;
-
- *out = '\0';
- *value = tmp;
- return SUCCEED;
-fail:
- zbx_free(tmp);
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: check the item key characters length and, if the length exceeds *
- * max allowable characters length, truncate the item key, while *
- * maintaining the right square bracket *
- * *
- * Parameters: key - [IN] item key for processing *
- * char_max - [IN] item key max characters length *
- * buf - [IN/OUT] buffer for short version of item key *
- * buf_len - [IN] buffer size for short version of item key *
- * *
- * Return value: The item key that does not exceed passed length *
- * *
- ******************************************************************************/
-const char *zbx_truncate_itemkey(const char *key, const size_t char_max, char *buf, const size_t buf_len)
-{
-# define ZBX_SUFFIX "..."
-# define ZBX_BSUFFIX "[...]"
-
- size_t key_byte_count, key_char_total;
- int is_bracket = 0;
- char *bracket_l;
-
- if (char_max >= (key_char_total = zbx_strlen_utf8(key)))
- return key;
-
- if (NULL != (bracket_l = strchr(key, '[')))
- is_bracket = 1;
-
- if (char_max < ZBX_CONST_STRLEN(ZBX_SUFFIX) + 2 * is_bracket) /* [...] or ... */
- return key;
-
- if (0 != is_bracket)
- {
- size_t key_char_count, param_char_count, param_byte_count;
-
- key_char_count = zbx_charcount_utf8_nbytes(key, bracket_l - key);
- param_char_count = key_char_total - key_char_count;
-
- if (param_char_count <= ZBX_CONST_STRLEN(ZBX_BSUFFIX))
- {
- if (char_max < param_char_count + ZBX_CONST_STRLEN(ZBX_SUFFIX))
- return key;
-
- key_byte_count = 1 + zbx_strlen_utf8_nchars(key, char_max - param_char_count -
- ZBX_CONST_STRLEN(ZBX_SUFFIX));
- param_byte_count = 1 + zbx_strlen_utf8_nchars(bracket_l, key_char_count);
-
- if (buf_len < key_byte_count + ZBX_CONST_STRLEN(ZBX_SUFFIX) + param_byte_count - 1)
- return key;
-
- key_byte_count = zbx_strlcpy_utf8(buf, key, key_byte_count);
- key_byte_count += zbx_strlcpy_utf8(&buf[key_byte_count], ZBX_SUFFIX, sizeof(ZBX_SUFFIX));
- zbx_strlcpy_utf8(&buf[key_byte_count], bracket_l, param_byte_count);
-
- return buf;
- }
-
- if (key_char_count + ZBX_CONST_STRLEN(ZBX_BSUFFIX) > char_max)
- {
- if (char_max <= ZBX_CONST_STRLEN(ZBX_SUFFIX) + ZBX_CONST_STRLEN(ZBX_BSUFFIX))
- return key;
-
- key_byte_count = 1 + zbx_strlen_utf8_nchars(key, char_max - ZBX_CONST_STRLEN(ZBX_SUFFIX) -
- ZBX_CONST_STRLEN(ZBX_BSUFFIX));
-
- if (buf_len < key_byte_count + ZBX_CONST_STRLEN(ZBX_SUFFIX) + ZBX_CONST_STRLEN(ZBX_BSUFFIX))
- return key;
-
- key_byte_count = zbx_strlcpy_utf8(buf, key, key_byte_count);
- key_byte_count += zbx_strlcpy_utf8(&buf[key_byte_count], ZBX_SUFFIX, sizeof(ZBX_SUFFIX));
- zbx_strlcpy_utf8(&buf[key_byte_count], ZBX_BSUFFIX, sizeof(ZBX_BSUFFIX));
-
- return buf;
- }
- }
-
- key_byte_count = 1 + zbx_strlen_utf8_nchars(key, char_max - (ZBX_CONST_STRLEN(ZBX_SUFFIX) + is_bracket));
-
- if (buf_len < key_byte_count + ZBX_CONST_STRLEN(ZBX_SUFFIX) + is_bracket)
- return key;
-
- key_byte_count = zbx_strlcpy_utf8(buf, key, key_byte_count);
- zbx_strlcpy_utf8(&buf[key_byte_count], ZBX_SUFFIX, sizeof(ZBX_SUFFIX));
-
- if (0 != is_bracket)
- zbx_strlcpy_utf8(&buf[key_byte_count + ZBX_CONST_STRLEN(ZBX_SUFFIX)], "]", sizeof("]"));
-
- return buf;
-
-# undef ZBX_SUFFIX
-# undef ZBX_BSUFFIX
-}
-
-/******************************************************************************
- * *
- * Purpose: check the value characters length and, if the length exceeds *
- * max allowable characters length, truncate the value *
- * *
- * Parameters: val - [IN] value for processing *
- * char_max - [IN] value max characters length *
- * buf - [IN/OUT] buffer for short version of value *
- * buf_len - [IN] buffer size for short version of value *
- * *
- * Return value: The value that does not exceed passed length *
- * *
- ******************************************************************************/
-const char *zbx_truncate_value(const char *val, const size_t char_max, char *buf, const size_t buf_len)
-{
-# define ZBX_SUFFIX "..."
-
- size_t key_byte_count;
-
- if (char_max >= zbx_strlen_utf8(val))
- return val;
-
- key_byte_count = 1 + zbx_strlen_utf8_nchars(val, char_max - ZBX_CONST_STRLEN(ZBX_SUFFIX));
-
- if (buf_len < key_byte_count + ZBX_CONST_STRLEN(ZBX_SUFFIX))
- return val;
-
- key_byte_count = zbx_strlcpy_utf8(buf, val, key_byte_count);
- zbx_strlcpy_utf8(&buf[key_byte_count], ZBX_SUFFIX, sizeof(ZBX_SUFFIX));
-
- return buf;
-
-# undef ZBX_SUFFIX
-}
-
-/******************************************************************************
- * *
- * Purpose: converts double value to string and truncates insignificant *
- * precision *
- * *
- * Parameters: buffer - [OUT] the output buffer *
- * size - [IN] the output buffer size *
- * val - [IN] double value to be converted *
- * *
- * Return value: the output buffer with printed value *
- * *
- ******************************************************************************/
-const char *zbx_print_double(char *buffer, size_t size, double val)
-{
- zbx_snprintf(buffer, size, "%.15G", val);
-
- if (atof(buffer) != val)
- zbx_snprintf(buffer, size, ZBX_FS_DBL64, val);
-
- return buffer;
-}
-
-/******************************************************************************
- * *
- * Purpose: unquotes valid substring at the specified location *
- * *
- * Parameters: src - [IN] the source string *
- * left - [IN] the left substring position 9start) *
- * right - [IN] the right substirng position (end) *
- * *
- * Return value: The unquoted and copied substring. *
- * *
- ******************************************************************************/
-char *zbx_substr_unquote(const char *src, size_t left, size_t right)
-{
- char *str, *ptr;
-
- if ('"' == src[left])
- {
- src += left + 1;
- str = zbx_malloc(NULL, right - left);
- ptr = str;
-
- while ('"' != *src)
- {
- if ('\\' == *src)
- {
- switch (*(++src))
- {
- case '\\':
- *ptr++ = '\\';
- break;
- case '"':
- *ptr++ = '"';
- break;
- case '\0':
- THIS_SHOULD_NEVER_HAPPEN;
- *ptr = '\0';
- return str;
- }
- }
- else
- *ptr++ = *src;
- src++;
- }
- *ptr = '\0';
- }
- else
- {
- str = zbx_malloc(NULL, right - left + 2);
- memcpy(str, src + left, right - left + 1);
- str[right - left + 1] = '\0';
- }
-
- return str;
-}
-
-/******************************************************************************
- * *
- * Purpose: extracts substring at the specified location *
- * *
- * Parameters: src - [IN] the source string *
- * left - [IN] the left substring position 9start) *
- * right - [IN] the right substirng position (end) *
- * *
- * Return value: The unquoted and copied substring. *
- * *
- ******************************************************************************/
-char *zbx_substr(const char *src, size_t left, size_t right)
-{
- char *str;
-
- str = zbx_malloc(NULL, right - left + 2);
- memcpy(str, src + left, right - left + 1);
- str[right - left + 1] = '\0';
-
- return str;
-}
-
-/******************************************************************************
- * *
- * Purpose: return pointer to the next utf-8 character *
- * *
- * Parameters: str - [IN] the input string *
- * *
- * Return value: A pointer to the next utf-8 character. *
- * *
- ******************************************************************************/
-static const char *utf8_chr_next(const char *str)
-{
- ++str;
-
- while (0x80 == (0xc0 & (unsigned char)*str))
- str++;
-
- return str;
-}
-
-/******************************************************************************
- * *
- * Purpose: return pointer to the previous utf-8 character *
- * *
- * Parameters: str - [IN] the input string *
- * start - [IN] the start of the initial string *
- * *
- * Return value: A pointer to the previous utf-8 character. *
- * *
- ******************************************************************************/
-static char *utf8_chr_prev(char *str, const char *start)
-{
- do
- {
- if (--str < start)
- return NULL;
- }
- while (0x80 == (0xc0 & (unsigned char)*str));
-
- return str;
-}
-
-/******************************************************************************
- * *
- * Purpose: checks if string contains utf-8 character *
- * *
- * Parameters: seq - [IN] the input string *
- * c - [IN] the utf-8 character to look for *
- * *
- * Return value: SUCCEED - the string contains the specified character *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int strchr_utf8(const char *seq, const char *c)
-{
- size_t len, c_len;
-
- if (0 == (c_len = zbx_utf8_char_len(c)))
- return FAIL;
-
- if (1 == c_len)
- return (NULL == strchr(seq, *c) ? FAIL : SUCCEED);
-
- /* check for broken utf-8 sequence in character */
- if (c + c_len != utf8_chr_next(c))
- return FAIL;
-
- while ('\0' != *seq)
- {
- len = (size_t)(utf8_chr_next(seq) - seq);
-
- if (len == c_len && 0 == memcmp(seq, c, len))
- return SUCCEED;
-
- seq += len;
- }
-
- return FAIL;
-}
-
-/******************************************************************************
- * *
- * Purpose: trim the specified utf-8 characters from the left side of input *
- * string *
- * *
- * Parameters: str - [IN] the input string *
- * charlist - [IN] the characters to trim *
- * *
- ******************************************************************************/
-void zbx_ltrim_utf8(char *str, const char *charlist)
-{
- const char *next;
-
- for (next = str; '\0' != *next; next = utf8_chr_next(next))
- {
- if (SUCCEED != strchr_utf8(charlist, next))
- break;
- }
-
- if (next != str)
- {
- size_t len;
-
- if (0 != (len = strlen(next)))
- memmove(str, next, len);
-
- str[len] = '\0';
- }
-}
-
-/******************************************************************************
- * *
- * Purpose: trim the specified utf-8 characters from the right side of input *
- * string *
- * *
- * Parameters: str - [IN] the input string *
- * charlist - [IN] the characters to trim *
- * *
- ******************************************************************************/
-void zbx_rtrim_utf8(char *str, const char *charlist)
-{
- char *prev, *last;
-
- for (last = str + strlen(str), prev = last; NULL != prev; prev = utf8_chr_prev(prev, str))
- {
- if (SUCCEED != strchr_utf8(charlist, prev))
- break;
-
- if ((last = prev) <= str)
- break;
- }
-
- *last = '\0';
-}
-
-/******************************************************************************
- * *
- * Purpose: convert string from iso8601 timezone info to offset in seconds *
- * *
- * Parameters: zone - [IN] iso8601 timezone string *
- * offset - [OUT] offset value *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int zbx_iso8601_timezone(const char *zone, long int *offset)
-{
- int m, h, sign = 0;
- char c;
- const char *ptr = zone;
-
- if ('.' == *zone) /* skip milliseconds */
- {
- for (ptr++; 0 != isdigit(*ptr); ptr++)
- ;
- }
-
- for (; ' ' == *ptr; ptr++)
- ;
-
- *offset = 0;
- c = *ptr;
-
- if ('\0' == c || 'Z' == c || 'z' == c)
- return SUCCEED;
- else if ('-' == c)
- sign = -1;
- else if ('+' == c)
- sign = +1;
- else
- return FAIL;
-
- ptr++;
-
- if (ZBX_CONST_STRLEN("00:00") > strlen(ptr) || ':' != ptr[2])
- return FAIL;
-
- if (0 == isdigit(*ptr) || 23 < (h = atoi(ptr)))
- return FAIL;
-
- if (0 == isdigit(ptr[3]) || 59 < (m = atoi(&ptr[3])))
- return FAIL;
-
- *offset = sign * (m + h * 60) * 60;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Purpose: parse string from iso8601 datetime (xml base) to UTC *
- * without millisecond, supported formats: *
- * yyyy-mm-ddThh:mm:ss *
- * yyyy-mm-ddThh:mm:ssZ *
- * yyyy-mm-ddThh:mm:ss+hh:mm *
- * yyyy-mm-ddThh:mm:ss-hh:mm *
- * yyyy-mm-ddThh:mm:ss +hh:mm *
- * yyyy-mm-ddThh:mm:ss -hh:mm *
- * yyyy-mm-ddThh:mm:ss.ccc *
- * yyyy-mm-ddThh:mm:ss.cccZ *
- * yyyy-mm-ddThh:mm:ss.ccc+hh:mm *
- * yyyy-mm-ddThh:mm:ss.ccc-hh:mm *
- * yyyy-mm-ddThh:mm:ss.ccc +hh:mm *
- * yyyy-mm-ddThh:mm:ss.ccc -hh:mm *
- * yyyy-mm-dd hh:mm:ss *
- * yyyy-mm-dd hh:mm:ssZ *
- * yyyy-mm-dd hh:mm:ss+hh:mm *
- * yyyy-mm-dd hh:mm:ss-hh:mm *
- * yyyy-mm-dd hh:mm:ss +hh:mm *
- * yyyy-mm-dd hh:mm:ss -hh:mm *
- * yyyy-mm-dd hh:mm:ss.ccc *
- * yyyy-mm-dd hh:mm:ss.cccZ *
- * yyyy-mm-dd hh:mm:ss.ccc+hh:mm *
- * yyyy-mm-dd hh:mm:ss.ccc-hh:mm *
- * yyyy-mm-dd hh:mm:ss.ccc +hh:mm *
- * yyyy-mm-dd hh:mm:ss.ccc -hh:mm *
- * *
- * Parameters: str - [IN] iso8601 datetime string *
- * time - [OUT] parsed tm value *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-int zbx_iso8601_utc(const char *str, time_t *time)
-{
- long int offset;
- struct tm tm;
-
- if ( 0 == isdigit(*str) || ZBX_CONST_STRLEN("1234-12-12T12:12:12") > strlen(str) ||
- ('T' != str[10] && ' ' != str[10]) ||
- '-' != str[4] || '-' != str[7] || ':' != str[13] || ':' != str[16])
- {
- return FAIL;
- }
-
- memset(&tm, 0 , sizeof (struct tm));
- tm.tm_year = atoi(str);
-
- if (0 == isdigit(str[5]) || 12 < (tm.tm_mon = atoi(&str[5])))
- return FAIL;
-
- if (0 == isdigit(str[8]) || 31 < (tm.tm_mday = atoi(&str[8])))
- return FAIL;
-
- if (0 == isdigit(str[11]) || 23 < (tm.tm_hour = atoi(&str[11])))
- return FAIL;
-
- if (0 == isdigit(str[14]) || 59 < (tm.tm_min = atoi(&str[14])))
- return FAIL;
-
- if (0 == isdigit(str[17]) || 59 < (tm.tm_sec = atoi(&str[17])))
- return FAIL;
-
- tm.tm_isdst = 0;
-
- if (FAIL == zbx_iso8601_timezone(&str[19], &offset))
- return FAIL;
-
- if (NULL != time)
- {
- int t;
-
- if(FAIL == zbx_utc_time(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, &t))
- return FAIL;
-
- *time = t - offset;
- }
-
- return SUCCEED;
-}