/* ** Zabbix ** Copyright (C) 2001-2023 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. **/ /* this file is for the minimal possible set of string related functions that are used by libzbxcommon.a */ /* or libraries/files it depends on */ #include "zbxcommon.h" /****************************************************************************** * * * 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: 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: 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: 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; } #if defined(_WINDOWS) || defined(__MINGW32__) /* 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 UTF-8 to unicode */ wchar_t *zbx_utf8_to_unicode(const char *utf8_string) { return zbx_to_unicode(CP_UTF8, utf8_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); } #endif