tornavis/source/blender/blenlib/BLI_string.h

638 lines
24 KiB
C++

/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bli
*/
#include <inttypes.h>
#include <stdarg.h>
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Buffer size of maximum `uint64` plus commas and terminator. */
#define BLI_STR_FORMAT_UINT64_GROUPED_SIZE 27
/* Buffer size of maximum `int32` with commas and terminator. */
#define BLI_STR_FORMAT_INT32_GROUPED_SIZE 15
/* Buffer size of maximum `int64` formatted as byte size (with GiB for example). */
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE 15
/* Buffer size of maximum `int32` formatted as compact decimal size ("15.6M" for example). */
#define BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE 7
/* Buffer size of maximum `int32` formatted as very short decimal size ("15B" for example). */
#define BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE 5
/**
* Duplicates the first \a len bytes of the C-string \a str
* into a newly mallocN'd string and returns it. \a str
* is assumed to be at least len bytes long.
*
* \param str: The string to be duplicated
* \param len: The number of bytes to duplicate
* \retval Returns the duplicated string
*/
char *BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Duplicates the C-string \a str into a newly mallocN'd
* string and returns it.
*
* \param str: The string to be duplicated
* \retval Returns the duplicated string
*/
char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC;
/**
* Duplicates the C-string \a str into a newly mallocN'd
* string and returns it.
*
* \param str: The string to be duplicated, can be null
* \retval Returns the duplicated string or null if \a str is null
*/
char *BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC;
/**
* Appends the two strings, and returns new mallocN'ed string
* \param str1: first string for copy
* \param str2: second string for append
* \retval Returns dst
*/
char *BLI_strdupcat(const char *__restrict str1,
const char *__restrict str2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2) ATTR_MALLOC;
/**
* Like `strncpy` but ensures dst is always `\0` terminated.
*
* \param dst: Destination for copy.
* \param src: Source string to copy.
* \param dst_maxncpy: Maximum number of characters to copy (generally the size of dst).
* \retval Returns dst
*/
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
ATTR_NONNULL(1, 2);
/**
* Like BLI_strncpy but ensures dst is always padded by given char,
* on both sides (unless `src` is empty).
*
* \param dst: Destination for copy
* \param src: Source string to copy
* \param pad: the char to use for padding
* \param dst_maxncpy: Maximum number of characters to copy (generally the size of dst).
* \retval Returns dst
*/
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
char pad,
size_t dst_maxncpy) ATTR_NONNULL(1, 2);
/**
* Like `strncpy` but ensures dst is always `\0` terminated.
*
* \note This is a duplicate of #BLI_strncpy that returns bytes copied.
* And is a drop in replacement for `snprintf(str, sizeof(str), "%s", arg);`
*
* \param dst: Destination for copy
* \param src: Source string to copy
* \param dst_maxncpy: Maximum number of characters to copy (generally the size of dst).
* \retval The number of bytes copied (The only difference from #BLI_strncpy).
*/
size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src,
size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
char *BLI_strncat(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
ATTR_NONNULL(1, 2);
/**
* A version of `strchr` that returns the end of the string (point to `\0`)
* if the character is not found.
*
* Useful for stepping over newlines up until the last line.
*/
const char *BLI_strchr_or_end(const char *str,
char ch) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
ATTR_NONNULL(1);
/**
* Return the range of the quoted string (excluding quotes) `str` after `prefix`.
*
* A version of #BLI_str_quoted_substrN that calculates the range
* instead of un-escaping and allocating the result.
*
* \param str: String potentially including `prefix`.
* \param prefix: Quoted string prefix.
* \param r_start: The start of the quoted string (after the first quote).
* \param r_end: The end of the quoted string (before the last quote).
* \return True when a quoted string range could be found after `prefix`.
*/
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
int *__restrict r_end) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3, 4);
#if 0 /* UNUSED */
char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2) ATTR_MALLOC;
#endif
/**
* Fills \a result with text within "" that appear after some the contents of \a prefix.
* i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
*
* \param str: is the entire string to chop.
* \param prefix: is the part of the string to step over.
* \param result: The buffer to fill.
* \param result_maxncpy: The maximum size of the buffer (including nil terminator).
* \return True if the prefix was found and the entire quoted string was copied into result.
*
* Assume that the strings returned must be freed afterwards,
* and that the inputs will contain data we want.
*/
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
size_t result_maxncpy);
/**
* Portable replacement for `snprintf`.
*/
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
/**
* A version of #BLI_snprintf that returns `strlen(dst)`
*/
size_t BLI_snprintf_rlen(char *__restrict dst,
size_t dst_maxncpy,
const char *__restrict format,
...) ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
/**
* Portable replacement for `vsnprintf`.
*/
size_t BLI_vsnprintf(char *__restrict dst,
size_t dst_maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
/**
* A version of #BLI_vsnprintf that returns `strlen(dst)`
*/
size_t BLI_vsnprintf_rlen(char *__restrict dst,
size_t dst_maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
char *BLI_sprintfN_with_buffer(char *fixed_buf,
size_t fixed_buf_size,
size_t *result_len,
const char *__restrict format,
...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3, 4)
ATTR_PRINTF_FORMAT(4, 5);
char *BLI_vsprintfN_with_buffer(char *fixed_buf,
size_t fixed_buf_size,
size_t *result_len,
const char *__restrict format,
va_list args) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3, 4)
ATTR_PRINTF_FORMAT(4, 0);
/**
* Print formatted string into a newly #MEM_mallocN'd string
* and return it.
*/
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
/** A version of #BLI_sprintfN that takes a #va_list. */
char *BLI_vsprintfN(const char *__restrict format, va_list args) ATTR_NONNULL(1, 2) ATTR_MALLOC
ATTR_PRINTF_FORMAT(1, 0);
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
*
* Since every character may need escaping,
* it's common to create a buffer twice as large as the input.
*
* \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
* \param src: The un-escaped source string.
* \param dst_maxncpy: The maximum number of bytes allowable to copy.
*
* \note This is used for creating animation paths in blend files.
*/
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
ATTR_NONNULL(1, 2);
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
*
* The destination will never be larger than the source, it will either be the same
* or up to half when all characters are escaped.
*
* \param dst: The destination string, at least the size of `strlen(src) + 1`.
* \param src: The escaped source string.
* \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
* \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
* \param r_is_complete: Set to true when.
*/
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
size_t src_maxncpy,
/* Additional arguments. */
size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL(1, 2, 5);
/**
* See #BLI_str_unescape_ex doc-string.
*
* This function makes the assumption that `dst` always has
* at least `src_maxncpy` bytes available.
*
* Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
*
* \note This is used for parsing animation paths in blend files (runs often).
*/
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t src_maxncpy)
ATTR_NONNULL(1, 2);
/**
* Find the first un-escaped quote in the string (to find the end of the string).
*
* \param str: Typically this is the first character in a quoted string.
* Where the character before `*str` would be `"`.
*
* \return The pointer to the first un-escaped quote.
*/
const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(1);
/**
* Format integers with decimal grouping.
* 1000 -> 1,000
*
* \param dst: The resulting string.
* \param num: Number to format.
* \return The length of \a dst
*/
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num)
ATTR_NONNULL(1);
/**
* Format uint64_t with decimal grouping.
* 1000 -> 1,000
*
* \param dst: The resulting string.
* \param num: Number to format.
* \return The length of \a dst.
*/
size_t BLI_str_format_uint64_grouped(char dst[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], uint64_t num)
ATTR_NONNULL(1);
/**
* Format a size in bytes using binary units.
* 1000 -> 1 KB
* Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
*
* \param dst: The resulting string.
* Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
* \param bytes: Number to format.
* \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
*/
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE],
long long int bytes,
bool base_10) ATTR_NONNULL(1);
/**
* Format a count to up to 6 places (plus `\0` terminator) string using long number
* names abbreviations. Used to produce a compact representation of large numbers.
*
* 1 -> 1
* 15 -> 15
* 155 -> 155
* 1555 -> 1.6K
* 15555 -> 15.6K
* 155555 -> 156K
* 1555555 -> 1.6M
* 15555555 -> 15.6M
* 155555555 -> 156M
* 1000000000 -> 1B
* ...
*
* Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
*/
void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE],
int number_to_format) ATTR_NONNULL(1);
/**
* Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long
* number names abbreviations. Used to produce a compact representation of large numbers as
* integers.
*
* It shows a lower bound instead of rounding the number.
*
* 1 -> 1
* 15 -> 15
* 155 -> 155
* 1555 -> 1K
* 15555 -> 15K
* 155555 -> .1M
* 1555555 -> 1M
* 15555555 -> 15M
* 155555555 -> .1B
* 1000000000 -> 1B
* ...
*
* Length of 5 is the maximum of the resulting string, for example, `-15K\0`.
*/
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE],
int number_to_format) ATTR_NONNULL(1);
/**
* Compare two strings without regard to case.
*
* \retval True if the strings are equal, false otherwise.
*/
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Portable replacement for `strcasestr` (not available in MSVC)
*/
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Variation of #BLI_strcasestr with string length limited to \a len
*/
char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
/**
* Case insensitive, *natural* string comparison,
* keeping numbers in order.
*/
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
/**
* Like `strcmp`, but will ignore any heading/trailing pad char for comparison.
* So e.g. if pad is `*`, `*world` and `world*` will compare equal.
*/
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
/**
* Determine the length of a fixed-size string.
*/
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* String case conversion, not affected by locale.
*/
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL(1);
void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL(1);
char BLI_tolower_ascii(const char c) ATTR_WARN_UNUSED_RESULT;
char BLI_toupper_ascii(const char c) ATTR_WARN_UNUSED_RESULT;
/**
* Strip white-space from end of the string.
*/
void BLI_str_rstrip(char *str) ATTR_NONNULL(1);
/**
* Strip trailing zeros from a float, eg:
* - 0.0000 -> 0.0
* - 2.0010 -> 2.001
*
* \param str:
* \param pad:
* \return The number of zeros stripped.
*/
int BLI_str_rstrip_float_zero(char *str, char pad) ATTR_NONNULL(1);
/**
* Strip trailing digits.
* - ABC123 -> ABC
*
* \param str:
* \return The number of digits stripped.
*/
int BLI_str_rstrip_digits(char *str) ATTR_NONNULL();
/**
* Return index of a string in a string array.
*
* \param str: The string to find.
* \param str_array: Array of strings.
* \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
* \return The index of str in str_array or -1.
*/
int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array,
int str_array_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Return index of a string in a string array.
*
* \param str: The string to find.
* \param str_array: Array of strings, (must be NULL-terminated).
* \return The index of str in str_array or -1.
*/
int BLI_str_index_in_array(const char *__restrict str,
const char **__restrict str_array) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
/**
* Find if a string starts with another string.
*
* \param str: The string to search within.
* \param start: The string we look for at the start.
* \return If str starts with start.
*/
bool BLI_str_startswith(const char *__restrict str,
const char *__restrict start) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Find if a string ends with another string.
*
* \param str: The string to search within.
* \param end: The string we look for at the end.
* \return If str ends with end.
*/
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1, 2);
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length)
ATTR_NONNULL(1, 2);
/**
* Find the first char matching one of the chars in \a delim, from left.
*
* \param str: The string to search within.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL(1, 2, 3, 4);
/**
* Find the first char matching one of the chars in \a delim, from right.
*
* \param str: The string to search within.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL(1, 2, 3, 4);
/**
* Find the first char matching one of the chars in \a delim, either from left or right.
*
* \param str: The string to search within.
* \param end: If non-NULL, the right delimiter of the string.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \param from_right: If %true, search from the right of \a str, else, search from its left.
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
const char **sep,
const char **suf,
bool from_right) ATTR_NONNULL(1, 3, 4, 5);
int BLI_string_max_possible_word_count(int str_len) ATTR_WARN_UNUSED_RESULT;
bool BLI_string_has_word_prefix(const char *haystack,
const char *needle,
size_t needle_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
bool BLI_string_all_words_matched(const char *name,
const char *str,
int (*words)[2],
int words_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
/**
* Find the ranges needed to split \a str into its individual words.
*
* \param str: The string to search for words.
* \param str_maxlen: Size of the string to search (ignored when larger than `strlen(str)`).
* \param delim: Character to use as a delimiter.
* \param r_words: Info about the words found. Set to [index, len] pairs.
* \param words_max: Max number of words to find
* \return The number of words found in \a str
*/
int BLI_string_find_split_words(const char *str,
size_t str_maxlen,
char delim,
int r_words[][2],
int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 4);
/* -------------------------------------------------------------------- */
/** \name String Copy/Format Macros
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
#ifndef __cplusplus
# define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
#endif
#define STRNCPY_RLEN(dst, src) BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
#define SNPRINTF(dst, format, ...) BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
#define SNPRINTF_RLEN(dst, format, ...) \
BLI_snprintf_rlen(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
#define VSNPRINTF(dst, format, args) BLI_vsnprintf(dst, ARRAY_SIZE(dst), format, args)
#define VSNPRINTF_RLEN(dst, format, args) BLI_vsnprintf_rlen(dst, ARRAY_SIZE(dst), format, args)
#define STR_CONCAT(dst, len, suffix) \
len += BLI_strncpy_rlen(dst + len, suffix, ARRAY_SIZE(dst) - len)
#define STR_CONCATF(dst, len, format, ...) \
len += BLI_snprintf_rlen(dst + len, ARRAY_SIZE(dst) - len, format, __VA_ARGS__)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Equal to Any Element (STR_ELEM) Macro
*
* Follows #ELEM macro convention.
* \{ */
/* Manual line breaks for readability. */
/* clang-format off */
/* STR_ELEM#(v, ...): is the first arg equal any others? */
/* Internal helpers. */
#define _VA_STR_ELEM2(v, a) (strcmp(v, a) == 0)
#define _VA_STR_ELEM3(v, a, b) \
(_VA_STR_ELEM2(v, a) || (_VA_STR_ELEM2(v, b)))
#define _VA_STR_ELEM4(v, a, b, c) \
(_VA_STR_ELEM3(v, a, b) || (_VA_STR_ELEM2(v, c)))
#define _VA_STR_ELEM5(v, a, b, c, d) \
(_VA_STR_ELEM4(v, a, b, c) || (_VA_STR_ELEM2(v, d)))
#define _VA_STR_ELEM6(v, a, b, c, d, e) \
(_VA_STR_ELEM5(v, a, b, c, d) || (_VA_STR_ELEM2(v, e)))
#define _VA_STR_ELEM7(v, a, b, c, d, e, f) \
(_VA_STR_ELEM6(v, a, b, c, d, e) || (_VA_STR_ELEM2(v, f)))
#define _VA_STR_ELEM8(v, a, b, c, d, e, f, g) \
(_VA_STR_ELEM7(v, a, b, c, d, e, f) || (_VA_STR_ELEM2(v, g)))
#define _VA_STR_ELEM9(v, a, b, c, d, e, f, g, h) \
(_VA_STR_ELEM8(v, a, b, c, d, e, f, g) || (_VA_STR_ELEM2(v, h)))
#define _VA_STR_ELEM10(v, a, b, c, d, e, f, g, h, i) \
(_VA_STR_ELEM9(v, a, b, c, d, e, f, g, h) || (_VA_STR_ELEM2(v, i)))
#define _VA_STR_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \
(_VA_STR_ELEM10(v, a, b, c, d, e, f, g, h, i) || (_VA_STR_ELEM2(v, j)))
#define _VA_STR_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \
(_VA_STR_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || (_VA_STR_ELEM2(v, k)))
#define _VA_STR_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \
(_VA_STR_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || (_VA_STR_ELEM2(v, l)))
#define _VA_STR_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
(_VA_STR_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || (_VA_STR_ELEM2(v, m)))
#define _VA_STR_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
(_VA_STR_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || (_VA_STR_ELEM2(v, n)))
#define _VA_STR_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
(_VA_STR_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || (_VA_STR_ELEM2(v, o)))
#define _VA_STR_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
(_VA_STR_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || (_VA_STR_ELEM2(v, p)))
/* clang-format on */
/* reusable STR_ELEM macro */
#define STR_ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_STR_ELEM, __VA_ARGS__)
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Debugging
* \{ */
#ifdef WITH_STRSIZE_DEBUG
# define BLI_string_debug_size(str, str_maxncpy) memset(str, 0xff, sizeof(*(str)) * str_maxncpy)
/**
* Fill `str` with a non-nil value after the trailing nil character,
* use to ensure buffer sizes passed to string functions are correct.
*/
void BLI_string_debug_size_after_nil(char *str, size_t str_maxncpy);
#else
# define BLI_string_debug_size(str, str_maxncpy) \
if (0) { \
(void)str, (void)str_maxncpy; \
} \
((void)0)
# define BLI_string_debug_size_after_nil(str, str_maxncpy) BLI_string_debug_size(str, str_maxncpy)
#endif /* !WITH_STRSIZE_DEBUG */
/** \} */
#ifdef __cplusplus
}
/**
* Copy source string str into the destination dst of a size known at a compile time.
* Ensures that the destination is not overflown, and that the destination is always
* null-terminated.
*
* Returns the dst.
*/
template<size_t N> inline char *STRNCPY(char (&dst)[N], const char *src)
{
return BLI_strncpy(dst, src, N);
}
#endif /* __cplusplus */