2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
* Copyright 2011 Blender Foundation. All rights reserved. */
|
2012-03-07 15:55:12 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bli
|
2012-03-09 18:28:30 +00:00
|
|
|
*/
|
2012-03-07 15:55:12 +00:00
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#include "BLI_string_utf8.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2012-03-07 15:55:12 +00:00
|
|
|
|
|
|
|
|
#include "BLI_string_cursor_utf8.h" /* own include */
|
|
|
|
|
|
2013-05-12 06:33:21 +00:00
|
|
|
#ifdef __GNUC__
|
|
|
|
|
# pragma GCC diagnostic error "-Wsign-conversion"
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
typedef enum eStrCursorDelimType {
|
2012-03-07 16:24:25 +00:00
|
|
|
STRCUR_DELIM_NONE,
|
2012-12-09 03:57:10 +00:00
|
|
|
STRCUR_DELIM_ALPHANUMERIC,
|
2012-03-07 16:24:25 +00:00
|
|
|
STRCUR_DELIM_PUNCT,
|
|
|
|
|
STRCUR_DELIM_BRACE,
|
|
|
|
|
STRCUR_DELIM_OPERATOR,
|
|
|
|
|
STRCUR_DELIM_QUOTE,
|
|
|
|
|
STRCUR_DELIM_WHITESPACE,
|
2019-04-16 16:40:47 +02:00
|
|
|
STRCUR_DELIM_OTHER,
|
2017-10-17 13:43:10 +11:00
|
|
|
} eStrCursorDelimType;
|
2012-03-07 15:55:12 +00:00
|
|
|
|
2017-10-28 17:48:45 +11:00
|
|
|
static eStrCursorDelimType cursor_delim_type_unicode(const uint uch)
|
2012-03-07 15:55:12 +00:00
|
|
|
{
|
2012-03-12 00:03:42 +00:00
|
|
|
switch (uch) {
|
2012-03-07 15:55:12 +00:00
|
|
|
case ',':
|
|
|
|
|
case '.':
|
|
|
|
|
return STRCUR_DELIM_PUNCT;
|
|
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
|
case '}':
|
|
|
|
|
case '[':
|
|
|
|
|
case ']':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
return STRCUR_DELIM_BRACE;
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
case '-':
|
|
|
|
|
case '=':
|
|
|
|
|
case '~':
|
|
|
|
|
case '%':
|
|
|
|
|
case '/':
|
|
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
case '^':
|
|
|
|
|
case '*':
|
|
|
|
|
case '&':
|
2012-12-09 03:57:10 +00:00
|
|
|
case '|':
|
2012-03-07 15:55:12 +00:00
|
|
|
return STRCUR_DELIM_OPERATOR;
|
|
|
|
|
|
|
|
|
|
case '\'':
|
2012-12-09 03:57:10 +00:00
|
|
|
case '\"':
|
2012-03-07 15:55:12 +00:00
|
|
|
return STRCUR_DELIM_QUOTE;
|
|
|
|
|
|
|
|
|
|
case ' ':
|
2012-04-30 13:14:15 +00:00
|
|
|
case '\t':
|
2013-12-29 16:54:43 +11:00
|
|
|
case '\n':
|
2012-03-07 15:55:12 +00:00
|
|
|
return STRCUR_DELIM_WHITESPACE;
|
|
|
|
|
|
|
|
|
|
case '\\':
|
|
|
|
|
case '@':
|
|
|
|
|
case '#':
|
|
|
|
|
case '$':
|
|
|
|
|
case ':':
|
|
|
|
|
case ';':
|
|
|
|
|
case '?':
|
2012-12-09 03:57:10 +00:00
|
|
|
case '!':
|
|
|
|
|
case 0xA3: /* pound */
|
|
|
|
|
case 0x80: /* euro */
|
2012-03-11 23:47:41 +00:00
|
|
|
/* case '_': */ /* special case, for python */
|
2012-03-07 15:55:12 +00:00
|
|
|
return STRCUR_DELIM_OTHER;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-12-09 03:57:10 +00:00
|
|
|
return STRCUR_DELIM_ALPHANUMERIC; /* Not quite true, but ok for now */
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
2021-08-25 15:19:00 +10:00
|
|
|
static eStrCursorDelimType cursor_delim_type_utf8(const char *ch_utf8,
|
|
|
|
|
const size_t ch_utf8_len,
|
|
|
|
|
const int pos)
|
2013-12-29 16:54:43 +11:00
|
|
|
{
|
|
|
|
|
/* for full unicode support we really need to have large lookup tables to figure
|
2019-08-01 13:53:25 +10:00
|
|
|
* out what's what in every possible char set - and python, glib both have these. */
|
2021-08-25 15:19:00 +10:00
|
|
|
size_t index = (size_t)pos;
|
|
|
|
|
uint uch = BLI_str_utf8_as_unicode_step_or_error(ch_utf8, ch_utf8_len, &index);
|
2013-12-29 16:54:43 +11:00
|
|
|
return cursor_delim_type_unicode(uch);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-27 08:39:24 -07:00
|
|
|
/* Keep in sync with BLI_str_cursor_step_next_utf32. */
|
2014-03-31 23:39:08 +11:00
|
|
|
bool BLI_str_cursor_step_next_utf8(const char *str, size_t maxlen, int *pos)
|
2012-03-07 15:55:12 +00:00
|
|
|
{
|
2022-09-27 08:39:24 -07:00
|
|
|
if ((*pos) >= (int)maxlen) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-03-11 23:47:41 +00:00
|
|
|
const char *str_end = str + (maxlen + 1);
|
|
|
|
|
const char *str_pos = str + (*pos);
|
2022-09-27 08:39:24 -07:00
|
|
|
const char *str_next = str_pos;
|
|
|
|
|
do {
|
|
|
|
|
str_next = BLI_str_find_next_char_utf8(str_next, str_end);
|
|
|
|
|
} while (str_next < str_end && str_next[0] != 0 && BLI_str_utf8_char_width(str_next) < 1);
|
|
|
|
|
(*pos) += (str_next - str_pos);
|
|
|
|
|
if ((*pos) > (int)maxlen) {
|
|
|
|
|
(*pos) = (int)maxlen;
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-27 08:39:24 -07:00
|
|
|
return true;
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-27 08:39:24 -07:00
|
|
|
/* Keep in sync with BLI_str_cursor_step_prev_utf32. */
|
|
|
|
|
bool BLI_str_cursor_step_prev_utf8(const char *str, size_t maxlen, int *pos)
|
2012-03-07 15:55:12 +00:00
|
|
|
{
|
2022-09-27 08:39:24 -07:00
|
|
|
if ((*pos) > 0 && (*pos) <= maxlen) {
|
2012-03-11 23:47:41 +00:00
|
|
|
const char *str_pos = str + (*pos);
|
2022-09-27 08:39:24 -07:00
|
|
|
const char *str_prev = str_pos;
|
|
|
|
|
do {
|
|
|
|
|
str_prev = BLI_str_find_prev_char_utf8(str_prev, str);
|
|
|
|
|
} while (str_prev > str && BLI_str_utf8_char_width(str_prev) == 0);
|
2021-08-27 16:42:31 +10:00
|
|
|
(*pos) -= (str_pos - str_prev);
|
|
|
|
|
return true;
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
void BLI_str_cursor_step_utf8(const char *str,
|
|
|
|
|
size_t maxlen,
|
|
|
|
|
int *pos,
|
|
|
|
|
eStrCursorJumpDirection direction,
|
|
|
|
|
eStrCursorJumpType jump,
|
|
|
|
|
bool use_init_step)
|
2012-03-07 15:55:12 +00:00
|
|
|
{
|
2013-05-06 03:35:21 +00:00
|
|
|
const int pos_orig = *pos;
|
2012-12-10 02:06:26 +00:00
|
|
|
|
2012-03-07 15:55:12 +00:00
|
|
|
if (direction == STRCUR_DIR_NEXT) {
|
2013-02-14 03:03:12 +00:00
|
|
|
if (use_init_step) {
|
|
|
|
|
BLI_str_cursor_step_next_utf8(str, maxlen, pos);
|
|
|
|
|
}
|
2013-02-14 05:02:20 +00:00
|
|
|
else {
|
|
|
|
|
BLI_assert(jump == STRCUR_JUMP_DELIM);
|
|
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
|
2012-03-07 15:55:12 +00:00
|
|
|
if (jump != STRCUR_JUMP_NONE) {
|
2021-08-25 15:19:00 +10:00
|
|
|
const eStrCursorDelimType delim_type = (*pos) < maxlen ?
|
|
|
|
|
cursor_delim_type_utf8(str, maxlen, *pos) :
|
|
|
|
|
STRCUR_DELIM_NONE;
|
2012-03-07 15:55:12 +00:00
|
|
|
/* jump between special characters (/,\,_,-, etc.),
|
2012-12-10 02:06:26 +00:00
|
|
|
* look at function cursor_delim_type() for complete
|
2012-03-07 15:55:12 +00:00
|
|
|
* list of special character, ctr -> */
|
2012-12-10 02:06:26 +00:00
|
|
|
while ((*pos) < maxlen) {
|
|
|
|
|
if (BLI_str_cursor_step_next_utf8(str, maxlen, pos)) {
|
2021-08-25 17:18:26 +10:00
|
|
|
if (*pos == maxlen) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-08-25 15:19:00 +10:00
|
|
|
if ((jump != STRCUR_JUMP_ALL) &&
|
|
|
|
|
(delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) {
|
2013-05-06 03:35:21 +00:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2013-05-06 03:35:21 +00:00
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
else {
|
|
|
|
|
break; /* unlikely but just in case */
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (direction == STRCUR_DIR_PREV) {
|
2013-02-14 03:03:12 +00:00
|
|
|
if (use_init_step) {
|
|
|
|
|
BLI_str_cursor_step_prev_utf8(str, maxlen, pos);
|
|
|
|
|
}
|
2013-02-14 05:02:20 +00:00
|
|
|
else {
|
|
|
|
|
BLI_assert(jump == STRCUR_JUMP_DELIM);
|
|
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
|
2012-03-11 23:47:41 +00:00
|
|
|
if (jump != STRCUR_JUMP_NONE) {
|
2017-10-17 13:43:10 +11:00
|
|
|
const eStrCursorDelimType delim_type = (*pos) > 0 ?
|
2021-08-25 15:19:00 +10:00
|
|
|
cursor_delim_type_utf8(str, maxlen, *pos - 1) :
|
2017-10-17 13:43:10 +11:00
|
|
|
STRCUR_DELIM_NONE;
|
2012-03-07 15:55:12 +00:00
|
|
|
/* jump between special characters (/,\,_,-, etc.),
|
2012-12-10 02:06:26 +00:00
|
|
|
* look at function cursor_delim_type() for complete
|
2012-03-07 15:55:12 +00:00
|
|
|
* list of special character, ctr -> */
|
2012-12-10 02:06:26 +00:00
|
|
|
while ((*pos) > 0) {
|
2013-05-06 03:35:21 +00:00
|
|
|
const int pos_prev = *pos;
|
2012-12-10 02:06:26 +00:00
|
|
|
if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) {
|
2021-08-25 15:19:00 +10:00
|
|
|
if ((jump != STRCUR_JUMP_ALL) &&
|
2021-12-22 08:39:33 -07:00
|
|
|
(delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) {
|
2013-05-06 03:35:21 +00:00
|
|
|
/* left only: compensate for index/change in direction */
|
|
|
|
|
if ((pos_orig - (*pos)) >= 1) {
|
|
|
|
|
*pos = pos_prev;
|
|
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
break;
|
2013-05-06 03:35:21 +00:00
|
|
|
}
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
else {
|
2012-03-07 15:55:12 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2012-12-10 02:06:26 +00:00
|
|
|
}
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-05-17 15:11:13 +02:00
|
|
|
BLI_assert_unreachable();
|
2012-03-07 15:55:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-12-29 16:54:43 +11:00
|
|
|
|
2022-09-27 08:39:24 -07:00
|
|
|
/* Keep in sync with BLI_str_cursor_step_next_utf8. */
|
|
|
|
|
bool BLI_str_cursor_step_next_utf32(const char32_t *str, size_t maxlen, int *pos)
|
2013-12-29 16:54:43 +11:00
|
|
|
{
|
|
|
|
|
if ((*pos) >= (int)maxlen) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-27 08:39:24 -07:00
|
|
|
do {
|
|
|
|
|
(*pos)++;
|
|
|
|
|
} while (*pos < (int)maxlen && str[*pos] != 0 && BLI_wcwidth(str[*pos]) == 0);
|
|
|
|
|
|
2013-12-29 16:54:43 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-27 08:39:24 -07:00
|
|
|
/* Keep in sync with BLI_str_cursor_step_prev_utf8. */
|
|
|
|
|
bool BLI_str_cursor_step_prev_utf32(const char32_t *str, size_t UNUSED(maxlen), int *pos)
|
2013-12-29 16:54:43 +11:00
|
|
|
{
|
|
|
|
|
if ((*pos) <= 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-27 08:39:24 -07:00
|
|
|
do {
|
|
|
|
|
(*pos)--;
|
|
|
|
|
} while (*pos > 0 && BLI_wcwidth(str[*pos]) == 0);
|
|
|
|
|
|
2013-12-29 16:54:43 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 12:26:54 -03:00
|
|
|
void BLI_str_cursor_step_utf32(const char32_t *str,
|
2017-10-17 13:43:10 +11:00
|
|
|
size_t maxlen,
|
|
|
|
|
int *pos,
|
|
|
|
|
eStrCursorJumpDirection direction,
|
|
|
|
|
eStrCursorJumpType jump,
|
|
|
|
|
bool use_init_step)
|
2013-12-29 16:54:43 +11:00
|
|
|
{
|
|
|
|
|
const int pos_orig = *pos;
|
|
|
|
|
|
|
|
|
|
if (direction == STRCUR_DIR_NEXT) {
|
|
|
|
|
if (use_init_step) {
|
2022-09-27 08:39:24 -07:00
|
|
|
BLI_str_cursor_step_next_utf32(str, maxlen, pos);
|
2013-12-29 16:54:43 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(jump == STRCUR_JUMP_DELIM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (jump != STRCUR_JUMP_NONE) {
|
2017-10-17 13:43:10 +11:00
|
|
|
const eStrCursorDelimType delim_type = (*pos) < maxlen ?
|
2017-10-28 17:48:45 +11:00
|
|
|
cursor_delim_type_unicode((uint)str[*pos]) :
|
|
|
|
|
STRCUR_DELIM_NONE;
|
2013-12-29 16:54:43 +11:00
|
|
|
/* jump between special characters (/,\,_,-, etc.),
|
|
|
|
|
* look at function cursor_delim_type_unicode() for complete
|
|
|
|
|
* list of special character, ctr -> */
|
|
|
|
|
while ((*pos) < maxlen) {
|
2022-09-27 08:39:24 -07:00
|
|
|
if (BLI_str_cursor_step_next_utf32(str, maxlen, pos)) {
|
2017-10-17 13:43:10 +11:00
|
|
|
if ((jump != STRCUR_JUMP_ALL) &&
|
2017-10-28 17:48:45 +11:00
|
|
|
(delim_type != cursor_delim_type_unicode((uint)str[*pos]))) {
|
2013-12-29 16:54:43 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
break; /* unlikely but just in case */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (direction == STRCUR_DIR_PREV) {
|
|
|
|
|
if (use_init_step) {
|
2022-09-27 08:39:24 -07:00
|
|
|
BLI_str_cursor_step_prev_utf32(str, maxlen, pos);
|
2013-12-29 16:54:43 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(jump == STRCUR_JUMP_DELIM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (jump != STRCUR_JUMP_NONE) {
|
2017-10-17 13:43:10 +11:00
|
|
|
const eStrCursorDelimType delim_type = (*pos) > 0 ?
|
2017-10-28 17:48:45 +11:00
|
|
|
cursor_delim_type_unicode((uint)str[(*pos) - 1]) :
|
|
|
|
|
STRCUR_DELIM_NONE;
|
2013-12-29 16:54:43 +11:00
|
|
|
/* jump between special characters (/,\,_,-, etc.),
|
|
|
|
|
* look at function cursor_delim_type() for complete
|
|
|
|
|
* list of special character, ctr -> */
|
|
|
|
|
while ((*pos) > 0) {
|
|
|
|
|
const int pos_prev = *pos;
|
2022-09-27 08:39:24 -07:00
|
|
|
if (BLI_str_cursor_step_prev_utf32(str, maxlen, pos)) {
|
2017-10-17 13:43:10 +11:00
|
|
|
if ((jump != STRCUR_JUMP_ALL) &&
|
2017-10-28 17:48:45 +11:00
|
|
|
(delim_type != cursor_delim_type_unicode((uint)str[*pos]))) {
|
2013-12-29 16:54:43 +11:00
|
|
|
/* left only: compensate for index/change in direction */
|
|
|
|
|
if ((pos_orig - (*pos)) >= 1) {
|
|
|
|
|
*pos = pos_prev;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-05-17 15:11:13 +02:00
|
|
|
BLI_assert_unreachable();
|
2013-12-29 16:54:43 +11:00
|
|
|
}
|
|
|
|
|
}
|