Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
utf8.h
Go to the documentation of this file.
1/* This is free and unencumbered software released into the public domain.
2 *
3 * Anyone is free to copy, modify, publish, use, compile, sell, or
4 * distribute this software, either in source code form or as a compiled
5 * binary, for any purpose, commercial or non-commercial, and by any
6 * means.
7 *
8 * In jurisdictions that recognize copyright laws, the author or authors
9 * of this software dedicate any and all copyright interest in the
10 * software to the public domain. We make this dedication for the benefit
11 * of the public at large and to the detriment of our heirs and
12 * successors. We intend this dedication to be an overt act of
13 * relinquishment in perpetuity of all present and future rights to this
14 * software under copyright law.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * For more information, please refer to <http://unlicense.org/> */
25#pragma once
26
27#if defined(_MSC_VER)
28# pragma warning(push)
29
30/* disable warning: no function prototype given: converting '()' to '(void)' */
31# pragma warning(disable : 4255)
32
33/* disable warning: '__cplusplus' is not defined as a preprocessor macro,
34 * replacing with '0' for '#if/#elif' */
35# pragma warning(disable : 4668)
36
37/* disable warning: bytes padding added after construct */
38# pragma warning(disable : 4820)
39#endif
40
41#if defined(__cplusplus)
42# if defined(_MSC_VER)
43# define utf8_cplusplus _MSVC_LANG
44# else
45# define utf8_cplusplus __cplusplus
46# endif
47#endif
48
49#include <stddef.h>
50#include <stdlib.h>
51
52#if defined(_MSC_VER)
53# pragma warning(pop)
54#endif
55
56#if defined(_MSC_VER) && (_MSC_VER < 1920)
57typedef __int32 utf8_int32_t;
58#else
59# include <stdint.h>
60typedef int32_t utf8_int32_t;
61#endif
62
63#if defined(__clang__)
64# pragma clang diagnostic push
65# pragma clang diagnostic ignored "-Wold-style-cast"
66# pragma clang diagnostic ignored "-Wcast-qual"
67
68# if __has_warning("-Wunsafe-buffer-usage")
69# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
70# endif
71#endif
72
73#ifdef utf8_cplusplus
74extern "C" {
75#endif
76
77#if defined(__TINYC__)
78# define UTF8_ATTRIBUTE(a) __attribute((a))
79#else
80# define UTF8_ATTRIBUTE(a) __attribute__((a))
81#endif
82
83#if defined(_MSC_VER)
84# define utf8_nonnull
85# define utf8_pure
86# define utf8_restrict __restrict
87# define utf8_weak __inline
88#elif defined(__clang__) || defined(__GNUC__)
89# define utf8_nonnull UTF8_ATTRIBUTE(nonnull)
90# define utf8_pure UTF8_ATTRIBUTE(pure)
91# define utf8_restrict __restrict__
92# define utf8_weak UTF8_ATTRIBUTE(weak)
93#elif defined(__TINYC__)
94# define utf8_nonnull UTF8_ATTRIBUTE(nonnull)
95# define utf8_pure UTF8_ATTRIBUTE(pure)
96# define utf8_restrict
97# define utf8_weak UTF8_ATTRIBUTE(weak)
98#elif defined(__IAR_SYSTEMS_ICC__)
99# define utf8_nonnull
100# define utf8_pure UTF8_ATTRIBUTE(pure)
101# define utf8_restrict __restrict
102# define utf8_weak UTF8_ATTRIBUTE(weak)
103#else
104# error Non clang, non gcc, non MSVC, non tcc, non iar compiler found!
105#endif
106
107#ifdef utf8_cplusplus
108# define utf8_null NULL
109#else
110# define utf8_null 0
111#endif
112
113#if defined(utf8_cplusplus) && utf8_cplusplus >= 201402L && \
114 (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1910))
115# define utf8_constexpr14 constexpr
116# define utf8_constexpr14_impl constexpr
117#else
118/* constexpr and weak are incompatible. so only enable one of them */
119# define utf8_constexpr14 utf8_weak
120# define utf8_constexpr14_impl
121#endif
122
123#if defined(utf8_cplusplus) && utf8_cplusplus >= 202002L && \
124 defined(__cpp_char8_t)
125using utf8_int8_t = char8_t; /* Introduced in C++20 */
126#else
127typedef char utf8_int8_t;
128#endif
129
130/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
131 * src2 respectively, case insensitive. */
132utf8_constexpr14 utf8_nonnull utf8_pure int
133utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2);
134
135/* Append the utf8 string src onto the utf8 string dst. */
136utf8_nonnull utf8_weak utf8_int8_t *
137utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
138
139/* Find the first match of the utf8 codepoint chr in the utf8 string src. */
140utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
141utf8chr(const utf8_int8_t *src, utf8_int32_t chr);
142
143/* Return less than 0, 0, greater than 0 if src1 < src2,
144 * src1 == src2, src1 > src2 respectively. */
145utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1,
146 const utf8_int8_t *src2);
147
148/* Copy the utf8 string src onto the memory allocated in dst. */
149utf8_nonnull utf8_weak utf8_int8_t *
150utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
151
152/* Number of utf8 codepoints in the utf8 string src that consists entirely
153 * of utf8 codepoints not from the utf8 string reject. */
154utf8_constexpr14 utf8_nonnull utf8_pure size_t
155utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject);
156
157/* Duplicate the utf8 string src by getting its size, malloc'ing a new buffer
158 * copying over the data, and returning that. Or 0 if malloc failed. */
159utf8_weak utf8_int8_t *utf8dup(const utf8_int8_t *src);
160
161/* Number of utf8 codepoints in the utf8 string str,
162 * excluding the null terminating byte. */
163utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str);
164
165/* Similar to utf8len, except that only at most n bytes of src are looked. */
166utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str,
167 size_t n);
168
169/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
170 * src2 respectively, case insensitive. Checking at most n bytes of each utf8
171 * string. */
172utf8_constexpr14 utf8_nonnull utf8_pure int
173utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
174
175/* Append the utf8 string src onto the utf8 string dst,
176 * writing at most n+1 bytes. Can produce an invalid utf8
177 * string if n falls partway through a utf8 codepoint. */
178utf8_nonnull utf8_weak utf8_int8_t *
179utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
180 size_t n);
181
182/* Return less than 0, 0, greater than 0 if src1 < src2,
183 * src1 == src2, src1 > src2 respectively. Checking at most n
184 * bytes of each utf8 string. */
185utf8_constexpr14 utf8_nonnull utf8_pure int
186utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
187
188/* Copy the utf8 string src onto the memory allocated in dst.
189 * Copies at most n bytes. If n falls partway through a utf8
190 * codepoint, or if dst doesn't have enough room for a null
191 * terminator, the final string will be cut short to preserve
192 * utf8 validity. */
193
194utf8_nonnull utf8_weak utf8_int8_t *
195utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
196 size_t n);
197
198/* Similar to utf8dup, except that at most n bytes of src are copied. If src is
199 * longer than n, only n bytes are copied and a null byte is added.
200 *
201 * Returns a new string if successful, 0 otherwise */
202utf8_weak utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n);
203
204/* Locates the first occurrence in the utf8 string str of any byte in the
205 * utf8 string accept, or 0 if no match was found. */
206utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
207utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept);
208
209/* Find the last match of the utf8 codepoint chr in the utf8 string src. */
210utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
211utf8rchr(const utf8_int8_t *src, int chr);
212
213/* Number of bytes in the utf8 string str,
214 * including the null terminating byte. */
215utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str);
216
217/* Similar to utf8size, except that the null terminating byte is excluded. */
218utf8_constexpr14 utf8_nonnull utf8_pure size_t
219utf8size_lazy(const utf8_int8_t *str);
220
221/* Similar to utf8size, except that only at most n bytes of src are looked and
222 * the null terminating byte is excluded. */
223utf8_constexpr14 utf8_nonnull utf8_pure size_t
224utf8nsize_lazy(const utf8_int8_t *str, size_t n);
225
226/* Number of utf8 codepoints in the utf8 string src that consists entirely
227 * of utf8 codepoints from the utf8 string accept. */
228utf8_constexpr14 utf8_nonnull utf8_pure size_t
229utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept);
230
231/* The position of the utf8 string needle in the utf8 string haystack. */
232utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
233utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle);
234
235/* The position of the utf8 string needle in the utf8 string haystack, case
236 * insensitive. */
237utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
238utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle);
239
240/* Return 0 on success, or the position of the invalid
241 * utf8 codepoint on failure. */
242utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
243utf8valid(const utf8_int8_t *str);
244
245/* Similar to utf8valid, except that only at most n bytes of src are looked. */
246utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
247utf8nvalid(const utf8_int8_t *str, size_t n);
248
249/* Given a null-terminated string, makes the string valid by replacing invalid
250 * codepoints with a 1-byte replacement. Returns 0 on success. */
251utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str,
252 const utf8_int32_t replacement);
253
254/* Sets out_codepoint to the current utf8 codepoint in str, and returns the
255 * address of the next utf8 codepoint after the current one in str. */
256utf8_constexpr14 utf8_nonnull utf8_int8_t *
257utf8codepoint(const utf8_int8_t *utf8_restrict str,
258 utf8_int32_t *utf8_restrict out_codepoint);
259
260/* Calculates the size of the next utf8 codepoint in str. */
261utf8_constexpr14 utf8_nonnull size_t
263
264/* Returns the size of the given codepoint in bytes. */
266
267/* Write a codepoint to the given string, and return the address to the next
268 * place after the written codepoint. Pass how many bytes left in the buffer to
269 * n. If there is not enough space for the codepoint, this function returns
270 * null. */
271utf8_nonnull utf8_weak utf8_int8_t *
272utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n);
273
274/* Returns 1 if the given character is lowercase, or 0 if it is not. */
276
277/* Returns 1 if the given character is uppercase, or 0 if it is not. */
279
280/* Transform the given string into all lowercase codepoints. */
281utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str);
282
283/* Transform the given string into all uppercase codepoints. */
284utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str);
285
286/* Make a codepoint lower case if possible. */
288
289/* Make a codepoint upper case if possible. */
291
292/* Sets out_codepoint to the current utf8 codepoint in str, and returns the
293 * address of the previous utf8 codepoint before the current one in str. */
294utf8_constexpr14 utf8_nonnull utf8_int8_t *
295utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
296 utf8_int32_t *utf8_restrict out_codepoint);
297
298/* Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to
299 * copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr
300 * returned null. */
301utf8_weak utf8_int8_t *utf8dup_ex(const utf8_int8_t *src,
302 utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
303 size_t),
304 utf8_int8_t *user_data);
305
306/* Similar to utf8dup, except that at most n bytes of src are copied. If src is
307 * longer than n, only n bytes are copied and a null byte is added.
308 *
309 * Returns a new string if successful, 0 otherwise. */
310utf8_weak utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n,
311 utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
312 size_t),
313 utf8_int8_t *user_data);
314
315#undef utf8_weak
316#undef utf8_pure
317#undef utf8_nonnull
318
320 const utf8_int8_t *src2) {
321 utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
322 src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
323
324 for (;;) {
325 src1 = utf8codepoint(src1, &src1_orig_cp);
326 src2 = utf8codepoint(src2, &src2_orig_cp);
327
328 /* lower the srcs if required */
329 src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
330 src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
331
332 /* lower the srcs if required */
333 src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
334 src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
335
336 /* check if the lowered codepoints match */
337 if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
338 return 0;
339 } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
340 continue;
341 }
342
343 /* if they don't match, then we return the difference between the characters
344 */
345 return src1_lwr_cp - src2_lwr_cp;
346 }
347}
348
349utf8_int8_t *utf8cat(utf8_int8_t *utf8_restrict dst,
350 const utf8_int8_t *utf8_restrict src) {
351 utf8_int8_t *d = dst;
352 /* find the null terminating byte in dst */
353 while ('\0' != *d) {
354 d++;
355 }
356
357 /* overwriting the null terminating byte in dst, append src byte-by-byte */
358 while ('\0' != *src) {
359 *d++ = *src++;
360 }
361
362 /* write out a new null terminating byte into dst */
363 *d = '\0';
364
365 return dst;
366}
367
369 utf8_int32_t chr) {
370 utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
371
372 if (0 == chr) {
373 /* being asked to return position of null terminating byte, so
374 * just run s to the end, and return! */
375 while ('\0' != *src) {
376 src++;
377 }
378 return (utf8_int8_t *)src;
379 } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
380 /* 1-byte/7-bit ascii
381 * (0b0xxxxxxx) */
382 c[0] = (utf8_int8_t)chr;
383 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
384 /* 2-byte/11-bit utf8 code point
385 * (0b110xxxxx 0b10xxxxxx) */
386 c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
387 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
388 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
389 /* 3-byte/16-bit utf8 code point
390 * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
391 c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
392 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
393 c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
394 } else { /* if (0 == ((int)0xffe00000 & chr)) { */
395 /* 4-byte/21-bit utf8 code point
396 * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
397 c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
398 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
399 c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
400 c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
401 }
402
403 /* we've made c into a 2 utf8 codepoint string, one for the chr we are
404 * seeking, another for the null terminating byte. Now use utf8str to
405 * search */
406 return utf8str(src, c);
407}
408
410 const utf8_int8_t *src2) {
411 while (('\0' != *src1) || ('\0' != *src2)) {
412 if (*src1 < *src2) {
413 return -1;
414 } else if (*src1 > *src2) {
415 return 1;
416 }
417
418 src1++;
419 src2++;
420 }
421
422 /* both utf8 strings matched */
423 return 0;
424}
425
427 const utf8_int8_t *src2);
428
429utf8_int8_t *utf8cpy(utf8_int8_t *utf8_restrict dst,
430 const utf8_int8_t *utf8_restrict src) {
431 utf8_int8_t *d = dst;
432
433 /* overwriting anything previously in dst, write byte-by-byte
434 * from src */
435 while ('\0' != *src) {
436 *d++ = *src++;
437 }
438
439 /* append null terminating byte */
440 *d = '\0';
441
442 return dst;
443}
444
446 const utf8_int8_t *reject) {
447 size_t chars = 0;
448
449 while ('\0' != *src) {
450 const utf8_int8_t *r = reject;
451 size_t offset = 0;
452
453 while ('\0' != *r) {
454 /* checking that if *r is the start of a utf8 codepoint
455 * (it is not 0b10xxxxxx) and we have successfully matched
456 * a previous character (0 < offset) - we found a match */
457 if ((0x80 != (0xc0 & *r)) && (0 < offset)) {
458 return chars;
459 } else {
460 if (*r == src[offset]) {
461 /* part of a utf8 codepoint matched, so move our checking
462 * onwards to the next byte */
463 offset++;
464 r++;
465 } else {
466 /* r could be in the middle of an unmatching utf8 code point,
467 * so we need to march it on to the next character beginning, */
468
469 do {
470 r++;
471 } while (0x80 == (0xc0 & *r));
472
473 /* reset offset too as we found a mismatch */
474 offset = 0;
475 }
476 }
477 }
478
479 /* found a match at the end of *r, so didn't get a chance to test it */
480 if (0 < offset) {
481 return chars;
482 }
483
484 /* the current utf8 codepoint in src did not match reject, but src
485 * could have been partway through a utf8 codepoint, so we need to
486 * march it onto the next utf8 codepoint starting byte */
487 do {
488 src++;
489 } while ((0x80 == (0xc0 & *src)));
490 chars++;
491 }
492
493 return chars;
494}
495
497 return utf8dup_ex(src, utf8_null, utf8_null);
498}
499
501 utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
502 utf8_int8_t *user_data) {
504
505 /* figure out how many bytes (including the terminator) we need to copy first
506 */
507 size_t bytes = utf8size(src);
508
509 if (alloc_func_ptr) {
510 n = alloc_func_ptr(user_data, bytes);
511 } else {
512#if !defined(UTF8_NO_STD_MALLOC)
513 n = (utf8_int8_t *)malloc(bytes);
514#else
515 return utf8_null;
516#endif
517 }
518
519 if (utf8_null == n) {
520 /* out of memory so we bail */
521 return utf8_null;
522 } else {
523 bytes = 0;
524
525 /* copy src byte-by-byte into our new utf8 string */
526 while ('\0' != src[bytes]) {
527 n[bytes] = src[bytes];
528 bytes++;
529 }
530
531 /* append null terminating byte */
532 n[bytes] = '\0';
533 return n;
534 }
535}
536
538
540 return utf8nlen(str, SIZE_MAX);
541}
542
543utf8_constexpr14_impl size_t utf8nlen(const utf8_int8_t *str, size_t n) {
544 const utf8_int8_t *t = str;
545 size_t length = 0;
546
547 while ((size_t)(str - t) < n && '\0' != *str) {
548 if (0xf0 == (0xf8 & *str)) {
549 /* 4-byte utf8 code point (began with 0b11110xxx) */
550 str += 4;
551 } else if (0xe0 == (0xf0 & *str)) {
552 /* 3-byte utf8 code point (began with 0b1110xxxx) */
553 str += 3;
554 } else if (0xc0 == (0xe0 & *str)) {
555 /* 2-byte utf8 code point (began with 0b110xxxxx) */
556 str += 2;
557 } else { /* if (0x00 == (0x80 & *s)) { */
558 /* 1-byte ascii (began with 0b0xxxxxxx) */
559 str += 1;
560 }
561
562 /* no matter the bytes we marched s forward by, it was
563 * only 1 utf8 codepoint */
564 length++;
565 }
566
567 if ((size_t)(str - t) > n) {
568 length--;
569 }
570 return length;
571}
572
574 const utf8_int8_t *src2, size_t n) {
575 utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
576 src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
577
578 do {
579 const utf8_int8_t *const s1 = src1;
580 const utf8_int8_t *const s2 = src2;
581
582 /* first check that we have enough bytes left in n to contain an entire
583 * codepoint */
584 if (0 == n) {
585 return 0;
586 }
587
588 if ((1 == n) && ((0xc0 == (0xe0 & *s1)) || (0xc0 == (0xe0 & *s2)))) {
589 const utf8_int32_t c1 = (0xe0 & *s1);
590 const utf8_int32_t c2 = (0xe0 & *s2);
591
592 if (c1 != c2) {
593 return c1 - c2;
594 } else {
595 return 0;
596 }
597 }
598
599 if ((2 >= n) && ((0xe0 == (0xf0 & *s1)) || (0xe0 == (0xf0 & *s2)))) {
600 const utf8_int32_t c1 = (0xf0 & *s1);
601 const utf8_int32_t c2 = (0xf0 & *s2);
602
603 if (c1 != c2) {
604 return c1 - c2;
605 } else {
606 return 0;
607 }
608 }
609
610 if ((3 >= n) && ((0xf0 == (0xf8 & *s1)) || (0xf0 == (0xf8 & *s2)))) {
611 const utf8_int32_t c1 = (0xf8 & *s1);
612 const utf8_int32_t c2 = (0xf8 & *s2);
613
614 if (c1 != c2) {
615 return c1 - c2;
616 } else {
617 return 0;
618 }
619 }
620
621 src1 = utf8codepoint(src1, &src1_orig_cp);
622 src2 = utf8codepoint(src2, &src2_orig_cp);
623 n -= utf8codepointsize(src1_orig_cp);
624
625 src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
626 src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
627
628 src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
629 src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
630
631 /* check if the lowered codepoints match */
632 if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
633 return 0;
634 } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
635 continue;
636 }
637
638 /* if they don't match, then we return the difference between the characters
639 */
640 return src1_lwr_cp - src2_lwr_cp;
641 } while (0 < n);
642
643 /* both utf8 strings matched */
644 return 0;
645}
646
647utf8_int8_t *utf8ncat(utf8_int8_t *utf8_restrict dst,
648 const utf8_int8_t *utf8_restrict src, size_t n) {
649 utf8_int8_t *d = dst;
650
651 /* find the null terminating byte in dst */
652 while ('\0' != *d) {
653 d++;
654 }
655
656 /* overwriting the null terminating byte in dst, append src byte-by-byte
657 * stopping if we run out of space */
658 while (('\0' != *src) && (0 != n--)) {
659 *d++ = *src++;
660 }
661
662 /* write out a new null terminating byte into dst */
663 *d = '\0';
664
665 return dst;
666}
667
669 const utf8_int8_t *src2, size_t n) {
670 while ((0 != n--) && (('\0' != *src1) || ('\0' != *src2))) {
671 if (*src1 < *src2) {
672 return -1;
673 } else if (*src1 > *src2) {
674 return 1;
675 }
676
677 src1++;
678 src2++;
679 }
680
681 /* both utf8 strings matched */
682 return 0;
683}
684
685utf8_int8_t *utf8ncpy(utf8_int8_t *utf8_restrict dst,
686 const utf8_int8_t *utf8_restrict src, size_t n) {
687 utf8_int8_t *d = dst;
688 size_t index = 0, check_index = 0;
689
690 if (n == 0) {
691 return dst;
692 }
693
694 /* overwriting anything previously in dst, write byte-by-byte
695 * from src */
696 for (index = 0; index < n; index++) {
697 d[index] = src[index];
698 if ('\0' == src[index]) {
699 break;
700 }
701 }
702
703 for (check_index = index - 1;
704 check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) {
705 /* just moving the index */
706 }
707
708 if (check_index < index &&
709 ((index - check_index) < utf8codepointcalcsize(&d[check_index]) ||
710 (index - check_index) == n)) {
711 index = check_index;
712 }
713
714 /* append null terminating byte */
715 for (; index < n; index++) {
716 d[index] = 0;
717 }
718
719 return dst;
720}
721
722utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n) {
723 return utf8ndup_ex(src, n, utf8_null, utf8_null);
724}
725
727 utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
728 utf8_int8_t *user_data) {
730 size_t bytes = 0;
731
732 /* Find the end of the string or stop when n is reached */
733 while ('\0' != src[bytes] && bytes < n) {
734 bytes++;
735 }
736
737 /* In case bytes is actually less than n, we need to set it
738 * to be used later in the copy byte by byte. */
739 n = bytes;
740
741 if (alloc_func_ptr) {
742 c = alloc_func_ptr(user_data, bytes + 1);
743 } else {
744#if !defined(UTF8_NO_STD_MALLOC)
745 c = (utf8_int8_t *)malloc(bytes + 1);
746#else
747 c = utf8_null;
748#endif
749 }
750
751 if (utf8_null == c) {
752 /* out of memory so we bail */
753 return utf8_null;
754 }
755
756 bytes = 0;
757
758 /* copy src byte-by-byte into our new utf8 string */
759 while ('\0' != src[bytes] && bytes < n) {
760 c[bytes] = src[bytes];
761 bytes++;
762 }
763
764 /* append null terminating byte */
765 c[bytes] = '\0';
766 return c;
767}
768
770
771 utf8_int8_t *match = utf8_null;
772 utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
773
774 if (0 == chr) {
775 /* being asked to return position of null terminating byte, so
776 * just run s to the end, and return! */
777 while ('\0' != *src) {
778 src++;
779 }
780 return (utf8_int8_t *)src;
781 } else if (0 == ((int)0xffffff80 & chr)) {
782 /* 1-byte/7-bit ascii
783 * (0b0xxxxxxx) */
784 c[0] = (utf8_int8_t)chr;
785 } else if (0 == ((int)0xfffff800 & chr)) {
786 /* 2-byte/11-bit utf8 code point
787 * (0b110xxxxx 0b10xxxxxx) */
788 c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
789 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
790 } else if (0 == ((int)0xffff0000 & chr)) {
791 /* 3-byte/16-bit utf8 code point
792 * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
793 c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
794 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
795 c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
796 } else { /* if (0 == ((int)0xffe00000 & chr)) { */
797 /* 4-byte/21-bit utf8 code point
798 * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
799 c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
800 c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
801 c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
802 c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
803 }
804
805 /* we've created a 2 utf8 codepoint string in c that is
806 * the utf8 character asked for by chr, and a null
807 * terminating byte */
808
809 while ('\0' != *src) {
810 size_t offset = 0;
811
812 while ((src[offset] == c[offset]) && ('\0' != src[offset])) {
813 offset++;
814 }
815
816 if ('\0' == c[offset]) {
817 /* we found a matching utf8 code point */
818 match = (utf8_int8_t *)src;
819 src += offset;
820
821 if ('\0' == *src) {
822 break;
823 }
824 } else {
825 src += offset;
826
827 /* need to march s along to next utf8 codepoint start
828 * (the next byte that doesn't match 0b10xxxxxx) */
829 if ('\0' != *src) {
830 do {
831 src++;
832 } while (0x80 == (0xc0 & *src));
833 }
834 }
835 }
836
837 /* return the last match we found (or 0 if no match was found) */
838 return match;
839}
840
842 const utf8_int8_t *accept) {
843 while ('\0' != *str) {
844 const utf8_int8_t *a = accept;
845 size_t offset = 0;
846
847 while ('\0' != *a) {
848 /* checking that if *a is the start of a utf8 codepoint
849 * (it is not 0b10xxxxxx) and we have successfully matched
850 * a previous character (0 < offset) - we found a match */
851 if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
852 return (utf8_int8_t *)str;
853 } else {
854 if (*a == str[offset]) {
855 /* part of a utf8 codepoint matched, so move our checking
856 * onwards to the next byte */
857 offset++;
858 a++;
859 } else {
860 /* r could be in the middle of an unmatching utf8 code point,
861 * so we need to march it on to the next character beginning, */
862
863 do {
864 a++;
865 } while (0x80 == (0xc0 & *a));
866
867 /* reset offset too as we found a mismatch */
868 offset = 0;
869 }
870 }
871 }
872
873 /* we found a match on the last utf8 codepoint */
874 if (0 < offset) {
875 return (utf8_int8_t *)str;
876 }
877
878 /* the current utf8 codepoint in src did not match accept, but src
879 * could have been partway through a utf8 codepoint, so we need to
880 * march it onto the next utf8 codepoint starting byte */
881 do {
882 str++;
883 } while ((0x80 == (0xc0 & *str)));
884 }
885
886 return utf8_null;
887}
888
890 return utf8size_lazy(str) + 1;
891}
892
894 return utf8nsize_lazy(str, SIZE_MAX);
895}
896
898 size_t size = 0;
899 while (size < n && '\0' != str[size]) {
900 size++;
901 }
902 return size;
903}
904
906 const utf8_int8_t *accept) {
907 size_t chars = 0;
908
909 while ('\0' != *src) {
910 const utf8_int8_t *a = accept;
911 size_t offset = 0;
912
913 while ('\0' != *a) {
914 /* checking that if *r is the start of a utf8 codepoint
915 * (it is not 0b10xxxxxx) and we have successfully matched
916 * a previous character (0 < offset) - we found a match */
917 if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
918 /* found a match, so increment the number of utf8 codepoints
919 * that have matched and stop checking whether any other utf8
920 * codepoints in a match */
921 chars++;
922 src += offset;
923 offset = 0;
924 break;
925 } else {
926 if (*a == src[offset]) {
927 offset++;
928 a++;
929 } else {
930 /* a could be in the middle of an unmatching utf8 codepoint,
931 * so we need to march it on to the next character beginning, */
932 do {
933 a++;
934 } while (0x80 == (0xc0 & *a));
935
936 /* reset offset too as we found a mismatch */
937 offset = 0;
938 }
939 }
940 }
941
942 /* found a match at the end of *a, so didn't get a chance to test it */
943 if (0 < offset) {
944 chars++;
945 src += offset;
946 continue;
947 }
948
949 /* if a got to its terminating null byte, then we didn't find a match.
950 * Return the current number of matched utf8 codepoints */
951 if ('\0' == *a) {
952 return chars;
953 }
954 }
955
956 return chars;
957}
958
960 const utf8_int8_t *needle) {
961 utf8_int32_t throwaway_codepoint = 0;
962
963 /* if needle has no utf8 codepoints before the null terminating
964 * byte then return haystack */
965 if ('\0' == *needle) {
966 return (utf8_int8_t *)haystack;
967 }
968
969 while ('\0' != *haystack) {
970 const utf8_int8_t *maybeMatch = haystack;
971 const utf8_int8_t *n = needle;
972
973 while (*haystack == *n && (*haystack != '\0' && *n != '\0')) {
974 n++;
975 haystack++;
976 }
977
978 if ('\0' == *n) {
979 /* we found the whole utf8 string for needle in haystack at
980 * maybeMatch, so return it */
981 return (utf8_int8_t *)maybeMatch;
982 } else {
983 /* h could be in the middle of an unmatching utf8 codepoint,
984 * so we need to march it on to the next character beginning
985 * starting from the current character */
986 haystack = utf8codepoint(maybeMatch, &throwaway_codepoint);
987 }
988 }
989
990 /* no match */
991 return utf8_null;
992}
993
995 const utf8_int8_t *needle) {
996 /* if needle has no utf8 codepoints before the null terminating
997 * byte then return haystack */
998 if ('\0' == *needle) {
999 return (utf8_int8_t *)haystack;
1000 }
1001
1002 for (;;) {
1003 const utf8_int8_t *maybeMatch = haystack;
1004 const utf8_int8_t *n = needle;
1005 utf8_int32_t h_cp = 0, n_cp = 0;
1006
1007 /* Get the next code point and track it */
1008 const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp);
1009 n = utf8codepoint(n, &n_cp);
1010
1011 while ((0 != h_cp) && (0 != n_cp)) {
1012 h_cp = utf8lwrcodepoint(h_cp);
1013 n_cp = utf8lwrcodepoint(n_cp);
1014
1015 /* if we find a mismatch, bail out! */
1016 if (h_cp != n_cp) {
1017 break;
1018 }
1019
1020 haystack = utf8codepoint(haystack, &h_cp);
1021 n = utf8codepoint(n, &n_cp);
1022 }
1023
1024 if (0 == n_cp) {
1025 /* we found the whole utf8 string for needle in haystack at
1026 * maybeMatch, so return it */
1027 return (utf8_int8_t *)maybeMatch;
1028 }
1029
1030 if (0 == h_cp) {
1031 /* no match */
1032 return utf8_null;
1033 }
1034
1035 /* Roll back to the next code point in the haystack to test */
1036 haystack = nextH;
1037 }
1038}
1039
1041 return utf8nvalid(str, SIZE_MAX);
1042}
1043
1045 size_t n) {
1046 const utf8_int8_t *t = str;
1047 size_t consumed = 0;
1048
1049 while ((void)(consumed = (size_t)(str - t)), consumed < n && '\0' != *str) {
1050 const size_t remaining = n - consumed;
1051
1052 if (0xf0 == (0xf8 & *str)) {
1053 /* ensure that there's 4 bytes or more remaining */
1054 if (remaining < 4) {
1055 return (utf8_int8_t *)str;
1056 }
1057
1058 /* ensure each of the 3 following bytes in this 4-byte
1059 * utf8 codepoint began with 0b10xxxxxx */
1060 if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2])) ||
1061 (0x80 != (0xc0 & str[3]))) {
1062 return (utf8_int8_t *)str;
1063 }
1064
1065 /* ensure that our utf8 codepoint ended after 4 bytes */
1066 if ((remaining != 4) && (0x80 == (0xc0 & str[4]))) {
1067 return (utf8_int8_t *)str;
1068 }
1069
1070 /* ensure that the top 5 bits of this 4-byte utf8
1071 * codepoint were not 0, as then we could have used
1072 * one of the smaller encodings */
1073 if ((0 == (0x07 & str[0])) && (0 == (0x30 & str[1]))) {
1074 return (utf8_int8_t *)str;
1075 }
1076
1077 /* 4-byte utf8 code point (began with 0b11110xxx) */
1078 str += 4;
1079 } else if (0xe0 == (0xf0 & *str)) {
1080 /* ensure that there's 3 bytes or more remaining */
1081 if (remaining < 3) {
1082 return (utf8_int8_t *)str;
1083 }
1084
1085 /* ensure each of the 2 following bytes in this 3-byte
1086 * utf8 codepoint began with 0b10xxxxxx */
1087 if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2]))) {
1088 return (utf8_int8_t *)str;
1089 }
1090
1091 /* ensure that our utf8 codepoint ended after 3 bytes */
1092 if ((remaining != 3) && (0x80 == (0xc0 & str[3]))) {
1093 return (utf8_int8_t *)str;
1094 }
1095
1096 /* ensure that the top 5 bits of this 3-byte utf8
1097 * codepoint were not 0, as then we could have used
1098 * one of the smaller encodings */
1099 if ((0 == (0x0f & str[0])) && (0 == (0x20 & str[1]))) {
1100 return (utf8_int8_t *)str;
1101 }
1102
1103 /* 3-byte utf8 code point (began with 0b1110xxxx) */
1104 str += 3;
1105 } else if (0xc0 == (0xe0 & *str)) {
1106 /* ensure that there's 2 bytes or more remaining */
1107 if (remaining < 2) {
1108 return (utf8_int8_t *)str;
1109 }
1110
1111 /* ensure the 1 following byte in this 2-byte
1112 * utf8 codepoint began with 0b10xxxxxx */
1113 if (0x80 != (0xc0 & str[1])) {
1114 return (utf8_int8_t *)str;
1115 }
1116
1117 /* ensure that our utf8 codepoint ended after 2 bytes */
1118 if ((remaining != 2) && (0x80 == (0xc0 & str[2]))) {
1119 return (utf8_int8_t *)str;
1120 }
1121
1122 /* ensure that the top 4 bits of this 2-byte utf8
1123 * codepoint were not 0, as then we could have used
1124 * one of the smaller encodings */
1125 if (0 == (0x1e & str[0])) {
1126 return (utf8_int8_t *)str;
1127 }
1128
1129 /* 2-byte utf8 code point (began with 0b110xxxxx) */
1130 str += 2;
1131 } else if (0x00 == (0x80 & *str)) {
1132 /* 1-byte ascii (began with 0b0xxxxxxx) */
1133 str += 1;
1134 } else {
1135 /* we have an invalid 0b1xxxxxxx utf8 code point entry */
1136 return (utf8_int8_t *)str;
1137 }
1138 }
1139
1140 return utf8_null;
1141}
1142
1143int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement) {
1144 utf8_int8_t *read = str;
1145 utf8_int8_t *write = read;
1146 const utf8_int8_t r = (utf8_int8_t)replacement;
1147 utf8_int32_t codepoint = 0;
1148
1149 if (replacement > 0x7f) {
1150 return -1;
1151 }
1152
1153 while ('\0' != *read) {
1154 if (0xf0 == (0xf8 & *read)) {
1155 /* ensure each of the 3 following bytes in this 4-byte
1156 * utf8 codepoint began with 0b10xxxxxx */
1157 if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) ||
1158 (0x80 != (0xc0 & read[3]))) {
1159 *write++ = r;
1160 read++;
1161 continue;
1162 }
1163
1164 /* 4-byte utf8 code point (began with 0b11110xxx) */
1165 read = utf8codepoint(read, &codepoint);
1166 write = utf8catcodepoint(write, codepoint, 4);
1167 } else if (0xe0 == (0xf0 & *read)) {
1168 /* ensure each of the 2 following bytes in this 3-byte
1169 * utf8 codepoint began with 0b10xxxxxx */
1170 if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) {
1171 *write++ = r;
1172 read++;
1173 continue;
1174 }
1175
1176 /* 3-byte utf8 code point (began with 0b1110xxxx) */
1177 read = utf8codepoint(read, &codepoint);
1178 write = utf8catcodepoint(write, codepoint, 3);
1179 } else if (0xc0 == (0xe0 & *read)) {
1180 /* ensure the 1 following byte in this 2-byte
1181 * utf8 codepoint began with 0b10xxxxxx */
1182 if (0x80 != (0xc0 & read[1])) {
1183 *write++ = r;
1184 read++;
1185 continue;
1186 }
1187
1188 /* 2-byte utf8 code point (began with 0b110xxxxx) */
1189 read = utf8codepoint(read, &codepoint);
1190 write = utf8catcodepoint(write, codepoint, 2);
1191 } else if (0x00 == (0x80 & *read)) {
1192 /* 1-byte ascii (began with 0b0xxxxxxx) */
1193 read = utf8codepoint(read, &codepoint);
1194 write = utf8catcodepoint(write, codepoint, 1);
1195 } else {
1196 /* if we got here then we've got a dangling continuation (0b10xxxxxx) */
1197 *write++ = r;
1198 read++;
1199 continue;
1200 }
1201 }
1202
1203 *write = '\0';
1204
1205 return 0;
1206}
1207
1209utf8codepoint(const utf8_int8_t *utf8_restrict str,
1210 utf8_int32_t *utf8_restrict out_codepoint) {
1211 if (0xf0 == (0xf8 & str[0])) {
1212 /* 4 byte utf8 codepoint */
1213 *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) |
1214 ((0x3f & str[2]) << 6) | (0x3f & str[3]);
1215 str += 4;
1216 } else if (0xe0 == (0xf0 & str[0])) {
1217 /* 3 byte utf8 codepoint */
1218 *out_codepoint =
1219 ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]);
1220 str += 3;
1221 } else if (0xc0 == (0xe0 & str[0])) {
1222 /* 2 byte utf8 codepoint */
1223 *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]);
1224 str += 2;
1225 } else {
1226 /* 1 byte utf8 codepoint otherwise */
1227 *out_codepoint = str[0];
1228 str += 1;
1229 }
1230
1231 return (utf8_int8_t *)str;
1232}
1233
1235 if (0xf0 == (0xf8 & str[0])) {
1236 /* 4 byte utf8 codepoint */
1237 return 4;
1238 } else if (0xe0 == (0xf0 & str[0])) {
1239 /* 3 byte utf8 codepoint */
1240 return 3;
1241 } else if (0xc0 == (0xe0 & str[0])) {
1242 /* 2 byte utf8 codepoint */
1243 return 2;
1244 }
1245
1246 /* 1 byte utf8 codepoint otherwise */
1247 return 1;
1248}
1249
1251 if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
1252 return 1;
1253 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
1254 return 2;
1255 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
1256 return 3;
1257 } else { /* if (0 == ((int)0xffe00000 & chr)) { */
1258 return 4;
1259 }
1260}
1261
1263 if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
1264 /* 1-byte/7-bit ascii
1265 * (0b0xxxxxxx) */
1266 if (n < 1) {
1267 return utf8_null;
1268 }
1269 str[0] = (utf8_int8_t)chr;
1270 str += 1;
1271 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
1272 /* 2-byte/11-bit utf8 code point
1273 * (0b110xxxxx 0b10xxxxxx) */
1274 if (n < 2) {
1275 return utf8_null;
1276 }
1277 str[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)((chr >> 6) & 0x1f));
1278 str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
1279 str += 2;
1280 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
1281 /* 3-byte/16-bit utf8 code point
1282 * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
1283 if (n < 3) {
1284 return utf8_null;
1285 }
1286 str[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)((chr >> 12) & 0x0f));
1287 str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
1288 str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
1289 str += 3;
1290 } else { /* if (0 == ((int)0xffe00000 & chr)) { */
1291 /* 4-byte/21-bit utf8 code point
1292 * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
1293 if (n < 4) {
1294 return utf8_null;
1295 }
1296 str[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)((chr >> 18) & 0x07));
1297 str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
1298 str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
1299 str[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
1300 str += 4;
1301 }
1302
1303 return str;
1304}
1305
1307 return chr != utf8uprcodepoint(chr);
1308}
1309
1311 return chr != utf8lwrcodepoint(chr);
1312}
1313
1314void utf8lwr(utf8_int8_t *utf8_restrict str) {
1315 utf8_int32_t cp = 0;
1316 utf8_int8_t *pn = utf8codepoint(str, &cp);
1317
1318 while (cp != 0) {
1319 const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp);
1320 const size_t size = utf8codepointsize(lwr_cp);
1321
1322 if (lwr_cp != cp) {
1323 utf8catcodepoint(str, lwr_cp, size);
1324 }
1325
1326 str = pn;
1327 pn = utf8codepoint(str, &cp);
1328 }
1329}
1330
1331void utf8upr(utf8_int8_t *utf8_restrict str) {
1332 utf8_int32_t cp = 0;
1333 utf8_int8_t *pn = utf8codepoint(str, &cp);
1334
1335 while (cp != 0) {
1336 const utf8_int32_t lwr_cp = utf8uprcodepoint(cp);
1337 const size_t size = utf8codepointsize(lwr_cp);
1338
1339 if (lwr_cp != cp) {
1340 utf8catcodepoint(str, lwr_cp, size);
1341 }
1342
1343 str = pn;
1344 pn = utf8codepoint(str, &cp);
1345 }
1346}
1347
1349 if (((0x0041 <= cp) && (0x005a >= cp)) ||
1350 ((0x00c0 <= cp) && (0x00d6 >= cp)) ||
1351 ((0x00d8 <= cp) && (0x00de >= cp)) ||
1352 ((0x0391 <= cp) && (0x03a1 >= cp)) ||
1353 ((0x03a3 <= cp) && (0x03ab >= cp)) ||
1354 ((0x0410 <= cp) && (0x042f >= cp))) {
1355 cp += 32;
1356 } else if ((0x0400 <= cp) && (0x040f >= cp)) {
1357 cp += 80;
1358 } else if (((0x0100 <= cp) && (0x012f >= cp)) ||
1359 ((0x0132 <= cp) && (0x0137 >= cp)) ||
1360 ((0x014a <= cp) && (0x0177 >= cp)) ||
1361 ((0x0182 <= cp) && (0x0185 >= cp)) ||
1362 ((0x01a0 <= cp) && (0x01a5 >= cp)) ||
1363 ((0x01de <= cp) && (0x01ef >= cp)) ||
1364 ((0x01f8 <= cp) && (0x021f >= cp)) ||
1365 ((0x0222 <= cp) && (0x0233 >= cp)) ||
1366 ((0x0246 <= cp) && (0x024f >= cp)) ||
1367 ((0x03d8 <= cp) && (0x03ef >= cp)) ||
1368 ((0x0460 <= cp) && (0x0481 >= cp)) ||
1369 ((0x048a <= cp) && (0x04ff >= cp))) {
1370 cp |= 0x1;
1371 } else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
1372 ((0x0179 <= cp) && (0x017e >= cp)) ||
1373 ((0x01af <= cp) && (0x01b0 >= cp)) ||
1374 ((0x01b3 <= cp) && (0x01b6 >= cp)) ||
1375 ((0x01cd <= cp) && (0x01dc >= cp))) {
1376 cp += 1;
1377 cp &= ~0x1;
1378 } else {
1379 switch (cp) {
1380 default:
1381 break;
1382 case 0x0178:
1383 cp = 0x00ff;
1384 break;
1385 case 0x0243:
1386 cp = 0x0180;
1387 break;
1388 case 0x018e:
1389 cp = 0x01dd;
1390 break;
1391 case 0x023d:
1392 cp = 0x019a;
1393 break;
1394 case 0x0220:
1395 cp = 0x019e;
1396 break;
1397 case 0x01b7:
1398 cp = 0x0292;
1399 break;
1400 case 0x01c4:
1401 cp = 0x01c6;
1402 break;
1403 case 0x01c7:
1404 cp = 0x01c9;
1405 break;
1406 case 0x01ca:
1407 cp = 0x01cc;
1408 break;
1409 case 0x01f1:
1410 cp = 0x01f3;
1411 break;
1412 case 0x01f7:
1413 cp = 0x01bf;
1414 break;
1415 case 0x0187:
1416 cp = 0x0188;
1417 break;
1418 case 0x018b:
1419 cp = 0x018c;
1420 break;
1421 case 0x0191:
1422 cp = 0x0192;
1423 break;
1424 case 0x0198:
1425 cp = 0x0199;
1426 break;
1427 case 0x01a7:
1428 cp = 0x01a8;
1429 break;
1430 case 0x01ac:
1431 cp = 0x01ad;
1432 break;
1433 case 0x01b8:
1434 cp = 0x01b9;
1435 break;
1436 case 0x01bc:
1437 cp = 0x01bd;
1438 break;
1439 case 0x01f4:
1440 cp = 0x01f5;
1441 break;
1442 case 0x023b:
1443 cp = 0x023c;
1444 break;
1445 case 0x0241:
1446 cp = 0x0242;
1447 break;
1448 case 0x03fd:
1449 cp = 0x037b;
1450 break;
1451 case 0x03fe:
1452 cp = 0x037c;
1453 break;
1454 case 0x03ff:
1455 cp = 0x037d;
1456 break;
1457 case 0x037f:
1458 cp = 0x03f3;
1459 break;
1460 case 0x0386:
1461 cp = 0x03ac;
1462 break;
1463 case 0x0388:
1464 cp = 0x03ad;
1465 break;
1466 case 0x0389:
1467 cp = 0x03ae;
1468 break;
1469 case 0x038a:
1470 cp = 0x03af;
1471 break;
1472 case 0x038c:
1473 cp = 0x03cc;
1474 break;
1475 case 0x038e:
1476 cp = 0x03cd;
1477 break;
1478 case 0x038f:
1479 cp = 0x03ce;
1480 break;
1481 case 0x0370:
1482 cp = 0x0371;
1483 break;
1484 case 0x0372:
1485 cp = 0x0373;
1486 break;
1487 case 0x0376:
1488 cp = 0x0377;
1489 break;
1490 case 0x03f4:
1491 cp = 0x03b8;
1492 break;
1493 case 0x03cf:
1494 cp = 0x03d7;
1495 break;
1496 case 0x03f9:
1497 cp = 0x03f2;
1498 break;
1499 case 0x03f7:
1500 cp = 0x03f8;
1501 break;
1502 case 0x03fa:
1503 cp = 0x03fb;
1504 break;
1505 }
1506 }
1507
1508 return cp;
1509}
1510
1512 if (((0x0061 <= cp) && (0x007a >= cp)) ||
1513 ((0x00e0 <= cp) && (0x00f6 >= cp)) ||
1514 ((0x00f8 <= cp) && (0x00fe >= cp)) ||
1515 ((0x03b1 <= cp) && (0x03c1 >= cp)) ||
1516 ((0x03c3 <= cp) && (0x03cb >= cp)) ||
1517 ((0x0430 <= cp) && (0x044f >= cp))) {
1518 cp -= 32;
1519 } else if ((0x0450 <= cp) && (0x045f >= cp)) {
1520 cp -= 80;
1521 } else if (((0x0100 <= cp) && (0x012f >= cp)) ||
1522 ((0x0132 <= cp) && (0x0137 >= cp)) ||
1523 ((0x014a <= cp) && (0x0177 >= cp)) ||
1524 ((0x0182 <= cp) && (0x0185 >= cp)) ||
1525 ((0x01a0 <= cp) && (0x01a5 >= cp)) ||
1526 ((0x01de <= cp) && (0x01ef >= cp)) ||
1527 ((0x01f8 <= cp) && (0x021f >= cp)) ||
1528 ((0x0222 <= cp) && (0x0233 >= cp)) ||
1529 ((0x0246 <= cp) && (0x024f >= cp)) ||
1530 ((0x03d8 <= cp) && (0x03ef >= cp)) ||
1531 ((0x0460 <= cp) && (0x0481 >= cp)) ||
1532 ((0x048a <= cp) && (0x04ff >= cp))) {
1533 cp &= ~0x1;
1534 } else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
1535 ((0x0179 <= cp) && (0x017e >= cp)) ||
1536 ((0x01af <= cp) && (0x01b0 >= cp)) ||
1537 ((0x01b3 <= cp) && (0x01b6 >= cp)) ||
1538 ((0x01cd <= cp) && (0x01dc >= cp))) {
1539 cp -= 1;
1540 cp |= 0x1;
1541 } else {
1542 switch (cp) {
1543 default:
1544 break;
1545 case 0x00ff:
1546 cp = 0x0178;
1547 break;
1548 case 0x0180:
1549 cp = 0x0243;
1550 break;
1551 case 0x01dd:
1552 cp = 0x018e;
1553 break;
1554 case 0x019a:
1555 cp = 0x023d;
1556 break;
1557 case 0x019e:
1558 cp = 0x0220;
1559 break;
1560 case 0x0292:
1561 cp = 0x01b7;
1562 break;
1563 case 0x01c6:
1564 cp = 0x01c4;
1565 break;
1566 case 0x01c9:
1567 cp = 0x01c7;
1568 break;
1569 case 0x01cc:
1570 cp = 0x01ca;
1571 break;
1572 case 0x01f3:
1573 cp = 0x01f1;
1574 break;
1575 case 0x01bf:
1576 cp = 0x01f7;
1577 break;
1578 case 0x0188:
1579 cp = 0x0187;
1580 break;
1581 case 0x018c:
1582 cp = 0x018b;
1583 break;
1584 case 0x0192:
1585 cp = 0x0191;
1586 break;
1587 case 0x0199:
1588 cp = 0x0198;
1589 break;
1590 case 0x01a8:
1591 cp = 0x01a7;
1592 break;
1593 case 0x01ad:
1594 cp = 0x01ac;
1595 break;
1596 case 0x01b9:
1597 cp = 0x01b8;
1598 break;
1599 case 0x01bd:
1600 cp = 0x01bc;
1601 break;
1602 case 0x01f5:
1603 cp = 0x01f4;
1604 break;
1605 case 0x023c:
1606 cp = 0x023b;
1607 break;
1608 case 0x0242:
1609 cp = 0x0241;
1610 break;
1611 case 0x037b:
1612 cp = 0x03fd;
1613 break;
1614 case 0x037c:
1615 cp = 0x03fe;
1616 break;
1617 case 0x037d:
1618 cp = 0x03ff;
1619 break;
1620 case 0x03f3:
1621 cp = 0x037f;
1622 break;
1623 case 0x03ac:
1624 cp = 0x0386;
1625 break;
1626 case 0x03ad:
1627 cp = 0x0388;
1628 break;
1629 case 0x03ae:
1630 cp = 0x0389;
1631 break;
1632 case 0x03af:
1633 cp = 0x038a;
1634 break;
1635 case 0x03cc:
1636 cp = 0x038c;
1637 break;
1638 case 0x03cd:
1639 cp = 0x038e;
1640 break;
1641 case 0x03ce:
1642 cp = 0x038f;
1643 break;
1644 case 0x0371:
1645 cp = 0x0370;
1646 break;
1647 case 0x0373:
1648 cp = 0x0372;
1649 break;
1650 case 0x0377:
1651 cp = 0x0376;
1652 break;
1653 case 0x03d1:
1654 cp = 0x0398;
1655 break;
1656 case 0x03d7:
1657 cp = 0x03cf;
1658 break;
1659 case 0x03f2:
1660 cp = 0x03f9;
1661 break;
1662 case 0x03f8:
1663 cp = 0x03f7;
1664 break;
1665 case 0x03fb:
1666 cp = 0x03fa;
1667 break;
1668 }
1669 }
1670
1671 return cp;
1672}
1673
1675utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
1676 utf8_int32_t *utf8_restrict out_codepoint) {
1677 const utf8_int8_t *s = (const utf8_int8_t *)str;
1678
1679 if (0xf0 == (0xf8 & s[0])) {
1680 /* 4 byte utf8 codepoint */
1681 *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) |
1682 ((0x3f & s[2]) << 6) | (0x3f & s[3]);
1683 } else if (0xe0 == (0xf0 & s[0])) {
1684 /* 3 byte utf8 codepoint */
1685 *out_codepoint =
1686 ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]);
1687 } else if (0xc0 == (0xe0 & s[0])) {
1688 /* 2 byte utf8 codepoint */
1689 *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]);
1690 } else {
1691 /* 1 byte utf8 codepoint otherwise */
1692 *out_codepoint = s[0];
1693 }
1694
1695 do {
1696 s--;
1697 } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0])));
1698
1699 return (utf8_int8_t *)s;
1700}
1701
1702#undef utf8_restrict
1703#undef utf8_constexpr14
1704#undef utf8_null
1705
1706#ifdef utf8_cplusplus
1707} /* extern "C" */
1708#endif
1709
1710#if defined(__clang__)
1711# pragma clang diagnostic pop
1712#endif
int n
Definition acutest.h:538
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8chr(const utf8_int8_t *src, utf8_int32_t chr)
Definition utf8.h:368
utf8_nonnull utf8_weak utf8_int8_t * utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n)
Definition utf8.h:1262
utf8_weak utf8_int8_t * utf8dup(const utf8_int8_t *src)
Definition utf8.h:496
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str)
Definition utf8.h:539
utf8_constexpr14 utf8_nonnull size_t utf8codepointcalcsize(const utf8_int8_t *str)
Definition utf8.h:1234
utf8_nonnull utf8_weak utf8_int8_t * utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, size_t n)
Definition utf8.h:647
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8valid(const utf8_int8_t *str)
Definition utf8.h:1040
utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp)
Definition utf8.h:1511
utf8_constexpr14 utf8_nonnull utf8_pure int utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n)
Definition utf8.h:668
utf8_constexpr14 size_t utf8codepointsize(utf8_int32_t chr)
Definition utf8.h:1250
int32_t utf8_int32_t
Definition utf8.h:60
utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str)
Definition utf8.h:1314
utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str)
Definition utf8.h:1331
utf8_constexpr14_impl utf8_int8_t * utf8fry(const utf8_int8_t *str)
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size_lazy(const utf8_int8_t *str)
Definition utf8.h:893
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str)
Definition utf8.h:889
utf8_nonnull utf8_weak utf8_int8_t * utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src)
Definition utf8.h:349
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject)
Definition utf8.h:445
utf8_constexpr14 utf8_nonnull utf8_int8_t * utf8codepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint)
Definition utf8.h:1209
utf8_constexpr14 int utf8isupper(utf8_int32_t chr)
Definition utf8.h:1310
utf8_constexpr14 utf8_nonnull utf8_int8_t * utf8rcodepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint)
Definition utf8.h:1675
utf8_constexpr14 int utf8islower(utf8_int32_t chr)
Definition utf8.h:1306
utf8_constexpr14 utf8_nonnull utf8_pure int utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n)
Definition utf8.h:573
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle)
Definition utf8.h:959
utf8_constexpr14 utf8_nonnull utf8_pure int utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2)
Definition utf8.h:319
utf8_weak utf8_int8_t * utf8dup_ex(const utf8_int8_t *src, utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), utf8_int8_t *user_data)
Definition utf8.h:500
utf8_weak utf8_int8_t * utf8ndup(const utf8_int8_t *src, size_t n)
Definition utf8.h:722
utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement)
Definition utf8.h:1143
#define utf8_null
Definition utf8.h:110
utf8_weak utf8_int8_t * utf8ndup_ex(const utf8_int8_t *src, size_t n, utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), utf8_int8_t *user_data)
Definition utf8.h:726
utf8_nonnull utf8_weak utf8_int8_t * utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, size_t n)
Definition utf8.h:685
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8rchr(const utf8_int8_t *src, int chr)
Definition utf8.h:769
utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp)
Definition utf8.h:1348
#define utf8_constexpr14_impl
Definition utf8.h:120
utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1, const utf8_int8_t *src2)
Definition utf8.h:409
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle)
Definition utf8.h:994
utf8_nonnull utf8_weak utf8_int8_t * utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src)
Definition utf8.h:429
utf8_constexpr14_impl int utf8coll(const utf8_int8_t *src1, const utf8_int8_t *src2)
char utf8_int8_t
Definition utf8.h:127
#define utf8_constexpr14
Definition utf8.h:119
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept)
Definition utf8.h:841
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept)
Definition utf8.h:905
utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8nvalid(const utf8_int8_t *str, size_t n)
Definition utf8.h:1044
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str, size_t n)
Definition utf8.h:543
utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nsize_lazy(const utf8_int8_t *str, size_t n)
Definition utf8.h:897