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