1#pragma once
2
3#include <ctype.h>
4
5#include <pw_assert.h>
6#include <pw_types.h>
7#include <pw_utf.h>
8
9#ifdef PW_WITH_ICU
10 // ICU library for character classification:
11# include <unicode/uchar.h>
12#endif
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18/****************************************************************
19 * String constructors
20 */
21
22[[nodiscard]] bool pw_create_empty_string(unsigned capacity, uint8_t char_size, PwValuePtr result);
23
24#define pw_create_string(initializer, result) _Generic((initializer), \
25 char*: _pw_create_string_ascii, \
26 char8_t*: _pw_create_string_utf8, \
27 char32_t*: _pw_create_string_utf32, \
28 PwValuePtr: _pw_create_string \
29 )((initializer), (result))
30
31[[nodiscard]] bool _pw_create_string (PwValuePtr initializer, PwValuePtr result);
32[[nodiscard]] bool _pw_create_string_ascii(char* initializer, PwValuePtr result);
33[[nodiscard]] bool _pw_create_string_utf8 (char8_t* initializer, PwValuePtr result);
34[[nodiscard]] bool _pw_create_string_utf32(char32_t* initializer, PwValuePtr result);
35
36
37/****************************************************************
38 * Basic functions
39 */
40
41static inline uint8_t* _pw_string_start(PwValuePtr str)
42/*
43 * Return pointer to the start of internal string data.
44 */
45{
46 if (str->embedded) {
47 return str->str_1;
48 } else if (str->allocated) {
49 return str->string_data->data;
50 } else {
51 return str->char_ptr;
52 }
53}
54
55static inline uint8_t* _pw_string_start_end(PwValuePtr str, uint8_t** end)
56/*
57 * Return pointer to the start of internal string data
58 * and write final pointer to `end`.
59 */
60{
61 uint8_t* start_ptr;
62 uint8_t char_size = str->char_size;
63 if (str->embedded) {
64 start_ptr = str->str_1;
65 *end = start_ptr + str->embedded_length * char_size;
66 } else if (str->allocated) {
67 start_ptr = str->string_data->data;
68 *end = start_ptr + str->length * char_size;
69 } else {
70 // static string
71 start_ptr = str->char_ptr;
72 *end = start_ptr + str->length * char_size;
73 }
74 return start_ptr;
75}
76
77static inline uint8_t* _pw_string_start_length(PwValuePtr str, unsigned* length)
78/*
79 * Return pointer to the start of internal string data
80 * and write length of string to `length`.
81 */
82{
83 if (str->embedded) {
84 *length = str->embedded_length;
85 return str->str_1;
86 } else if (str->allocated) {
87 *length = str->length;
88 return str->string_data->data;
89 } else {
90 *length = str->length;
91 return str->char_ptr;
92 }
93}
94
95[[noreturn]]
96void _pw_panic_bad_char_size(uint8_t char_size);
97
98static inline char32_t _pw_get_char(uint8_t* ptr, uint8_t char_size)
99{
100 if (_pw_likely(char_size == 1)) {
101 return *ptr;
102 }
103 if (_pw_likely(char_size == 2)) {
104 return *(uint16_t*) ptr;
105 }
106 if (_pw_likely(char_size == 0)) {
107 return _pw_decode_utf8_char(&ptr);
108 }
109 if (_pw_likely(char_size == 4)) {
110 return *(char32_t*) ptr;
111 }
112 if (_pw_likely(char_size == 3)) {
113 char32_t c = *ptr++;
114 c |= (*ptr++) << 8;
115 c |= (*ptr) << 16;
116 return c;
117 }
118 _pw_panic_bad_char_size(char_size);
119}
120
121static inline char32_t _pw_get_char_reverse(uint8_t** ptr, uint8_t char_size)
122{
123 if (_pw_likely(char_size == 1)) {
124 uint8_t* p = *ptr;
125 p--;
126 *ptr = p;
127 return *p;
128 }
129 if (_pw_likely(char_size == 2)) {
130 uint16_t* p = *(uint16_t**) ptr;
131 p--;
132 *ptr = (uint8_t*) p;
133 return *p;
134 }
135 if (_pw_likely(char_size == 0)) {
136 return _pw_decode_utf8_char_reverse(ptr);
137 }
138 if (_pw_likely(char_size == 4)) {
139 char32_t* p = *(char32_t**) ptr;
140 p--;
141 *ptr = (uint8_t*) p;
142 return *p;
143 }
144 if (_pw_likely(char_size == 3)) {
145 uint8_t* p = *ptr;
146 p -= 3;
147 *ptr = p;
148 char32_t c = *p++;
149 c |= (*p++) << 8;
150 c |= (*p) << 16;
151 return c;
152 }
153 _pw_panic_bad_char_size(char_size);
154}
155
156static inline unsigned _pw_put_char(uint8_t* ptr, char32_t chr, uint8_t char_size)
157{
158 if (_pw_likely(char_size == 1)) {
159 *ptr = (uint8_t) chr;
160 } else if (_pw_likely(char_size == 2)) {
161 *((uint16_t*) ptr) = (uint16_t) chr;
162 } else if (_pw_likely(char_size == 0)) {
163 return pw_char32_to_utf8(chr, (char*) ptr);
164 } else if (_pw_likely(char_size == 4)) {
165 *((char32_t*) ptr) = chr;
166 } else if (_pw_likely(char_size == 3)) {
167 *ptr++ = (uint8_t) chr; chr >>= 8;
168 *ptr++ = (uint8_t) chr; chr >>= 8;
169 *ptr = (uint8_t) chr;
170 } else {
171 _pw_panic_bad_char_size(char_size);
172 }
173 return char_size;
174}
175
176char32_t pw_char_at(PwValuePtr str, unsigned position);
177/*
178 * Return character at `position`.
179 * If position is beyond end of line return 0.
180 */
181
182// check if `index` is within string length
183#define pw_string_index_valid(str, index) ((index) < pw_strlen(str))
184
185static inline unsigned pw_strlen(PwValuePtr str)
186/*
187 * Return length of string.
188 */
189{
190 pw_assert_string(str);
191 if (str->embedded) {
192 return str->embedded_length;
193 } else {
194 return str->length;
195 }
196}
197
198[[nodiscard]] bool pw_substr(PwValuePtr str, unsigned start_pos, unsigned end_pos, PwValuePtr result);
199/*
200 * Get substring from `start_pos` to `end_pos`.
201 */
202
203[[nodiscard]] bool pw_string_erase(PwValuePtr str, unsigned start_pos, unsigned end_pos);
204/*
205 * Erase characters from `start_pos` to `end_pos`.
206 * This may make a copy of string, so checking return value is mandatory.
207 */
208
209[[nodiscard]] bool pw_string_truncate(PwValuePtr str, unsigned position);
210/*
211 * Truncate string at given `position`.
212 * This may make a copy of string, so checking return value is mandatory.
213 */
214
215[[ nodiscard]] bool pw_strchr(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result);
216/*
217 * Find first occurence of `chr` in `str` starting from `start_pos`.
218 *
219 * Return true if character is found and write its position to `result`.
220 * `result` can be nullptr if position is not needed and the function
221 * is called just to check if `chr` is in `str`.
222 */
223
224[[ nodiscard]] bool pw_strchr2(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result, uint8_t* max_char_size);
225/*
226 * Same as `pw_strchr` and `pw_strrchr`, but also return maximal char size.
227 */
228
229[[ nodiscard]] bool pw_strchri(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result);
230/*
231 * Find first case-insensitive occurence of `chr` in `str` starting from `start_pos`.
232 *
233 * Return true if character is found and write its position to `result`.
234 * `result` can be nullptr if position is not needed and the function
235 * is called just to check if `chr` is in `str`.
236 */
237
238[[nodiscard]] bool pw_string_ltrim(PwValuePtr str);
239[[nodiscard]] bool pw_string_rtrim(PwValuePtr str);
240[[nodiscard]] bool pw_string_trim(PwValuePtr str);
241
242[[nodiscard]] bool pw_string_lower(PwValuePtr str);
243[[nodiscard]] bool pw_string_upper(PwValuePtr str);
244
245
246#ifdef PW_WITH_ICU
247# define pw_char_lower(c) u_tolower(c)
248# define pw_char_upper(c) u_toupper(c)
249#else
250# define pw_char_lower(c) tolower(c)
251# define pw_char_upper(c) toupper(c)
252#endif
253
254#define pw_strcat(result, str, ...) \
255 _pw_strcat_va((result), (str) __VA_OPT__(,) __VA_ARGS__, PwVaEnd())
256
257[[nodiscard]] bool _pw_strcat_va(PwValuePtr result, ...);
258[[nodiscard]] bool _pw_strcat_ap(PwValuePtr result, va_list ap);
259
260unsigned pw_string_skip_spaces(PwValuePtr str, unsigned position);
261/*
262 * Find position of the first non-space character starting from `position`.
263 * If non-space character is not found, the length is returned.
264 */
265
266unsigned pw_string_skip_chars(PwValuePtr str, unsigned position, char32_t* skipchars);
267/*
268 * Find position of the first character not belonging to `skipchars` starting from `position`.
269 * If no `skipchars` encountered, the length is returned.
270 */
271
272/****************************************************************
273 * Character classification functions
274 */
275
276#ifdef PW_WITH_ICU
277# define pw_isspace(c) u_isspace(c)
278# define pw_isblank(c) u_isblank(c)
279# define pw_isalpha(c) u_isalpha(c)
280# define pw_isdigit(c) u_isdigit(c)
281# define pw_isalnum(c) u_isalnum(c)
282# define pw_ispunct(c) u_ispunct(c)
283# define pw_iscntrl(c) u_iscntrl(c)
284# define pw_isgraph(c) u_isgraph(c)
285# define pw_isprint(c) u_isprint(c)
286#else
287# define pw_isspace(c) ((c) <= 255 && isspace((unsigned char) (c)))
288# define pw_isblank(c) ((c) <= 255 && isblank((unsigned char) (c)))
289# define pw_isalpha(c) ((c) <= 255 && isalpha((unsigned char) (c)))
290# define pw_isdigit(c) ((c) <= 255 && isdigit((unsigned char) (c)))
291# define pw_isalnum(c) ((c) <= 255 && isalnum((unsigned char) (c)))
292# define pw_ispunct(c) ((c) <= 255 && ispunct((unsigned char) (c)))
293# define pw_iscntrl(c) ((c) <= 255 && iscntrl((unsigned char) (c)))
294# define pw_isgraph(c) ((c) <= 255 && isgraph((unsigned char) (c)))
295# define pw_isprint(c) ((c) <= 255 && isprint((unsigned char) (c)))
296#endif
297/*
298 * Return true if `c` is a whitespace character.
299 */
300
301#define pw_is_ascii_digit(c) isdigit(c)
302/*
303 * Return true if `c` is an ASCII digit.
304 * Do not consider any other unicode digits because this function
305 * is used in conjunction with standard C library (string to number conversion)
306 * that does not support unicode character classification.
307 */
308
309bool pw_string_isspace(PwValuePtr str);
310bool pw_string_isdigit(PwValuePtr str);
311bool pw_string_is_ascii_digit(PwValuePtr str);
312/*
313 * Return true if `str` is not empty and contains all digits.
314 */
315
316/****************************************************************
317 * Append functions
318 *
319 * Characters and PwValues:
320 *
321 * pw_string_append(dest_string, chr);
322 * pw_string_append(dest_string, src_string);
323 *
324 * Raw data (char*, char8_t*, char32_t*):
325 *
326 * pw_string_append(dest_string, start_ptr, end_ptr);
327 *
328 * Null-terminated C strings:
329 *
330 * pw_string_append(dest_string, start_ptr, nullptr);
331 *
332 * C strings are slowest because strlen is called to obtain end_ptr.
333 */
334
335#define pw_string_append(dest, src, ...) _Generic((src), \
336 char32_t: _pw_string_append_c32, \
337 int: _pw_string_append_c32, \
338 char*: _pw_string_append_ascii, \
339 char8_t*: _pw_string_append_utf8, \
340 char32_t*: _pw_string_append_utf32, \
341 PwValuePtr: _pw_string_append \
342 )((dest), (src) __VA_OPT__(,) __VA_ARGS__)
343
344[[nodiscard]] bool _pw_string_append_c32 (PwValuePtr dest, char32_t c);
345[[nodiscard]] bool _pw_string_append (PwValuePtr dest, PwValuePtr src);
346[[nodiscard]] bool _pw_string_append_ascii(PwValuePtr dest, char* start_ptr, char* end_ptr);
347[[nodiscard]] bool _pw_string_append_utf8 (PwValuePtr dest, char8_t* start_ptr, char8_t* end_ptr);
348[[nodiscard]] bool _pw_string_append_utf32(PwValuePtr dest, char32_t* start_ptr, char32_t* end_ptr);
349
350
351/****************************************************************
352 * Insert functions
353 * TODO other types
354 */
355
356#define pw_string_insert_chars(str, position, chr, n) _Generic((chr), \
357 char32_t: _pw_string_insert_many_c32, \
358 int: _pw_string_insert_many_c32 \
359 )((str), (position), (chr), (n))
360
361[[nodiscard]] bool _pw_string_insert_many_c32(PwValuePtr str, unsigned position, char32_t chr, unsigned n);
362
363/****************************************************************
364 * Append substring.
365 *
366 * Append `src` substring starting from `src_start_pos` to `src_end_pos`.
367 */
368
369[[nodiscard]] bool pw_string_append_substring(PwValuePtr dest, PwValuePtr src, unsigned src_start_pos, unsigned src_end_pos);
370
371
372/****************************************************************
373 * Substring comparison functions.
374 *
375 * Compare `str_a` from `start_pos` to `end_pos` with `str_b`.
376 */
377
378#define pw_substring_eq(a, start_pos, end_pos, b) _Generic((b), \
379 char*: _pw_substring_eq_ascii, \
380 char8_t*: _pw_substring_eq_utf8, \
381 char32_t*: _pw_substring_eq_utf32, \
382 PwValuePtr: _pw_substring_eq \
383 )((a), (start_pos), (end_pos), (b))
384
385[[nodiscard]] bool _pw_substring_eq (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
386[[nodiscard]] bool _pw_substring_eq_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
387
388[[nodiscard]] static inline bool _pw_substring_eq_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
389{
390 return _pw_substring_eq_z(a, start_pos, end_pos, b, 1);
391}
392[[nodiscard]] static inline bool _pw_substring_eq_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
393{
394 return _pw_substring_eq_z(a, start_pos, end_pos, b, 0);
395}
396[[nodiscard]] static inline bool _pw_substring_eq_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
397{
398 return _pw_substring_eq_z(a, start_pos, end_pos, b, 4);
399}
400
401
402#define pw_substring_eqi(a, start_pos, end_pos, b) _Generic((b), \
403 char*: _pw_substring_eqi_ascii, \
404 char8_t*: _pw_substring_eqi_utf8, \
405 char32_t*: _pw_substring_eqi_utf32, \
406 PwValuePtr: _pw_substring_eqi \
407 )((a), (start_pos), (end_pos), (b))
408
409[[nodiscard]] bool _pw_substring_eqi (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
410[[nodiscard]] bool _pw_substring_eqi_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
411
412[[nodiscard]] static inline bool _pw_substring_eqi_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
413{
414 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 1);
415}
416[[nodiscard]] static inline bool _pw_substring_eqi_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
417{
418 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 0);
419}
420[[nodiscard]] static inline bool _pw_substring_eqi_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
421{
422 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 4);
423}
424
425
426#define pw_startswith(str, prefix) _Generic((prefix), \
427 int: _pw_startswith_c32, \
428 char32_t: _pw_startswith_c32, \
429 char*: _pw_startswith_ascii, \
430 char8_t*: _pw_startswith_utf8, \
431 char32_t*: _pw_startswith_utf32, \
432 PwValuePtr: _pw_startswith \
433 )((str), (prefix))
434
435[[nodiscard]] bool _pw_startswith_c32(PwValuePtr str, char32_t prefix);
436[[nodiscard]] bool _pw_startswith (PwValuePtr str, PwValuePtr prefix);
437[[nodiscard]] bool _pw_startswith_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
438
439[[nodiscard]] static inline bool _pw_startswith_ascii(PwValuePtr str, char* prefix)
440{
441 return _pw_startswith_z(str, prefix, 1);
442}
443[[nodiscard]] static inline bool _pw_startswith_utf8(PwValuePtr str, char8_t* prefix)
444{
445 return _pw_startswith_z(str, prefix, 0);
446}
447[[nodiscard]] static inline bool _pw_startswith_utf32(PwValuePtr str, char32_t* prefix)
448{
449 return _pw_startswith_z(str, prefix, 4);
450}
451
452
453#define pw_startswithi(str, prefix) _Generic((prefix), \
454 int: _pw_startswithi_c32, \
455 char32_t: _pw_startswithi_c32, \
456 char*: _pw_startswithi_ascii, \
457 char8_t*: _pw_startswithi_utf8, \
458 char32_t*: _pw_startswithi_utf32, \
459 PwValuePtr: _pw_startswithi \
460 )((str), (prefix))
461
462[[nodiscard]] bool _pw_startswithi_c32(PwValuePtr str, char32_t prefix);
463[[nodiscard]] bool _pw_startswithi (PwValuePtr str, PwValuePtr prefix);
464[[nodiscard]] bool _pw_startswithi_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
465
466[[nodiscard]] static inline bool _pw_startswithi_ascii(PwValuePtr str, char* prefix)
467{
468 return _pw_startswithi_z(str, prefix, 1);
469}
470[[nodiscard]] static inline bool _pw_startswithi_utf8(PwValuePtr str, char8_t* prefix)
471{
472 return _pw_startswithi_z(str, prefix, 0);
473}
474[[nodiscard]] static inline bool _pw_startswithi_utf32(PwValuePtr str, char32_t* prefix)
475{
476 return _pw_startswithi_z(str, prefix, 4);
477}
478
479
480#define pw_endswith(str, suffix) _Generic((suffix), \
481 int: _pw_endswith_c32, \
482 char32_t: _pw_endswith_c32, \
483 char*: _pw_endswith_ascii, \
484 char8_t*: _pw_endswith_utf8, \
485 char32_t*: _pw_endswith_utf32, \
486 PwValuePtr: _pw_endswith \
487 )((str), (suffix))
488
489[[nodiscard]] bool _pw_endswith_c32(PwValuePtr str, char32_t suffix);
490[[nodiscard]] bool _pw_endswith (PwValuePtr str, PwValuePtr suffix);
491[[nodiscard]] bool _pw_endswith_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
492
493[[nodiscard]] static inline bool _pw_endswith_ascii(PwValuePtr str, char* suffix)
494{
495 return _pw_endswith_z(str, suffix, 1);
496}
497[[nodiscard]] static inline bool _pw_endswith_utf8(PwValuePtr str, char8_t* suffix)
498{
499 return _pw_endswith_z(str, suffix, 0);
500}
501[[nodiscard]] static inline bool _pw_endswith_utf32(PwValuePtr str, char32_t* suffix)
502{
503 return _pw_endswith_z(str, suffix, 4);
504}
505
506
507#define pw_endswithi(str, suffix) _Generic((suffix), \
508 int: _pw_endswithi_c32, \
509 char32_t: _pw_endswithi_c32, \
510 char*: _pw_endswithi_ascii, \
511 char8_t*: _pw_endswithi_utf8, \
512 char32_t*: _pw_endswithi_utf32, \
513 PwValuePtr: _pw_endswithi \
514 )((str), (suffix))
515
516[[nodiscard]] bool _pw_endswithi_c32(PwValuePtr str, char32_t suffix);
517[[nodiscard]] bool _pw_endswithi (PwValuePtr str, PwValuePtr suffix);
518[[nodiscard]] bool _pw_endswithi_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
519
520[[nodiscard]] static inline bool _pw_endswithi_ascii(PwValuePtr str, char* suffix)
521{
522 return _pw_endswithi_z(str, suffix, 1);
523}
524[[nodiscard]] static inline bool _pw_endswithi_utf8(PwValuePtr str, char8_t* suffix)
525{
526 return _pw_endswithi_z(str, suffix, 0);
527}
528[[nodiscard]] static inline bool _pw_endswithi_utf32(PwValuePtr str, char32_t* suffix)
529{
530 return _pw_endswithi_z(str, suffix, 4);
531}
532
533
534/****************************************************************
535 * Substring scanning functions.
536 */
537
538#define pw_strstr(str, substr, start_pos, pos) _Generic((substr), \
539 char*: _pw_strstr_ascii, \
540 char8_t*: _pw_strstr_utf8, \
541 char32_t*: _pw_strstr_utf32, \
542 PwValuePtr: _pw_strstr \
543 )((str), (substr), (start_pos), (pos))
544
545[[nodiscard]] bool _pw_strstr(PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
546
547[[nodiscard]] bool _pw_strstr_z(PwValuePtr str, void* substr, uint8_t substr_char_size, unsigned start_pos, unsigned* pos);
548
549[[nodiscard]] static inline bool _pw_strstr_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos)
550{
551 return _pw_strstr_z(str, substr, 1, start_pos, pos);
552}
553[[nodiscard]] static inline bool _pw_strstr_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos)
554{
555 return _pw_strstr_z(str, substr, 0, start_pos, pos);
556}
557[[nodiscard]] static inline bool _pw_strstr_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos)
558{
559 return _pw_strstr_z(str, substr, 4, start_pos, pos);
560}
561
562#define pw_strstri(str, substr, pos) _Generic((substr), \
563 char*: _pw_strstri_ascii, \
564 char8_t*: _pw_strstri_utf8, \
565 char32_t*: _pw_strstri_utf32, \
566 PwValuePtr: _pw_strstri \
567 )((str), (substr), (start_pos), (pos))
568
569[[nodiscard]] bool _pw_strstri (PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
570[[nodiscard]] bool _pw_strstri_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos);
571[[nodiscard]] bool _pw_strstri_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos);
572[[nodiscard]] bool _pw_strstri_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos);
573
574
575/****************************************************************
576 * Split functions.
577 * Return array of strings.
578 * maxsplit == 0 imposes no limit
579 */
580
581[[nodiscard]] bool _pw_string_split (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
582[[nodiscard]] bool _pw_string_split_chr (PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
583[[nodiscard]] bool _pw_string_rsplit (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
584[[nodiscard]] bool _pw_string_rsplit_chr(PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
585
586#define pw_string_split(...) _pw_string_split (__VA_ARGS__, PwTypeId_BasicArray)
587#define pw_string_split_chr(...) _pw_string_split_chr (__VA_ARGS__, PwTypeId_BasicArray)
588#define pw_string_rsplit(...) _pw_string_rsplit (__VA_ARGS__, PwTypeId_BasicArray)
589#define pw_string_rsplit_chr(...) _pw_string_rsplit_chr(__VA_ARGS__, PwTypeId_BasicArray)
590
591#define _pw_string_split_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
592 char*: _pw_string_split_any_ascii, \
593 char8_t*: _pw_string_split_any_utf8, \
594 char32_t*: _pw_string_split_any_utf32, \
595 PwValuePtr: _pw_string_split_any_var \
596 )((str), (splitters), (maxsplit), (result_type))
597
598#define pw_string_split_any(...) _pw_string_split_any(__VA_ARGS__, PwTypeId_BasicArray)
599
600[[nodiscard]] bool _pw_string_split_any_var (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
601[[nodiscard]] bool _pw_string_split_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
602[[nodiscard]] bool _pw_string_split_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
603[[nodiscard]] bool _pw_string_split_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
604
605#define _pw_string_rsplit_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
606 char*: _pw_string_rsplit_any_ascii, \
607 char8_t*: _pw_string_rsplit_any_utf8, \
608 char32_t*: _pw_string_rsplit_any_utf32, \
609 PwValuePtr: _pw_string_rsplit_any_var \
610 )((str), (splitters), (maxsplit), (result_type))
611
612#define pw_string_rsplit_any(...) _pw_string_rsplit_any(__VA_ARGS__, PwTypeId_BasicArray)
613
614[[nodiscard]] bool _pw_string_rsplit_any_var (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
615[[nodiscard]] bool _pw_string_rsplit_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
616[[nodiscard]] bool _pw_string_rsplit_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
617[[nodiscard]] bool _pw_string_rsplit_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
618
619#define _pw_string_split_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
620 char*: _pw_string_split_substr_ascii, \
621 char8_t*: _pw_string_split_substr_utf8, \
622 char32_t*: _pw_string_split_substr_utf32, \
623 PwValuePtr: _pw_string_split_substr_var \
624 )((str), (splitter), (maxsplit), (result_type))
625
626#define pw_string_split_substr(...) _pw_string_split_substr(__VA_ARGS__, PwTypeId_BasicArray)
627
628[[nodiscard]] bool _pw_string_split_substr_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
629[[nodiscard]] bool _pw_string_split_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
630[[nodiscard]] bool _pw_string_split_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
631[[nodiscard]] bool _pw_string_split_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
632
633#define _pw_string_split_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
634 char*: _pw_string_split_substri_ascii, \
635 char8_t*: _pw_string_split_substri_utf8, \
636 char32_t*: _pw_string_split_substri_utf32, \
637 PwValuePtr: _pw_string_split_substri_var \
638 )((str), (splitter), (maxsplit), (result_type))
639
640#define pw_string_split_substri(...) _pw_string_split_substri(__VA_ARGS__, PwTypeId_BasicArray)
641
642[[nodiscard]] bool _pw_string_split_substri_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
643[[nodiscard]] bool _pw_string_split_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
644[[nodiscard]] bool _pw_string_split_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
645[[nodiscard]] bool _pw_string_split_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
646
647#define _pw_string_rsplit_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
648 char*: _pw_string_rsplit_substr_ascii, \
649 char8_t*: _pw_string_rsplit_substr_utf8, \
650 char32_t*: _pw_string_rsplit_substr_utf32, \
651 PwValuePtr: _pw_string_rsplit_substr_var \
652 )((str), (splitter), (maxsplit), (result_type))
653
654#define pw_string_rsplit_substr(...) _pw_string_rsplit_substr(__VA_ARGS__, PwTypeId_BasicArray)
655
656[[nodiscard]] bool _pw_string_rsplit_substr_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
657[[nodiscard]] bool _pw_string_rsplit_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
658[[nodiscard]] bool _pw_string_rsplit_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
659[[nodiscard]] bool _pw_string_rsplit_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
660
661#define _pw_string_rsplit_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
662 char*: _pw_string_rsplit_substri_ascii, \
663 char8_t*: _pw_string_rsplit_substri_utf8, \
664 char32_t*: _pw_string_rsplit_substri_utf32, \
665 PwValuePtr: _pw_string_rsplit_substri_var \
666 )((str), (splitter), (maxsplit), (result_type))
667
668#define pw_string_rsplit_substri(...) _pw_string_rsplit_substri(__VA_ARGS__, PwTypeId_BasicArray)
669
670[[nodiscard]] bool _pw_string_rsplit_substri_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
671[[nodiscard]] bool _pw_string_rsplit_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
672[[nodiscard]] bool _pw_string_rsplit_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
673[[nodiscard]] bool _pw_string_rsplit_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
674
675
676/****************************************************************
677 * C strings
678 */
679
680// somewhat ugly macro to define a local variable initialized with a copy of pw string:
681#define PW_CSTRING(variable_name, pw_str) \
682 char variable_name[pw_strlen_in_utf8(pw_str) + 1]; \
683 pw_string_to_utf8((pw_str), variable_name)
684
685
686#ifdef __cplusplus
687}
688#endif