Merging r58464 through r58474 from trunk into soc-2013-depsgraph_mt
[blender.git] / source / blender / blenlib / intern / string_utf8.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * Code from gutf8.c Copyright (C) 1999 Tom Tromey
20  *                   Copyright (C) 2000 Red Hat, Inc.
21  * All rights reserved.
22  *
23  * Contributor(s): Campbell Barton.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29  /** \file blender/blenlib/intern/string_utf8.c
30   *  \ingroup bli
31   */
32
33 #include <string.h>
34 #include <wchar.h>
35 #include <wctype.h>
36 #include <wcwidth.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 #include "BLI_utildefines.h"
41
42 #include "BLI_string_utf8.h"  /* own include */
43
44 #ifdef __GNUC__
45 #  pragma GCC diagnostic error "-Wsign-conversion"
46 #endif
47
48 // #define DEBUG_STRSIZE
49
50 /* from libswish3, originally called u8_isvalid(),
51  * modified to return the index of the bad character (byte index not utf).
52  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
53
54 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
55  *
56  * length is in bytes, since without knowing whether the string is valid
57  * it's hard to know how many characters there are! */
58
59 static const char trailingBytesForUTF8[256] = {
60         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
68 };
69
70 int BLI_utf8_invalid_byte(const char *str, int length)
71 {
72         const unsigned char *p, *pend = (unsigned char *)str + length;
73         unsigned char c;
74         int ab;
75
76         for (p = (unsigned char *)str; p < pend; p++) {
77                 c = *p;
78                 if (c < 128)
79                         continue;
80                 if ((c & 0xc0) != 0xc0)
81                         goto utf8_error;
82                 ab = trailingBytesForUTF8[c];
83                 if (length < ab)
84                         goto utf8_error;
85                 length -= ab;
86
87                 p++;
88                 /* Check top bits in the second byte */
89                 if ((*p & 0xc0) != 0x80)
90                         goto utf8_error;
91
92                 /* Check for overlong sequences for each different length */
93                 switch (ab) {
94                         /* Check for xx00 000x */
95                 case 1:
96                         if ((c & 0x3e) == 0) goto utf8_error;
97                         continue;   /* We know there aren't any more bytes to check */
98
99                         /* Check for 1110 0000, xx0x xxxx */
100                 case 2:
101                         if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
102                         break;
103
104                         /* Check for 1111 0000, xx00 xxxx */
105                 case 3:
106                         if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
107                         break;
108
109                         /* Check for 1111 1000, xx00 0xxx */
110                 case 4:
111                         if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
112                         break;
113
114                         /* Check for leading 0xfe or 0xff,
115                          * and then for 1111 1100, xx00 00xx */
116                 case 5:
117                         if (c == 0xfe || c == 0xff ||
118                                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
119                         break;
120                 }
121
122                 /* Check for valid bytes after the 2nd, if any; all must start 10 */
123                 while (--ab > 0) {
124                         if ((*(p + 1) & 0xc0) != 0x80) goto utf8_error;
125                         p++; /* do this after so we get usable offset - campbell */
126                 }
127         }
128
129         return -1;
130
131 utf8_error:
132
133         return (int)((char *)p - (char *)str) - 1;
134 }
135
136 int BLI_utf8_invalid_strip(char *str, int length)
137 {
138         int bad_char, tot = 0;
139
140         while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
141                 str += bad_char;
142                 length -= bad_char;
143
144                 if (length == 0) {
145                         /* last character bad, strip it */
146                         *str = '\0';
147                         tot++;
148                         break;
149                 }
150                 else {
151                         /* strip, keep looking */
152                         memmove(str, str + 1, (size_t)length);
153                         tot++;
154                 }
155         }
156
157         return tot;
158 }
159
160
161 /* compatible with BLI_strncpy, but esnure no partial utf8 chars */
162
163 /* array copied from glib's gutf8.c,
164  * note: this looks to be at odd's with 'trailingBytesForUTF8',
165  * need to find out what gives here! - campbell */
166 static const size_t utf8_skip_data[256] = {
167         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
168         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
169         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
170         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
171         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
172         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
173         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
174         3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
175 };
176
177 #define BLI_STR_UTF8_CPY(dst, src, maxncpy)                                   \
178         {                                                                         \
179                 size_t utf8_size;                                                     \
180                 while (*src != '\0' && (utf8_size = utf8_skip_data[*src]) < maxncpy) {\
181                         maxncpy -= utf8_size;                                             \
182                         switch (utf8_size) {                                              \
183                                 case 6: *dst ++ = *src ++;                                    \
184                                 case 5: *dst ++ = *src ++;                                    \
185                                 case 4: *dst ++ = *src ++;                                    \
186                                 case 3: *dst ++ = *src ++;                                    \
187                                 case 2: *dst ++ = *src ++;                                    \
188                                 case 1: *dst ++ = *src ++;                                    \
189                         }                                                                 \
190                 }                                                                     \
191                 *dst = '\0';                                                          \
192         } (void)0
193
194 char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy)
195 {
196         char *dst_r = dst;
197
198         BLI_assert(maxncpy != 0);
199
200 #ifdef DEBUG_STRSIZE
201         memset(dst, 0xff, sizeof(*dst) * maxncpy);
202 #endif
203
204         /* note: currently we don't attempt to deal with invalid utf8 chars */
205         BLI_STR_UTF8_CPY(dst, src, maxncpy);
206
207         return dst_r;
208 }
209
210 char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy)
211 {
212         while (*dst && maxncpy > 0) {
213                 dst++;
214                 maxncpy--;
215         }
216
217 #ifdef DEBUG_STRSIZE
218         memset(dst, 0xff, sizeof(*dst) * maxncpy);
219 #endif
220
221         BLI_STR_UTF8_CPY(dst, src, maxncpy);
222
223         return dst;
224 }
225
226 #undef BLI_STR_UTF8_CPY
227
228 /* --------------------------------------------------------------------------*/
229 /* wchar_t / utf8 functions  */
230
231 size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxncpy)
232 {
233         const size_t maxlen = maxncpy - 1;
234         size_t len = 0;
235
236         BLI_assert(maxncpy != 0);
237
238 #ifdef DEBUG_STRSIZE
239         memset(dst, 0xff, sizeof(*dst) * maxncpy);
240 #endif
241
242         while (*src && len < maxlen) { /* XXX can still run over the buffer because utf8 size isn't known :| */
243                 len += BLI_str_utf8_from_unicode((unsigned int)*src++, dst + len);
244         }
245
246         dst[len] = '\0';
247
248         return len;
249 }
250
251 /* wchar len in utf8 */
252 size_t BLI_wstrlen_utf8(const wchar_t *src)
253 {
254         size_t len = 0;
255
256         while (*src) {
257                 len += BLI_str_utf8_from_unicode((unsigned int)*src++, NULL);
258         }
259
260         return len;
261 }
262
263 size_t BLI_strlen_utf8_ex(const char *strc, int *r_len_bytes)
264 {
265         size_t len;
266         const char *strc_orig = strc;
267
268         for (len = 0; *strc; len++)
269                 strc += BLI_str_utf8_size_safe(strc);
270
271         *r_len_bytes = (strc - strc_orig);
272         return len;
273 }
274
275 size_t BLI_strlen_utf8(const char *strc)
276 {
277         size_t len;
278
279         for (len = 0; *strc; len++)
280                 strc += BLI_str_utf8_size_safe(strc);
281
282         return len;
283 }
284
285 size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, int *r_len_bytes)
286 {
287         size_t len;
288         const char *strc_orig = strc;
289         const char *strc_end = strc + maxlen;
290
291         for (len = 0; *strc && strc < strc_end; len++) {
292                 strc += BLI_str_utf8_size_safe(strc);
293         }
294
295         *r_len_bytes = (strc - strc_orig);
296         return len;
297 }
298
299 /**
300  * \param start the string to measure the length.
301  * \param maxlen the string length (in bytes)
302  * \return the unicode length (not in bytes!)
303  */
304 size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
305 {
306         size_t len;
307         const char *strc_end = strc + maxlen;
308
309         for (len = 0; *strc && strc < strc_end; len++) {
310                 strc += BLI_str_utf8_size_safe(strc);
311         }
312
313         return len;
314 }
315
316 size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w, const char *__restrict src_c, const size_t maxncpy)
317 {
318         const size_t maxlen = maxncpy - 1;
319         size_t len = 0;
320
321         BLI_assert(maxncpy != 0);
322
323 #ifdef DEBUG_STRSIZE
324         memset(dst_w, 0xff, sizeof(*dst_w) * maxncpy);
325 #endif
326
327         while (*src_c && len != maxlen) {
328                 size_t step = 0;
329                 unsigned int unicode = BLI_str_utf8_as_unicode_and_size(src_c, &step);
330                 if (unicode != BLI_UTF8_ERR) {
331                         *dst_w = (wchar_t)unicode;
332                         src_c += step;
333                 }
334                 else {
335                         *dst_w = '?';
336                         src_c = BLI_str_find_next_char_utf8(src_c, NULL);
337                 }
338                 dst_w++;
339                 len++;
340         }
341
342         *dst_w = 0;
343
344         return len;
345 }
346
347 /* end wchar_t / utf8 functions  */
348 /* --------------------------------------------------------------------------*/
349
350 /* count columns that character/string occupies, based on wcwidth.c */
351
352 int BLI_wcwidth(wchar_t ucs)
353 {
354         return mk_wcwidth(ucs);
355 }
356
357 int BLI_wcswidth(const wchar_t *pwcs, size_t n)
358 {
359         return mk_wcswidth(pwcs, n);
360 }
361
362 int BLI_str_utf8_char_width(const char *p)
363 {
364         unsigned int unicode = BLI_str_utf8_as_unicode(p);
365         if (unicode == BLI_UTF8_ERR)
366                 return -1;
367
368         return BLI_wcwidth((wchar_t)unicode);
369 }
370
371 int BLI_str_utf8_char_width_safe(const char *p)
372 {
373         int columns;
374
375         unsigned int unicode = BLI_str_utf8_as_unicode(p);
376         if (unicode == BLI_UTF8_ERR)
377                 return 1;
378
379         columns = BLI_wcwidth((wchar_t)unicode);
380
381         return (columns < 0) ? 1 : columns;
382 }
383
384 /* --------------------------------------------------------------------------*/
385
386 /* copied from glib's gutf8.c, added 'Err' arg */
387
388 /* note, glib uses unsigned int for unicode, best we do the same,
389  * though we don't typedef it - campbell */
390
391 #define UTF8_COMPUTE(Char, Mask, Len, Err)                                    \
392         if (Char < 128) {                                                         \
393                 Len = 1;                                                              \
394                 Mask = 0x7f;                                                          \
395         }                                                                         \
396         else if ((Char & 0xe0) == 0xc0) {                                         \
397                 Len = 2;                                                              \
398                 Mask = 0x1f;                                                          \
399         }                                                                         \
400         else if ((Char & 0xf0) == 0xe0) {                                         \
401                 Len = 3;                                                              \
402                 Mask = 0x0f;                                                          \
403         }                                                                         \
404         else if ((Char & 0xf8) == 0xf0) {                                         \
405                 Len = 4;                                                              \
406                 Mask = 0x07;                                                          \
407         }                                                                         \
408         else if ((Char & 0xfc) == 0xf8) {                                         \
409                 Len = 5;                                                              \
410                 Mask = 0x03;                                                          \
411         }                                                                         \
412         else if ((Char & 0xfe) == 0xfc) {                                         \
413                 Len = 6;                                                              \
414                 Mask = 0x01;                                                          \
415         }                                                                         \
416         else {                                                                    \
417                 Len = Err;  /* -1 is the typical error value or 1 to skip */          \
418         } (void)0
419
420 /* same as glib define but added an 'Err' arg */
421 #define UTF8_GET(Result, Chars, Count, Mask, Len, Err)                        \
422         (Result) = (Chars)[0] & (Mask);                                           \
423         for ((Count) = 1; (Count) < (Len); ++(Count)) {                           \
424                 if (((Chars)[(Count)] & 0xc0) != 0x80) {                              \
425                         (Result) = Err;                                                   \
426                         break;                                                            \
427                 }                                                                     \
428                 (Result) <<= 6;                                                       \
429                 (Result) |= ((Chars)[(Count)] & 0x3f);                                \
430         } (void)0
431
432
433 /* uses glib functions but not from glib */
434 /* gets the size of a single utf8 char */
435 int BLI_str_utf8_size(const char *p)
436 {
437         int mask = 0, len;
438         const unsigned char c = (unsigned char) *p;
439
440         UTF8_COMPUTE (c, mask, len, -1);
441
442         (void)mask; /* quiet warning */
443
444         return len;
445 }
446
447 /* use when we want to skip errors */
448 int BLI_str_utf8_size_safe(const char *p)
449 {
450         int mask = 0, len;
451         const unsigned char c = (unsigned char) *p;
452
453         UTF8_COMPUTE (c, mask, len, 1);
454
455         (void)mask; /* quiet warning */
456
457         return len;
458 }
459
460 /* was g_utf8_get_char */
461 /**
462  * BLI_str_utf8_as_unicode:
463  * \param p a pointer to Unicode character encoded as UTF-8
464  *
465  * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
466  * If \a p does not point to a valid UTF-8 encoded character, results are
467  * undefined. If you are not sure that the bytes are complete
468  * valid Unicode characters, you should use g_utf8_get_char_validated()
469  * instead.
470  *
471  * Return value: the resulting character
472  **/
473 unsigned int BLI_str_utf8_as_unicode(const char *p)
474 {
475         int i, len;
476         unsigned int mask = 0;
477         unsigned int result;
478         const unsigned char c = (unsigned char) *p;
479
480         UTF8_COMPUTE (c, mask, len, -1);
481         if (UNLIKELY(len == -1))
482                 return BLI_UTF8_ERR;
483         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
484
485         return result;
486 }
487
488 /* variant that increments the length */
489 unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index)
490 {
491         int i, len;
492         unsigned mask = 0;
493         unsigned int result;
494         const unsigned char c = (unsigned char) *p;
495
496         UTF8_COMPUTE (c, mask, len, -1);
497         if (UNLIKELY(len == -1))
498                 return BLI_UTF8_ERR;
499         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
500         *index += (size_t)len;
501         return result;
502 }
503
504 unsigned int BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, size_t *__restrict index)
505 {
506         int i, len;
507         unsigned int mask = 0;
508         unsigned int result;
509         const unsigned char c = (unsigned char) *p;
510
511         UTF8_COMPUTE (c, mask, len, -1);
512         if (UNLIKELY(len == -1)) {
513                 *index += 1;
514                 return c;
515         }
516         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
517         *index += (size_t)len;
518         return result;
519 }
520
521 /* another variant that steps over the index,
522  * note, currently this also falls back to latin1 for text drawing. */
523 unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index)
524 {
525         int i, len;
526         unsigned int mask = 0;
527         unsigned int result;
528         unsigned char c;
529
530         p += *index;
531         c = (unsigned char) *p;
532
533         UTF8_COMPUTE (c, mask, len, -1);
534         if (UNLIKELY(len == -1)) {
535                 /* when called with NULL end, result will never be NULL,
536                  * checks for a NULL character */
537                 char *p_next = BLI_str_find_next_char_utf8(p, NULL);
538                 /* will never return the same pointer unless '\0',
539                  * eternal loop is prevented */
540                 *index += (size_t)(p_next - p);
541                 return BLI_UTF8_ERR;
542         }
543
544         /* this is tricky since there are a few ways we can bail out of bad unicode
545          * values, 3 possible solutions. */
546 #if 0
547         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
548 #elif 1
549         /* WARNING: this is NOT part of glib, or supported by similar functions.
550          * this is added for text drawing because some filepaths can have latin1
551          * characters */
552         UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR);
553         if (result == BLI_UTF8_ERR) {
554                 len = 1;
555                 result = *p;
556         }
557         /* end warning! */
558 #else
559         /* without a fallback like '?', text drawing will stop on this value */
560         UTF8_GET (result, p, i, mask, len, '?');
561 #endif
562
563         *index += (size_t)len;
564         return result;
565 }
566
567 /* was g_unichar_to_utf8 */
568 /**
569  * BLI_str_utf8_from_unicode:
570  * @c a Unicode character code
571  * \param outbuf output buffer, must have at least 6 bytes of space.
572  *       If %NULL, the length will be computed and returned
573  *       and nothing will be written to outbuf.
574  *
575  * Converts a single character to UTF-8.
576  *
577  * Return value: number of bytes written
578  **/
579 size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf)
580 {
581         /* If this gets modified, also update the copy in g_string_insert_unichar() */
582         unsigned int len = 0;
583         unsigned int first;
584         unsigned int i;
585
586         if (c < 0x80) {
587                 first = 0;
588                 len = 1;
589         }
590         else if (c < 0x800) {
591                 first = 0xc0;
592                 len = 2;
593         }
594         else if (c < 0x10000) {
595                 first = 0xe0;
596                 len = 3;
597         }
598         else if (c < 0x200000) {
599                 first = 0xf0;
600                 len = 4;
601         }
602         else if (c < 0x4000000) {
603                 first = 0xf8;
604                 len = 5;
605         }
606         else {
607                 first = 0xfc;
608                 len = 6;
609         }
610
611         if (outbuf) {
612                 for (i = len - 1; i > 0; --i) {
613                         outbuf[i] = (c & 0x3f) | 0x80;
614                         c >>= 6;
615                 }
616                 outbuf[0] = c | first;
617         }
618
619         return len;
620 }
621
622 /* was g_utf8_find_prev_char */
623 /**
624  * BLI_str_find_prev_char_utf8:
625  * \param str pointer to the beginning of a UTF-8 encoded string
626  * \param p pointer to some position within \a str
627  *
628  * Given a position \a p with a UTF-8 encoded string \a str, find the start
629  * of the previous UTF-8 character starting before. \a p Returns %NULL if no
630  * UTF-8 characters are present in \a str before \a p
631  *
632  * \a p does not have to be at the beginning of a UTF-8 character. No check
633  * is made to see if the character found is actually valid other than
634  * it starts with an appropriate byte.
635  *
636  * Return value: a pointer to the found character or %NULL.
637  **/
638 char *BLI_str_find_prev_char_utf8(const char *str, const char *p)
639 {
640         for (--p; p >= str; --p) {
641                 if ((*p & 0xc0) != 0x80) {
642                         return (char *)p;
643                 }
644         }
645         return NULL;
646 }
647
648 /* was g_utf8_find_next_char */
649 /**
650  * BLI_str_find_next_char_utf8:
651  * \param p a pointer to a position within a UTF-8 encoded string
652  * \param end a pointer to the byte following the end of the string,
653  * or %NULL to indicate that the string is nul-terminated.
654  *
655  * Finds the start of the next UTF-8 character in the string after \a p
656  *
657  * \a p does not have to be at the beginning of a UTF-8 character. No check
658  * is made to see if the character found is actually valid other than
659  * it starts with an appropriate byte.
660  *
661  * Return value: a pointer to the found character or %NULL
662  **/
663 char *BLI_str_find_next_char_utf8(const char *p, const char *end)
664 {
665         if (*p) {
666                 if (end) {
667                         for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
668                                 /* do nothing */
669                         }
670                 }
671                 else {
672                         for (++p; (*p & 0xc0) == 0x80; ++p) {
673                                 /* do nothing */
674                         }
675                 }
676         }
677         return (p == end) ? NULL : (char *)p;
678 }
679
680 /* was g_utf8_prev_char */
681 /**
682  * BLI_str_prev_char_utf8:
683  * \param p a pointer to a position within a UTF-8 encoded string
684  *
685  * Finds the previous UTF-8 character in the string before \a p
686  *
687  * \a p does not have to be at the beginning of a UTF-8 character. No check
688  * is made to see if the character found is actually valid other than
689  * it starts with an appropriate byte. If \a p might be the first
690  * character of the string, you must use g_utf8_find_prev_char() instead.
691  *
692  * Return value: a pointer to the found character.
693  **/
694 char *BLI_str_prev_char_utf8(const char *p)
695 {
696         while (1) {
697                 p--;
698                 if ((*p & 0xc0) != 0x80) {
699                         return (char *)p;
700                 }
701         }
702 }
703 /* end glib copy */