Cleanup: remove redundant, invalid info from headers
[blender.git] / source / blender / blenlib / intern / string_cursor_utf8.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file blender/blenlib/intern/string_cursor_utf8.c
21  *  \ingroup bli
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "BLI_utildefines.h"
28 #include "BLI_string_utf8.h"
29
30 #include "BLI_string_cursor_utf8.h" /* own include */
31
32 #ifdef __GNUC__
33 #  pragma GCC diagnostic error "-Wsign-conversion"
34 #endif
35
36 typedef enum eStrCursorDelimType {
37         STRCUR_DELIM_NONE,
38         STRCUR_DELIM_ALPHANUMERIC,
39         STRCUR_DELIM_PUNCT,
40         STRCUR_DELIM_BRACE,
41         STRCUR_DELIM_OPERATOR,
42         STRCUR_DELIM_QUOTE,
43         STRCUR_DELIM_WHITESPACE,
44         STRCUR_DELIM_OTHER
45 } eStrCursorDelimType;
46
47 static eStrCursorDelimType cursor_delim_type_unicode(const uint uch)
48 {
49         switch (uch) {
50                 case ',':
51                 case '.':
52                         return STRCUR_DELIM_PUNCT;
53
54                 case '{':
55                 case '}':
56                 case '[':
57                 case ']':
58                 case '(':
59                 case ')':
60                         return STRCUR_DELIM_BRACE;
61
62                 case '+':
63                 case '-':
64                 case '=':
65                 case '~':
66                 case '%':
67                 case '/':
68                 case '<':
69                 case '>':
70                 case '^':
71                 case '*':
72                 case '&':
73                 case '|':
74                         return STRCUR_DELIM_OPERATOR;
75
76                 case '\'':
77                 case '\"':
78                         return STRCUR_DELIM_QUOTE;
79
80                 case ' ':
81                 case '\t':
82                 case '\n':
83                         return STRCUR_DELIM_WHITESPACE;
84
85                 case '\\':
86                 case '@':
87                 case '#':
88                 case '$':
89                 case ':':
90                 case ';':
91                 case '?':
92                 case '!':
93                 case 0xA3:  /* pound */
94                 case 0x80:  /* euro */
95                         /* case '_': *//* special case, for python */
96                         return STRCUR_DELIM_OTHER;
97
98                 default:
99                         break;
100         }
101         return STRCUR_DELIM_ALPHANUMERIC; /* Not quite true, but ok for now */
102 }
103
104 static eStrCursorDelimType cursor_delim_type_utf8(const char *ch_utf8)
105 {
106         /* for full unicode support we really need to have large lookup tables to figure
107          * out whats what in every possible char set - and python, glib both have these. */
108         uint uch = BLI_str_utf8_as_unicode(ch_utf8);
109         return cursor_delim_type_unicode(uch);
110 }
111
112 bool BLI_str_cursor_step_next_utf8(const char *str, size_t maxlen, int *pos)
113 {
114         const char *str_end = str + (maxlen + 1);
115         const char *str_pos = str + (*pos);
116         const char *str_next = BLI_str_find_next_char_utf8(str_pos, str_end);
117         if (str_next) {
118                 (*pos) += (str_next - str_pos);
119                 if ((*pos) > (int)maxlen) {
120                         (*pos) = (int)maxlen;
121                 }
122                 return true;
123         }
124
125         return false;
126 }
127
128 bool BLI_str_cursor_step_prev_utf8(const char *str, size_t UNUSED(maxlen), int *pos)
129 {
130         if ((*pos) > 0) {
131                 const char *str_pos = str + (*pos);
132                 const char *str_prev = BLI_str_find_prev_char_utf8(str, str_pos);
133                 if (str_prev) {
134                         (*pos) -= (str_pos - str_prev);
135                         return true;
136                 }
137         }
138
139         return false;
140 }
141
142 void BLI_str_cursor_step_utf8(
143         const char *str, size_t maxlen,
144         int *pos, eStrCursorJumpDirection direction,
145         eStrCursorJumpType jump, bool use_init_step)
146 {
147         const int pos_orig = *pos;
148
149         if (direction == STRCUR_DIR_NEXT) {
150                 if (use_init_step) {
151                         BLI_str_cursor_step_next_utf8(str, maxlen, pos);
152                 }
153                 else {
154                         BLI_assert(jump == STRCUR_JUMP_DELIM);
155                 }
156
157                 if (jump != STRCUR_JUMP_NONE) {
158                         const eStrCursorDelimType delim_type =
159                                 (*pos) < maxlen ? cursor_delim_type_utf8(&str[*pos]) : STRCUR_DELIM_NONE;
160                         /* jump between special characters (/,\,_,-, etc.),
161                          * look at function cursor_delim_type() for complete
162                          * list of special character, ctr -> */
163                         while ((*pos) < maxlen) {
164                                 if (BLI_str_cursor_step_next_utf8(str, maxlen, pos)) {
165                                         if ((jump != STRCUR_JUMP_ALL) &&
166                                             (delim_type != cursor_delim_type_utf8(&str[*pos])))
167                                         {
168                                                 break;
169                                         }
170                                 }
171                                 else {
172                                         break; /* unlikely but just in case */
173                                 }
174                         }
175                 }
176         }
177         else if (direction == STRCUR_DIR_PREV) {
178                 if (use_init_step) {
179                         BLI_str_cursor_step_prev_utf8(str, maxlen, pos);
180                 }
181                 else {
182                         BLI_assert(jump == STRCUR_JUMP_DELIM);
183                 }
184
185                 if (jump != STRCUR_JUMP_NONE) {
186                         const eStrCursorDelimType delim_type =
187                                 (*pos) > 0 ? cursor_delim_type_utf8(&str[(*pos) - 1]) : STRCUR_DELIM_NONE;
188                         /* jump between special characters (/,\,_,-, etc.),
189                          * look at function cursor_delim_type() for complete
190                          * list of special character, ctr -> */
191                         while ((*pos) > 0) {
192                                 const int pos_prev = *pos;
193                                 if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) {
194                                         if ((jump != STRCUR_JUMP_ALL) &&
195                                             (delim_type != cursor_delim_type_utf8(&str[*pos])))
196                                         {
197                                                 /* left only: compensate for index/change in direction */
198                                                 if ((pos_orig - (*pos)) >= 1) {
199                                                         *pos = pos_prev;
200                                                 }
201                                                 break;
202                                         }
203                                 }
204                                 else {
205                                         break;
206                                 }
207                         }
208                 }
209         }
210         else {
211                 BLI_assert(0);
212         }
213 }
214
215 /* wchar_t version of BLI_str_cursor_step_utf8 (keep in sync!)
216  * less complex since it doesn't need to do multi-byte stepping.
217  */
218
219 /* helper funcs so we can match BLI_str_cursor_step_utf8 */
220 static bool wchar_t_step_next(const wchar_t *UNUSED(str), size_t maxlen, int *pos)
221 {
222         if ((*pos) >= (int)maxlen) {
223                 return false;
224         }
225         (*pos)++;
226         return true;
227 }
228
229 static bool wchar_t_step_prev(const wchar_t *UNUSED(str), size_t UNUSED(maxlen), int *pos)
230 {
231         if ((*pos) <= 0) {
232                 return false;
233         }
234         (*pos)--;
235         return true;
236 }
237
238 void BLI_str_cursor_step_wchar(
239         const wchar_t *str, size_t maxlen,
240         int *pos, eStrCursorJumpDirection direction,
241         eStrCursorJumpType jump, bool use_init_step)
242 {
243         const int pos_orig = *pos;
244
245         if (direction == STRCUR_DIR_NEXT) {
246                 if (use_init_step) {
247                         wchar_t_step_next(str, maxlen, pos);
248                 }
249                 else {
250                         BLI_assert(jump == STRCUR_JUMP_DELIM);
251                 }
252
253                 if (jump != STRCUR_JUMP_NONE) {
254                         const eStrCursorDelimType delim_type =
255                                 (*pos) < maxlen ? cursor_delim_type_unicode((uint)str[*pos]) : STRCUR_DELIM_NONE;
256                         /* jump between special characters (/,\,_,-, etc.),
257                          * look at function cursor_delim_type_unicode() for complete
258                          * list of special character, ctr -> */
259                         while ((*pos) < maxlen) {
260                                 if (wchar_t_step_next(str, maxlen, pos)) {
261                                         if ((jump != STRCUR_JUMP_ALL) &&
262                                             (delim_type != cursor_delim_type_unicode((uint)str[*pos])))
263                                         {
264                                                 break;
265                                         }
266                                 }
267                                 else {
268                                         break; /* unlikely but just in case */
269                                 }
270                         }
271                 }
272         }
273         else if (direction == STRCUR_DIR_PREV) {
274                 if (use_init_step) {
275                         wchar_t_step_prev(str, maxlen, pos);
276                 }
277                 else {
278                         BLI_assert(jump == STRCUR_JUMP_DELIM);
279                 }
280
281                 if (jump != STRCUR_JUMP_NONE) {
282                         const eStrCursorDelimType delim_type =
283                                 (*pos) > 0 ? cursor_delim_type_unicode((uint)str[(*pos) - 1]) : STRCUR_DELIM_NONE;
284                         /* jump between special characters (/,\,_,-, etc.),
285                          * look at function cursor_delim_type() for complete
286                          * list of special character, ctr -> */
287                         while ((*pos) > 0) {
288                                 const int pos_prev = *pos;
289                                 if (wchar_t_step_prev(str, maxlen, pos)) {
290                                         if ((jump != STRCUR_JUMP_ALL) &&
291                                             (delim_type != cursor_delim_type_unicode((uint)str[*pos])))
292                                         {
293                                                 /* left only: compensate for index/change in direction */
294                                                 if ((pos_orig - (*pos)) >= 1) {
295                                                         *pos = pos_prev;
296                                                 }
297                                                 break;
298                                         }
299                                 }
300                                 else {
301                                         break;
302                                 }
303                         }
304                 }
305         }
306         else {
307                 BLI_assert(0);
308         }
309 }