1#ifndef BASE_STR_H
2#define BASE_STR_H
3
4#include <cstddef>
5#include <cstdint>
6
7/**
8 * Copies a string to another.
9 *
10 * @ingroup Strings
11 *
12 * @param dst Pointer to a buffer that shall receive the string.
13 * @param src String to be copied.
14 * @param dst_size Size of the buffer dst.
15 *
16 * @return Length of written string, even if it has been truncated
17 *
18 * @remark The strings are treated as null-terminated strings.
19 * @remark Guarantees that dst string will contain null-termination.
20 */
21int str_copy(char *dst, const char *src, int dst_size);
22
23/**
24 * Copies a string to a fixed-size array of chars.
25 *
26 * @ingroup Strings
27 *
28 * @param dst Array that shall receive the string.
29 * @param src String to be copied.
30 *
31 * @remark The strings are treated as null-terminated strings.
32 * @remark Guarantees that dst string will contain null-termination.
33 */
34template<int N>
35void str_copy(char (&dst)[N], const char *src)
36{
37 str_copy(dst, src, N);
38}
39
40/**
41 * Appends a string to another.
42 *
43 * @ingroup Strings
44 *
45 * @param dst Pointer to a buffer that contains a string.
46 * @param src String to append.
47 * @param dst_size Size of the buffer of the dst string.
48 *
49 * @remark The strings are treated as null-terminated strings.
50 * @remark Guarantees that dst string will contain null-termination.
51 */
52void str_append(char *dst, const char *src, int dst_size);
53
54/**
55 * Appends a string to a fixed-size array of chars.
56 *
57 * @ingroup Strings
58 *
59 * @param dst Array that shall receive the string.
60 * @param src String to append.
61 *
62 * @remark The strings are treated as null-terminated strings.
63 * @remark Guarantees that dst string will contain null-termination.
64 */
65template<int N>
66void str_append(char (&dst)[N], const char *src)
67{
68 str_append(dst, src, N);
69}
70
71/**
72 * Truncates a string to a given length.
73 *
74 * @ingroup Strings
75 *
76 * @param dst Pointer to a buffer that shall receive the string.
77 * @param dst_size Size of the buffer dst.
78 * @param src String to be truncated.
79 * @param truncation_len Maximum length of the returned string (not
80 * counting the null-termination).
81 *
82 * @remark The strings are treated as null-terminated strings.
83 * @remark Guarantees that dst string will contain null-termination.
84 */
85void str_truncate(char *dst, int dst_size, const char *src, int truncation_len);
86
87/**
88 * Returns the length of a null-terminated string.
89 *
90 * @ingroup Strings
91 *
92 * @param str Pointer to the string.
93 *
94 * @return Length of string in bytes excluding the null-termination.
95 */
96int str_length(const char *str);
97
98char str_uppercase(char c);
99
100bool str_isnum(char c);
101
102int str_isallnum(const char *str);
103
104int str_isallnum_hex(const char *str);
105
106/**
107 * Determines whether a character is whitespace.
108 *
109 * @ingroup Strings
110 *
111 * @param c the character to check.
112 *
113 * @return `1` if the character is whitespace, `0` otherwise.
114 *
115 * @remark The following characters are considered whitespace: ` `, `\n`, `\r`, `\t`.
116 */
117int str_isspace(char c);
118
119/**
120 * Trims specific number of words at the start of a string.
121 *
122 * @ingroup Strings
123 *
124 * @param str String to trim the words from.
125 * @param words Count of words to trim.
126 *
127 * @return Trimmed string
128 *
129 * @remark The strings are treated as null-terminated strings.
130 * @remark Leading whitespace is always trimmed.
131 */
132const char *str_trim_words(const char *str, int words);
133
134/**
135 * Check whether string has ASCII control characters.
136 *
137 * @ingroup Strings
138 *
139 * @param str String to check.
140 *
141 * @return Whether the string has ASCII control characters.
142 *
143 * @remark The strings are treated as null-terminated strings.
144 */
145bool str_has_cc(const char *str);
146
147/**
148 * Replaces all characters below 32 with whitespace.
149 *
150 * @ingroup Strings
151 *
152 * @param str String to sanitize.
153 *
154 * @remark The strings are treated as null-terminated strings.
155 */
156void str_sanitize_cc(char *str);
157
158/**
159 * Replaces all characters below 32 with whitespace with
160 * exception to `\t`, `\n` and `\n`.
161 *
162 * @ingroup Strings
163 *
164 * @param str String to sanitize.
165 *
166 * @remark The strings are treated as null-terminated strings.
167 */
168void str_sanitize(char *str);
169
170/**
171 * Replaces all invalid filename characters with whitespace.
172 *
173 * @param str String to sanitize.
174 * @remark The strings are treated as null-terminated strings.
175 */
176void str_sanitize_filename(char *str);
177
178/**
179 * Checks if a string is a valid filename on all supported platforms.
180 *
181 * @param str Filename to check.
182 *
183 * @return `true` if the string is a valid filename, `false` otherwise.
184 *
185 * @remark The strings are treated as null-terminated strings.
186 */
187bool str_valid_filename(const char *str);
188
189/**
190 * Compares two strings case insensitive, digit chars will be compared as numbers.
191 *
192 * @ingroup Strings
193 *
194 * @param a String to compare.
195 * @param b String to compare.
196 *
197 * @return `< 0` - String a is less than string b
198 * @return `0` - String a is equal to string b
199 * @return `> 0` - String a is greater than string b
200 *
201 * @remark The strings are treated as null-terminated strings.
202 */
203int str_comp_filenames(const char *a, const char *b);
204
205/**
206 * Removes leading and trailing spaces and limits the use of multiple spaces.
207 *
208 * @ingroup Strings
209 *
210 * @param str String to clean up.
211 *
212 * @remark The strings are treated as null-terminated strings.
213 */
214void str_clean_whitespaces(char *str);
215
216/**
217 * Skips leading non-whitespace characters.
218 *
219 * @ingroup Strings
220 *
221 * @param str Pointer to the string.
222 *
223 * @return Pointer to the first whitespace character found
224 * within the string.
225 *
226 * @remark The strings are treated as null-terminated strings.
227 * @remark Whitespace is defined according to str_isspace.
228 */
229char *str_skip_to_whitespace(char *str);
230
231/**
232 * @ingroup Strings
233 *
234 * @see str_skip_to_whitespace
235 */
236const char *str_skip_to_whitespace_const(const char *str);
237
238/**
239 * Skips leading whitespace characters.
240 *
241 * @ingroup Strings
242 *
243 * @param str Pointer to the string.
244 *
245 * @return Pointer to the first non-whitespace character found
246 * within the string.
247 *
248 * @remark The strings are treated as null-terminated strings.
249 * @remark Whitespace is defined according to str_isspace.
250 */
251char *str_skip_whitespaces(char *str);
252
253/**
254 * @ingroup Strings
255 *
256 * @see str_skip_whitespaces
257 */
258const char *str_skip_whitespaces_const(const char *str);
259
260/**
261 * Compares to strings case insensitively.
262 *
263 * @ingroup Strings
264 *
265 * @param a String to compare.
266 * @param b String to compare.
267 *
268 * @return `< 0` if string a is less than string b.
269 * @return `0` if string a is equal to string b.
270 * @return `> 0` if string a is greater than string b.
271 *
272 * @remark Only guaranteed to work with a-z/A-Z.
273 * @remark The strings are treated as null-terminated strings.
274 */
275int str_comp_nocase(const char *a, const char *b);
276
277/**
278 * Compares up to `num` characters of two strings case insensitively.
279 *
280 * @ingroup Strings
281 *
282 * @param a String to compare.
283 * @param b String to compare.
284 * @param num Maximum characters to compare.
285 *
286 * @return `< 0` if string a is less than string b.
287 * @return `0` if string a is equal to string b.
288 * @return `> 0` if string a is greater than string b.
289 *
290 * @remark Only guaranteed to work with a-z/A-Z.
291 * @remark Use `str_utf8_comp_nocase_num` for unicode support.
292 * @remark The strings are treated as null-terminated strings.
293 */
294int str_comp_nocase_num(const char *a, const char *b, int num);
295
296/**
297 * Compares two strings case sensitive.
298 *
299 * @ingroup Strings
300 *
301 * @param a String to compare.
302 * @param b String to compare.
303 *
304 * @return `< 0` if string a is less than string b.
305 * @return `0` if string a is equal to string b.
306 * @return `> 0` if string a is greater than string b.
307 *
308 * @remark The strings are treated as null-terminated strings.
309 */
310int str_comp(const char *a, const char *b);
311
312/**
313 * Compares up to `num` characters of two strings case sensitive.
314 *
315 * @ingroup Strings
316 *
317 * @param a String to compare.
318 * @param b String to compare.
319 * @param num Maximum characters to compare.
320 *
321 * @return `< 0` if string a is less than string b.
322 * @return `0` if string a is equal to string b.
323 * @return `> 0` if string a is greater than string b.
324 *
325 * @remark The strings are treated as null-terminated strings.
326 */
327int str_comp_num(const char *a, const char *b, int num);
328
329/**
330 * Checks case insensitive whether the string begins with a certain prefix.
331 *
332 * @ingroup Strings
333 *
334 * @param str String to check.
335 * @param prefix Prefix to look for.
336 *
337 * @return A pointer to the string `str` after the string prefix, or `nullptr` if
338 * the string prefix isn't a prefix of the string `str`.
339 *
340 * @remark The strings are treated as null-terminated strings.
341 */
342const char *str_startswith_nocase(const char *str, const char *prefix);
343
344/**
345 * Checks case sensitive whether the string begins with a certain prefix.
346 *
347 * @ingroup Strings
348 *
349 * @param str String to check.
350 * @param prefix Prefix to look for.
351 *
352 * @return A pointer to the string `str` after the string prefix, or `nullptr` if
353 * the string prefix isn't a prefix of the string `str`.
354 *
355 * @remark The strings are treated as null-terminated strings.
356 */
357const char *str_startswith(const char *str, const char *prefix);
358
359/**
360 * Checks case insensitive whether the string ends with a certain suffix.
361 *
362 * @ingroup Strings
363 *
364 * @param str String to check.
365 * @param suffix Suffix to look.
366 *
367 * @return A pointer to the beginning of the suffix in the string `str`.
368 * @return `nullptr` if the string suffix isn't a suffix of the string `str`.
369 *
370 * @remark The strings are treated as null-terminated strings.
371 */
372const char *str_endswith_nocase(const char *str, const char *suffix);
373
374/**
375 * Checks case sensitive whether the string ends with a certain suffix.
376 *
377 * @param str String to check.
378 * @param suffix Suffix to look for.
379 *
380 * @return A pointer to the beginning of the suffix in the string `str`.
381 * @return `nullptr` if the string suffix isn't a suffix of the string `str`.
382 *
383 * @remark The strings are treated as null-terminated strings.
384 */
385const char *str_endswith(const char *str, const char *suffix);
386
387/**
388 * Finds a string inside another string case insensitively.
389 *
390 * @ingroup Strings
391 *
392 * @param haystack String to search in.
393 * @param needle String to search for.
394 *
395 * @return A pointer into `haystack` where the needle was found.
396 * @return Returns `nullptr` if `needle` could not be found.
397 *
398 * @remark Only guaranteed to work with a-z/A-Z.
399 * @remark Use str_utf8_find_nocase for unicode support.
400 * @remark The strings are treated as null-terminated strings.
401 */
402const char *str_find_nocase(const char *haystack, const char *needle);
403
404/**
405 * Finds a string inside another string case sensitive.
406 *
407 * @ingroup Strings
408 *
409 * @param haystack String to search in.
410 * @param needle String to search for.
411 *
412 * @return A pointer into `haystack` where the needle was found.
413 * @return Returns `nullptr` if `needle` could not be found.
414 *
415 * @remark The strings are treated as null-terminated strings.
416 */
417const char *str_find(const char *haystack, const char *needle);
418
419/**
420 * Writes the next token after str into buf, returns the rest of the string.
421 *
422 * @ingroup Strings
423 *
424 * @param str Pointer to string.
425 * @param delim Delimiter for tokenization.
426 * @param buffer Buffer to store token in.
427 * @param buffer_size Size of the buffer.
428 *
429 * @return Pointer to rest of the string.
430 *
431 * @remark The token is always null-terminated.
432 */
433const char *str_next_token(const char *str, const char *delim, char *buffer, int buffer_size);
434
435/**
436 * Checks if needle is in list delimited by delim.
437 *
438 * @param list List.
439 * @param delim List delimiter.
440 * @param needle Item that is being looked for.
441 *
442 * @return `1` - Item is in list.
443 * @return `0` - Item isn't in list.
444 *
445 * @remark The strings are treated as null-terminated strings.
446 */
447int str_in_list(const char *list, const char *delim, const char *needle);
448
449/**
450 * @ingroup Strings
451 *
452 * @param haystack String to search in.
453 * @param delim String to search for.
454 * @param offset Number of characters into `haystack`.
455 * @param start Will be set to the first delimiter on the left side of the offset (or `haystack` start).
456 * @param end Will be set to the first delimiter on the right side of the offset (or `haystack` end).
457 *
458 * @return `true` if both delimiters were found.
459 * @return `false` if a delimiter is missing (it uses `haystack` start and end as fallback).
460 *
461 * @remark The strings are treated as null-terminated strings.
462 */
463bool str_delimiters_around_offset(const char *haystack, const char *delim, int offset, int *start, int *end);
464
465/**
466 * Finds the last occurrence of a character
467 *
468 * @ingroup Strings
469 *
470 * @param haystack String to search in.
471 * @param needle Character to search for.
472
473 * @return A pointer into haystack where the needle was found.
474 * @return Returns `nullptr` if needle could not be found.
475 *
476 * @remark The strings are treated as null-terminated strings.
477 * @remark The zero-terminator character can also be found with this function.
478 */
479const char *str_rchr(const char *haystack, char needle);
480
481/**
482 * Counts the number of occurrences of a character in a string.
483 *
484 * @ingroup Strings
485 *
486 * @param haystack String to count in.
487 * @param needle Character to count.
488
489 * @return The number of characters in the haystack string matching
490 * the needle character.
491 *
492 * @remark The strings are treated as null-terminated strings.
493 * @remark The number of zero-terminator characters cannot be counted.
494 */
495int str_countchr(const char *haystack, char needle);
496
497/**
498 * Takes a datablock and generates a hex string of it, with spaces between bytes.
499 *
500 * @ingroup Strings
501 *
502 * @param dst Buffer to fill with hex data.
503 * @param dst_size Size of the buffer (at least 3 * data_size + 1 to contain all data).
504 * @param data Data to turn into hex.
505 * @param data_size Size of the data.
506 *
507 * @remark The destination buffer will be null-terminated.
508 */
509void str_hex(char *dst, int dst_size, const void *data, int data_size);
510
511/**
512 * Takes a datablock and generates a hex string of it, in the C style array format,
513 * i.e. with bytes formatted in 0x00-0xFF notation and commas with spaces between the bytes.
514 * The output can be split over multiple lines by specifying the maximum number of bytes
515 * that should be printed per line.
516 *
517 * @ingroup Strings
518 *
519 * @param dst Buffer to fill with hex data.
520 * @param dst_size Size of the buffer (at least `6 * data_size + 1` to contain all data).
521 * @param data Data to turn into hex.
522 * @param data_size Size of the data.
523 * @param bytes_per_line After this many printed bytes a newline will be printed.
524 *
525 * @remark The destination buffer will be null-terminated.
526 */
527void str_hex_cstyle(char *dst, int dst_size, const void *data, int data_size, int bytes_per_line = 12);
528
529/**
530 * Takes a hex string *without spaces between bytes* and returns a byte array.
531 *
532 * @ingroup Strings
533 *
534 * @param dst Buffer for the byte array.
535 * @param dst_size size of the buffer.
536 * @param src String to decode.
537 *
538 * @return `2` if string doesn't exactly fit the buffer.
539 * @return `1` if invalid character in string.
540 * @return `0` if success.
541 *
542 * @remark The contents of the buffer is only valid on success.
543 */
544int str_hex_decode(void *dst, int dst_size, const char *src);
545
546/**
547 * Takes a datablock and generates the base64 encoding of it.
548 *
549 * @ingroup Strings
550 *
551 * @param dst Buffer to fill with base64 data.
552 * @param dst_size Size of the buffer.
553 * @param data Data to turn into base64.
554 * @param data_size Size of the data.
555 *
556 * @remark The destination buffer will be null-terminated
557 */
558void str_base64(char *dst, int dst_size, const void *data, int data_size);
559
560/**
561 * Takes a base64 string without any whitespace and correct
562 * padding and returns a byte array.
563 *
564 * @ingroup Strings
565 *
566 * @param dst Buffer for the byte array.
567 * @param dst_size Size of the buffer.
568 * @param data String to decode.
569 *
570 * @return `< 0` - Error.
571 * @return `<= 0` - Success, length of the resulting byte buffer.
572 *
573 * @remark The contents of the buffer is only valid on success.
574 */
575int str_base64_decode(void *dst, int dst_size, const char *data);
576
577/**
578 * Escapes \ and " characters in a string.
579 *
580 * @param dst Destination array pointer, gets increased, will point to the terminating null.
581 * @param src Source array.
582 * @param end End of destination array.
583 */
584void str_escape(char **dst, const char *src, const char *end);
585
586int str_toint(const char *str);
587bool str_toint(const char *str, int *out);
588int str_toint_base(const char *str, int base);
589unsigned long str_toulong_base(const char *str, int base);
590int64_t str_toint64_base(const char *str, int base = 10);
591float str_tofloat(const char *str);
592bool str_tofloat(const char *str, float *out);
593
594unsigned str_quickhash(const char *str);
595
596/**
597 * Encode a UTF-8 character.
598 *
599 * @ingroup Strings
600 *
601 * @param ptr Pointer to a buffer that should receive the data. Should be able to hold at least 4 bytes.
602 * @param chr Unicode codepoint to encode.
603 *
604 * @return Number of bytes put into the buffer.
605 *
606 * @remark Does not do null-termination of the string.
607 */
608int str_utf8_encode(char *ptr, int chr);
609
610/**
611 * Decodes a UTF-8 codepoint.
612 *
613 * @ingroup Strings
614 *
615 * @param ptr Pointer to a UTF-8 string. This pointer will be moved forward.
616 *
617 * @return The Unicode codepoint. `-1` for invalid input and 0 for end of string.
618 *
619 * @remark This function will also move the pointer forward.
620 * @remark You may call this function again after an error occurred.
621 * @remark The strings are treated as null-terminated.
622 */
623int str_utf8_decode(const char **ptr);
624
625/**
626 * Truncates a UTF-8 encoded string to a given length.
627 *
628 * @ingroup Strings
629 *
630 * @param dst Pointer to a buffer that shall receive the string.
631 * @param dst_size Size of the buffer dst.
632 * @param src String to be truncated.
633 * @param truncation_len Maximum codepoints in the returned string.
634 *
635 * @remark The strings are treated as utf8-encoded null-terminated strings.
636 * @remark Guarantees that dst string will contain null-termination.
637 */
638void str_utf8_truncate(char *dst, int dst_size, const char *src, int truncation_len);
639
640/**
641 * Fixes truncation of a Unicode character at the end of a UTF-8 string.
642 *
643 * @ingroup Strings
644 *
645 * @param str UTF-8 string.
646 *
647 * @return The new string length.
648 *
649 * @remark The strings are treated as null-terminated.
650 */
651int str_utf8_fix_truncation(char *str);
652
653/**
654 * Removes trailing characters that render as spaces by modifying the string in-place.
655 *
656 * @ingroup Strings
657 *
658 * @param param Input string.
659 *
660 * @remark The string is modified in-place.
661 * @remark The strings are treated as null-terminated.
662 */
663void str_utf8_trim_right(char *param);
664
665/**
666 * Converts the given UTF-8 string to lowercase (locale insensitive).
667 *
668 * @ingroup Strings
669 *
670 * @param input String to convert to lowercase.
671 * @param output Buffer that will receive the lowercase string.
672 * @param size Size of the output buffer.
673 *
674 * @remark The strings are treated as zero-terminated strings.
675 * @remark This function does not work in-place as converting a UTF-8 string to
676 * lowercase may increase its length.
677 */
678void str_utf8_tolower(const char *input, char *output, size_t size);
679
680/**
681 * Checks whether the given Unicode codepoint renders as space.
682 *
683 * @ingroup Strings
684 *
685 * @param code Unicode codepoint to check.
686 *
687 * @return Whether the codepoint is a space.
688 */
689int str_utf8_isspace(int code);
690
691/**
692 * Checks whether a given byte is the start of a UTF-8 character.
693 *
694 * @ingroup Strings
695 *
696 * @param c Byte to check.
697 *
698 * @return Whether the char starts a UTF-8 character.
699 */
700int str_utf8_isstart(char c);
701
702/**
703 * Moves a cursor backwards in an UTF-8 string,
704 *
705 * @ingroup Strings
706 *
707 * @param str UTF-8 string.
708 * @param cursor Position in the string.
709 *
710 * @return New cursor position.
711 *
712 * @remark Won't move the cursor less then 0.
713 * @remark The strings are treated as null-terminated.
714 */
715int str_utf8_rewind(const char *str, int cursor);
716
717/**
718 * Finds a UTF-8 string inside another UTF-8 string case insensitively.
719 *
720 * @ingroup Strings
721 *
722 * @param haystack String to search in.
723 * @param needle String to search for.
724 * @param end A pointer that will be set to a pointer into haystack directly behind the
725 * last character where the needle was found. Will be set to `nullptr `if needle
726 * could not be found. Optional parameter.
727 *
728 * @return A pointer into haystack where the needle was found.
729 * @return Returns `nullptr` if needle could not be found.
730 *
731 * @remark The strings are treated as null-terminated strings.
732 */
733const char *str_utf8_find_nocase(const char *haystack, const char *needle, const char **end = nullptr);
734
735/**
736 * Compares two UTF-8 strings case insensitively.
737 *
738 * @ingroup Strings
739 *
740 * @param a String to compare.
741 * @param b String to compare.
742 *
743 * @return `< 0` if string a is less than string b.
744 * @return `0` if string a is equal to string b.
745 * @return `> 0` if string a is greater than string b.
746 */
747int str_utf8_comp_nocase(const char *a, const char *b);
748
749/**
750 * Compares up to `num` bytes of two UTF-8 strings case insensitively.
751 *
752 * @ingroup Strings
753 *
754 * @param a String to compare.
755 * @param b String to compare.
756 * @param num Maximum bytes to compare.
757 *
758 * @return `< 0` if string a is less than string b.
759 * @return `0` if string a is equal to string b.
760 * @return `> 0` if string a is greater than string b.
761 */
762int str_utf8_comp_nocase_num(const char *a, const char *b, int num);
763
764/**
765 * Skips leading characters that render as spaces.
766 *
767 * @ingroup Strings
768 *
769 * @param str Input string.
770 *
771 * @return Pointer to the first non-whitespace character found within the string.
772 * @remark The strings are treated as null-terminated strings.
773 */
774const char *str_utf8_skip_whitespaces(const char *str);
775
776/**
777 * Moves a cursor forwards in an UTF-8 string.
778 *
779 * @ingroup Strings
780 *
781 * @param str UTF-8 string.
782 * @param cursor Position in the string.
783 *
784 * @return New cursor position.
785 *
786 * @remark Won't move the cursor beyond the null-termination marker.
787 * @remark The strings are treated as null-terminated.
788 */
789int str_utf8_forward(const char *str, int cursor);
790
791/**
792 * Checks if a strings contains just valid UTF-8 characters.
793 *
794 * @ingroup Strings
795 *
796 * @param str Pointer to a possible UTF-8 string.
797 *
798 * @return `0` if invalid characters were found, `1` if only valid characters were found.
799 *
800 * @remark The string is treated as null-terminated UTF-8 string.
801 */
802int str_utf8_check(const char *str);
803
804/**
805 * Copies a number of UTF-8 characters from one string to another.
806 *
807 * @ingroup Strings
808 *
809 * @param dst Pointer to a buffer that shall receive the string.
810 * @param src String to be copied.
811 * @param dst_size Size of the buffer dst.
812 * @param num Maximum number of UTF-8 characters to be copied.
813 *
814 * @remark The strings are treated as null-terminated strings.
815 * @remark Guarantees that dst string will contain null-termination.
816 */
817void str_utf8_copy_num(char *dst, const char *src, int dst_size, int num);
818
819/**
820 * Determines the byte size and UTF-8 character count of a UTF-8 string.
821 *
822 * @ingroup Strings
823 *
824 * @param str Pointer to the string.
825 * @param max_size Maximum number of bytes to count.
826 * @param max_count Maximum number of UTF-8 characters to count.
827 * @param size Pointer to store size (number of non. Zero bytes) of the string.
828 * @param count Pointer to store count of UTF-8 characters of the string.
829 *
830 * @remark The string is treated as null-terminated UTF-8 string.
831 * @remark It's the user's responsibility to make sure the bounds are aligned.
832 */
833void str_utf8_stats(const char *str, size_t max_size, size_t max_count, size_t *size, size_t *count);
834
835/**
836 * Converts a byte offset of a UTF-8 string to the UTF-8 character offset.
837 *
838 * @ingroup Strings
839 *
840 * @param str Pointer to the string.
841 * @param byte_offset Offset in bytes.
842 *
843 * @return Offset in UTF-8 characters. Clamped to the maximum length of the string in UTF-8 characters.
844 *
845 * @remark The string is treated as a null-terminated UTF-8 string.
846 * @remark It's the user's responsibility to make sure the bounds are aligned.
847 */
848size_t str_utf8_offset_bytes_to_chars(const char *str, size_t byte_offset);
849
850/**
851 * Converts a UTF-8 character offset of a UTF-8 string to the byte offset.
852 *
853 * @ingroup Strings
854 *
855 * @param str Pointer to the string.
856 * @param char_offset Offset in UTF-8 characters.
857 *
858 * @return Offset in bytes. Clamped to the maximum length of the string in bytes.
859 *
860 * @remark The string is treated as a null-terminated UTF-8 string.
861 * @remark It's the user's responsibility to make sure the bounds are aligned.
862 */
863size_t str_utf8_offset_chars_to_bytes(const char *str, size_t char_offset);
864
865#endif
866