BLI_string: add BLI_str_quoted_substr_range

This is a similar funciton to BLI_str_quoted_substrN
that extracts the range of the quoted string
instead of allocating a new string un-escaped string.
This commit is contained in:
Campbell Barton
2021-09-01 15:23:58 +10:00
parent 90dac47717
commit f1cdd49a4e
2 changed files with 62 additions and 20 deletions

View File

@@ -57,6 +57,11 @@ size_t BLI_strncpy_rlen(char *__restrict dst,
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
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);
char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;

View File

@@ -419,6 +419,53 @@ const char *BLI_str_escape_find_quote(const char *str)
return (*str == '"') ? str : NULL;
}
/**
* 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)
{
const char *str_start = strstr(str, prefix);
if (str_start == NULL) {
return false;
}
const size_t prefix_len = strlen(prefix);
if (UNLIKELY(prefix_len == 0)) {
BLI_assert_msg(0,
"Zero length prefix passed in, "
"caller must prevent this from happening!");
return false;
}
BLI_assert_msg(prefix[prefix_len - 1] != '"',
"Prefix includes trailing quote, "
"caller must prevent this from happening!");
str_start += prefix_len;
if (UNLIKELY(*str_start != '\"')) {
return false;
}
str_start += 1;
const char *str_end = BLI_str_escape_find_quote(str_start);
if (UNLIKELY(str_end == NULL)) {
return false;
}
*r_start = (int)(str_start - str);
*r_end = (int)(str_end - str);
return true;
}
/**
* Makes a copy of the text within the "" that appear after some text `blahblah`.
* i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
@@ -431,27 +478,17 @@ const char *BLI_str_escape_find_quote(const char *str)
*/
char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix)
{
const char *start_match, *end_match;
/* get the starting point (i.e. where prefix starts, and add prefix_len+1
* to it to get be after the first " */
start_match = strstr(str, prefix);
if (start_match) {
const size_t prefix_len = strlen(prefix);
start_match += prefix_len + 1;
/* get the end point (i.e. where the next occurrence of " is after the starting point) */
end_match = BLI_str_escape_find_quote(start_match);
if (end_match) {
const size_t escaped_len = (size_t)(end_match - start_match);
char *result = MEM_mallocN(sizeof(char) * (escaped_len + 1), __func__);
const size_t unescaped_len = BLI_str_unescape(result, start_match, escaped_len);
if (unescaped_len != escaped_len) {
result = MEM_reallocN(result, sizeof(char) * (unescaped_len + 1));
}
return result;
}
int start_match_ofs, end_match_ofs;
if (!BLI_str_quoted_substr_range(str, prefix, &start_match_ofs, &end_match_ofs)) {
return NULL;
}
return NULL;
const size_t escaped_len = (size_t)(end_match_ofs - start_match_ofs);
char *result = MEM_mallocN(sizeof(char) * (escaped_len + 1), __func__);
const size_t unescaped_len = BLI_str_unescape(result, str + start_match_ofs, escaped_len);
if (unescaped_len != escaped_len) {
result = MEM_reallocN(result, sizeof(char) * (unescaped_len + 1));
}
return result;
}
/**