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(result, initializer) _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 )((result), (initializer))
30
31[[nodiscard]] bool _pw_create_string (PwValuePtr result, PwValuePtr initializer);
32[[nodiscard]] bool _pw_create_string_ascii(PwValuePtr result, char* initializer);
33[[nodiscard]] bool _pw_create_string_utf8 (PwValuePtr result, char8_t* initializer);
34[[nodiscard]] bool _pw_create_string_utf32(PwValuePtr result, char32_t* initializer);
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_lstrip(PwValuePtr str);
239[[nodiscard]] bool pw_string_rstrip(PwValuePtr str);
240[[nodiscard]] bool pw_string_strip(PwValuePtr str);
241
242[[nodiscard]] bool pw_string_lstrip_chars(PwValuePtr str, char32_t* chars);
243[[nodiscard]] bool pw_string_rstrip_chars(PwValuePtr str, char32_t* chars);
244[[nodiscard]] bool pw_string_strip_chars(PwValuePtr str, char32_t* chars);
245
246
247[[nodiscard]] bool pw_string_lower(PwValuePtr str);
248[[nodiscard]] bool pw_string_upper(PwValuePtr str);
249
250
251#ifdef PW_WITH_ICU
252# define pw_char_lower(c) u_tolower(c)
253# define pw_char_upper(c) u_toupper(c)
254#else
255# define pw_char_lower(c) tolower(c)
256# define pw_char_upper(c) toupper(c)
257#endif
258
259#define pw_strcat(result, str, ...) \
260 _pw_strcat_va((result), (str) __VA_OPT__(,) __VA_ARGS__, PwVaEnd())
261
262[[nodiscard]] bool _pw_strcat_va(PwValuePtr result, ...);
263[[nodiscard]] bool _pw_strcat_ap(PwValuePtr result, va_list ap);
264
265unsigned pw_string_skip_spaces(PwValuePtr str, unsigned position);
266/*
267 * Find position of the first non-space character starting from `position`.
268 * If non-space character is not found, the length is returned.
269 */
270
271unsigned pw_string_skip_chars(PwValuePtr str, unsigned position, char32_t* skipchars);
272/*
273 * Find position of the first character not belonging to `skipchars` starting from `position`.
274 * If no `skipchars` encountered, the length is returned.
275 */
276
277/****************************************************************
278 * Character classification functions
279 */
280
281#ifdef PW_WITH_ICU
282# define pw_isspace(c) u_isspace(c)
283# define pw_isblank(c) u_isblank(c)
284# define pw_isalpha(c) u_isalpha(c)
285# define pw_isdigit(c) u_isdigit(c)
286# define pw_isalnum(c) u_isalnum(c)
287# define pw_ispunct(c) u_ispunct(c)
288# define pw_iscntrl(c) u_iscntrl(c)
289# define pw_isgraph(c) u_isgraph(c)
290# define pw_isprint(c) u_isprint(c)
291#else
292# define pw_isspace(c) ((c) <= 255 && isspace((unsigned char) (c)))
293# define pw_isblank(c) ((c) <= 255 && isblank((unsigned char) (c)))
294# define pw_isalpha(c) ((c) <= 255 && isalpha((unsigned char) (c)))
295# define pw_isdigit(c) ((c) <= 255 && isdigit((unsigned char) (c)))
296# define pw_isalnum(c) ((c) <= 255 && isalnum((unsigned char) (c)))
297# define pw_ispunct(c) ((c) <= 255 && ispunct((unsigned char) (c)))
298# define pw_iscntrl(c) ((c) <= 255 && iscntrl((unsigned char) (c)))
299# define pw_isgraph(c) ((c) <= 255 && isgraph((unsigned char) (c)))
300# define pw_isprint(c) ((c) <= 255 && isprint((unsigned char) (c)))
301#endif
302/*
303 * Return true if `c` is a whitespace character.
304 */
305
306#define pw_is_ascii_digit(c) isdigit(c)
307/*
308 * Return true if `c` is an ASCII digit.
309 * Do not consider any other unicode digits because this function
310 * is used in conjunction with standard C library (string to number conversion)
311 * that does not support unicode character classification.
312 */
313
314bool pw_string_isspace(PwValuePtr str);
315bool pw_string_isdigit(PwValuePtr str);
316bool pw_string_is_ascii_digit(PwValuePtr str);
317/*
318 * Return true if `str` is not empty and contains all digits.
319 */
320
321/****************************************************************
322 * Append functions
323 *
324 * Characters and PwValues:
325 *
326 * pw_string_append(dest_string, chr);
327 * pw_string_append(dest_string, src_string);
328 *
329 * Raw data (char*, char8_t*, char32_t*):
330 *
331 * pw_string_append(dest_string, start_ptr, end_ptr);
332 *
333 * Null-terminated C strings:
334 *
335 * pw_string_append(dest_string, start_ptr, nullptr);
336 *
337 * C strings are slowest because strlen is called to obtain end_ptr.
338 */
339
340#define pw_string_append(dest, src, ...) _Generic((src), \
341 char32_t: _pw_string_append_c32, \
342 int: _pw_string_append_c32, \
343 char*: _pw_string_append_ascii, \
344 char8_t*: _pw_string_append_utf8, \
345 char32_t*: _pw_string_append_utf32, \
346 PwValuePtr: _pw_string_append \
347 )((dest), (src) __VA_OPT__(,) __VA_ARGS__)
348
349[[nodiscard]] bool _pw_string_append_c32 (PwValuePtr dest, char32_t c);
350[[nodiscard]] bool _pw_string_append (PwValuePtr dest, PwValuePtr src);
351[[nodiscard]] bool _pw_string_append_ascii(PwValuePtr dest, char* start_ptr, char* end_ptr);
352[[nodiscard]] bool _pw_string_append_utf8 (PwValuePtr dest, char8_t* start_ptr, char8_t* end_ptr);
353[[nodiscard]] bool _pw_string_append_utf32(PwValuePtr dest, char32_t* start_ptr, char32_t* end_ptr);
354
355
356/****************************************************************
357 * Insert functions
358 * TODO other types
359 */
360
361#define pw_string_insert_chars(str, position, chr, n) _Generic((chr), \
362 char32_t: _pw_string_insert_many_c32, \
363 int: _pw_string_insert_many_c32 \
364 )((str), (position), (chr), (n))
365
366[[nodiscard]] bool _pw_string_insert_many_c32(PwValuePtr str, unsigned position, char32_t chr, unsigned n);
367
368/****************************************************************
369 * Append substring.
370 *
371 * Append `src` substring starting from `src_start_pos` to `src_end_pos`.
372 */
373
374[[nodiscard]] bool pw_string_append_substring(PwValuePtr dest, PwValuePtr src, unsigned src_start_pos, unsigned src_end_pos);
375
376
377/****************************************************************
378 * Substring comparison functions.
379 *
380 * Compare `str_a` from `start_pos` to `end_pos` with `str_b`.
381 */
382
383#define pw_substring_eq(a, start_pos, end_pos, b) _Generic((b), \
384 char*: _pw_substring_eq_ascii, \
385 char8_t*: _pw_substring_eq_utf8, \
386 char32_t*: _pw_substring_eq_utf32, \
387 PwValuePtr: _pw_substring_eq \
388 )((a), (start_pos), (end_pos), (b))
389
390[[nodiscard]] bool _pw_substring_eq (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
391[[nodiscard]] bool _pw_substring_eq_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
392
393[[nodiscard]] static inline bool _pw_substring_eq_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
394{
395 return _pw_substring_eq_z(a, start_pos, end_pos, b, 1);
396}
397[[nodiscard]] static inline bool _pw_substring_eq_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
398{
399 return _pw_substring_eq_z(a, start_pos, end_pos, b, 0);
400}
401[[nodiscard]] static inline bool _pw_substring_eq_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
402{
403 return _pw_substring_eq_z(a, start_pos, end_pos, b, 4);
404}
405
406
407#define pw_substring_eqi(a, start_pos, end_pos, b) _Generic((b), \
408 char*: _pw_substring_eqi_ascii, \
409 char8_t*: _pw_substring_eqi_utf8, \
410 char32_t*: _pw_substring_eqi_utf32, \
411 PwValuePtr: _pw_substring_eqi \
412 )((a), (start_pos), (end_pos), (b))
413
414[[nodiscard]] bool _pw_substring_eqi (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
415[[nodiscard]] bool _pw_substring_eqi_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
416
417[[nodiscard]] static inline bool _pw_substring_eqi_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
418{
419 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 1);
420}
421[[nodiscard]] static inline bool _pw_substring_eqi_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
422{
423 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 0);
424}
425[[nodiscard]] static inline bool _pw_substring_eqi_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
426{
427 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 4);
428}
429
430
431#define pw_startswith(str, prefix) _Generic((prefix), \
432 int: _pw_startswith_c32, \
433 char32_t: _pw_startswith_c32, \
434 char*: _pw_startswith_ascii, \
435 char8_t*: _pw_startswith_utf8, \
436 char32_t*: _pw_startswith_utf32, \
437 PwValuePtr: _pw_startswith \
438 )((str), (prefix))
439
440[[nodiscard]] bool _pw_startswith_c32(PwValuePtr str, char32_t prefix);
441[[nodiscard]] bool _pw_startswith (PwValuePtr str, PwValuePtr prefix);
442[[nodiscard]] bool _pw_startswith_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
443
444[[nodiscard]] static inline bool _pw_startswith_ascii(PwValuePtr str, char* prefix)
445{
446 return _pw_startswith_z(str, prefix, 1);
447}
448[[nodiscard]] static inline bool _pw_startswith_utf8(PwValuePtr str, char8_t* prefix)
449{
450 return _pw_startswith_z(str, prefix, 0);
451}
452[[nodiscard]] static inline bool _pw_startswith_utf32(PwValuePtr str, char32_t* prefix)
453{
454 return _pw_startswith_z(str, prefix, 4);
455}
456
457
458#define pw_startswithi(str, prefix) _Generic((prefix), \
459 int: _pw_startswithi_c32, \
460 char32_t: _pw_startswithi_c32, \
461 char*: _pw_startswithi_ascii, \
462 char8_t*: _pw_startswithi_utf8, \
463 char32_t*: _pw_startswithi_utf32, \
464 PwValuePtr: _pw_startswithi \
465 )((str), (prefix))
466
467[[nodiscard]] bool _pw_startswithi_c32(PwValuePtr str, char32_t prefix);
468[[nodiscard]] bool _pw_startswithi (PwValuePtr str, PwValuePtr prefix);
469[[nodiscard]] bool _pw_startswithi_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
470
471[[nodiscard]] static inline bool _pw_startswithi_ascii(PwValuePtr str, char* prefix)
472{
473 return _pw_startswithi_z(str, prefix, 1);
474}
475[[nodiscard]] static inline bool _pw_startswithi_utf8(PwValuePtr str, char8_t* prefix)
476{
477 return _pw_startswithi_z(str, prefix, 0);
478}
479[[nodiscard]] static inline bool _pw_startswithi_utf32(PwValuePtr str, char32_t* prefix)
480{
481 return _pw_startswithi_z(str, prefix, 4);
482}
483
484
485#define pw_endswith(str, suffix) _Generic((suffix), \
486 int: _pw_endswith_c32, \
487 char32_t: _pw_endswith_c32, \
488 char*: _pw_endswith_ascii, \
489 char8_t*: _pw_endswith_utf8, \
490 char32_t*: _pw_endswith_utf32, \
491 PwValuePtr: _pw_endswith \
492 )((str), (suffix))
493
494[[nodiscard]] bool _pw_endswith_c32(PwValuePtr str, char32_t suffix);
495[[nodiscard]] bool _pw_endswith (PwValuePtr str, PwValuePtr suffix);
496[[nodiscard]] bool _pw_endswith_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
497
498[[nodiscard]] static inline bool _pw_endswith_ascii(PwValuePtr str, char* suffix)
499{
500 return _pw_endswith_z(str, suffix, 1);
501}
502[[nodiscard]] static inline bool _pw_endswith_utf8(PwValuePtr str, char8_t* suffix)
503{
504 return _pw_endswith_z(str, suffix, 0);
505}
506[[nodiscard]] static inline bool _pw_endswith_utf32(PwValuePtr str, char32_t* suffix)
507{
508 return _pw_endswith_z(str, suffix, 4);
509}
510
511
512#define pw_endswithi(str, suffix) _Generic((suffix), \
513 int: _pw_endswithi_c32, \
514 char32_t: _pw_endswithi_c32, \
515 char*: _pw_endswithi_ascii, \
516 char8_t*: _pw_endswithi_utf8, \
517 char32_t*: _pw_endswithi_utf32, \
518 PwValuePtr: _pw_endswithi \
519 )((str), (suffix))
520
521[[nodiscard]] bool _pw_endswithi_c32(PwValuePtr str, char32_t suffix);
522[[nodiscard]] bool _pw_endswithi (PwValuePtr str, PwValuePtr suffix);
523[[nodiscard]] bool _pw_endswithi_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
524
525[[nodiscard]] static inline bool _pw_endswithi_ascii(PwValuePtr str, char* suffix)
526{
527 return _pw_endswithi_z(str, suffix, 1);
528}
529[[nodiscard]] static inline bool _pw_endswithi_utf8(PwValuePtr str, char8_t* suffix)
530{
531 return _pw_endswithi_z(str, suffix, 0);
532}
533[[nodiscard]] static inline bool _pw_endswithi_utf32(PwValuePtr str, char32_t* suffix)
534{
535 return _pw_endswithi_z(str, suffix, 4);
536}
537
538
539/****************************************************************
540 * Substring scanning functions.
541 *
542 * Return true if substring is found, false if not.
543 */
544
545#define pw_strstr(str, substr, start_pos, pos) _Generic((substr), \
546 char*: _pw_strstr_ascii, \
547 char8_t*: _pw_strstr_utf8, \
548 char32_t*: _pw_strstr_utf32, \
549 PwValuePtr: _pw_strstr \
550 )((str), (substr), (start_pos), (pos))
551
552[[nodiscard]] bool _pw_strstr(PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
553
554[[nodiscard]] bool _pw_strstr_z(PwValuePtr str, void* substr, uint8_t substr_char_size, unsigned start_pos, unsigned* pos);
555
556[[nodiscard]] static inline bool _pw_strstr_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos)
557{
558 return _pw_strstr_z(str, substr, 1, start_pos, pos);
559}
560[[nodiscard]] static inline bool _pw_strstr_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos)
561{
562 return _pw_strstr_z(str, substr, 0, start_pos, pos);
563}
564[[nodiscard]] static inline bool _pw_strstr_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos)
565{
566 return _pw_strstr_z(str, substr, 4, start_pos, pos);
567}
568
569#define pw_strstri(str, substr, pos) _Generic((substr), \
570 char*: _pw_strstri_ascii, \
571 char8_t*: _pw_strstri_utf8, \
572 char32_t*: _pw_strstri_utf32, \
573 PwValuePtr: _pw_strstri \
574 )((str), (substr), (start_pos), (pos))
575
576[[nodiscard]] bool _pw_strstri (PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
577[[nodiscard]] bool _pw_strstri_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos);
578[[nodiscard]] bool _pw_strstri_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos);
579[[nodiscard]] bool _pw_strstri_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos);
580
581
582/****************************************************************
583 * Split functions.
584 * Return array of strings.
585 * maxsplit == 0 imposes no limit
586 */
587
588[[nodiscard]] bool _pw_string_split (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
589[[nodiscard]] bool _pw_string_split_chr (PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
590[[nodiscard]] bool _pw_string_rsplit (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
591[[nodiscard]] bool _pw_string_rsplit_chr(PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
592
593#define pw_string_split(...) _pw_string_split (__VA_ARGS__, PwTypeId_BasicArray)
594#define pw_string_split_chr(...) _pw_string_split_chr (__VA_ARGS__, PwTypeId_BasicArray)
595#define pw_string_rsplit(...) _pw_string_rsplit (__VA_ARGS__, PwTypeId_BasicArray)
596#define pw_string_rsplit_chr(...) _pw_string_rsplit_chr(__VA_ARGS__, PwTypeId_BasicArray)
597
598#define _pw_string_split_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
599 char*: _pw_string_split_any_ascii, \
600 char8_t*: _pw_string_split_any_utf8, \
601 char32_t*: _pw_string_split_any_utf32, \
602 PwValuePtr: _pw_string_split_any_var \
603 )((str), (splitters), (maxsplit), (result_type))
604
605#define pw_string_split_any(...) _pw_string_split_any(__VA_ARGS__, PwTypeId_BasicArray)
606
607[[nodiscard]] bool _pw_string_split_any_var (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
608[[nodiscard]] bool _pw_string_split_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
609[[nodiscard]] bool _pw_string_split_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
610[[nodiscard]] bool _pw_string_split_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
611
612#define _pw_string_rsplit_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
613 char*: _pw_string_rsplit_any_ascii, \
614 char8_t*: _pw_string_rsplit_any_utf8, \
615 char32_t*: _pw_string_rsplit_any_utf32, \
616 PwValuePtr: _pw_string_rsplit_any_var \
617 )((str), (splitters), (maxsplit), (result_type))
618
619#define pw_string_rsplit_any(...) _pw_string_rsplit_any(__VA_ARGS__, PwTypeId_BasicArray)
620
621[[nodiscard]] bool _pw_string_rsplit_any_var (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
622[[nodiscard]] bool _pw_string_rsplit_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
623[[nodiscard]] bool _pw_string_rsplit_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
624[[nodiscard]] bool _pw_string_rsplit_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
625
626#define _pw_string_split_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
627 char*: _pw_string_split_substr_ascii, \
628 char8_t*: _pw_string_split_substr_utf8, \
629 char32_t*: _pw_string_split_substr_utf32, \
630 PwValuePtr: _pw_string_split_substr_var \
631 )((str), (splitter), (maxsplit), (result_type))
632
633#define pw_string_split_substr(...) _pw_string_split_substr(__VA_ARGS__, PwTypeId_BasicArray)
634
635[[nodiscard]] bool _pw_string_split_substr_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
636[[nodiscard]] bool _pw_string_split_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
637[[nodiscard]] bool _pw_string_split_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
638[[nodiscard]] bool _pw_string_split_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
639
640#define _pw_string_split_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
641 char*: _pw_string_split_substri_ascii, \
642 char8_t*: _pw_string_split_substri_utf8, \
643 char32_t*: _pw_string_split_substri_utf32, \
644 PwValuePtr: _pw_string_split_substri_var \
645 )((str), (splitter), (maxsplit), (result_type))
646
647#define pw_string_split_substri(...) _pw_string_split_substri(__VA_ARGS__, PwTypeId_BasicArray)
648
649[[nodiscard]] bool _pw_string_split_substri_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
650[[nodiscard]] bool _pw_string_split_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
651[[nodiscard]] bool _pw_string_split_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
652[[nodiscard]] bool _pw_string_split_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
653
654#define _pw_string_rsplit_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
655 char*: _pw_string_rsplit_substr_ascii, \
656 char8_t*: _pw_string_rsplit_substr_utf8, \
657 char32_t*: _pw_string_rsplit_substr_utf32, \
658 PwValuePtr: _pw_string_rsplit_substr_var \
659 )((str), (splitter), (maxsplit), (result_type))
660
661#define pw_string_rsplit_substr(...) _pw_string_rsplit_substr(__VA_ARGS__, PwTypeId_BasicArray)
662
663[[nodiscard]] bool _pw_string_rsplit_substr_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
664[[nodiscard]] bool _pw_string_rsplit_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
665[[nodiscard]] bool _pw_string_rsplit_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
666[[nodiscard]] bool _pw_string_rsplit_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
667
668#define _pw_string_rsplit_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
669 char*: _pw_string_rsplit_substri_ascii, \
670 char8_t*: _pw_string_rsplit_substri_utf8, \
671 char32_t*: _pw_string_rsplit_substri_utf32, \
672 PwValuePtr: _pw_string_rsplit_substri_var \
673 )((str), (splitter), (maxsplit), (result_type))
674
675#define pw_string_rsplit_substri(...) _pw_string_rsplit_substri(__VA_ARGS__, PwTypeId_BasicArray)
676
677[[nodiscard]] bool _pw_string_rsplit_substri_var (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
678[[nodiscard]] bool _pw_string_rsplit_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
679[[nodiscard]] bool _pw_string_rsplit_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
680[[nodiscard]] bool _pw_string_rsplit_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
681
682
683/****************************************************************
684 * C strings
685 */
686
687// somewhat ugly macro to define a local variable initialized with a copy of pw string:
688#define PW_CSTRING(variable_name, pw_str) \
689 char variable_name[pw_strlen_in_utf8(pw_str) + 1]; \
690 pw_string_to_utf8((pw_str), variable_name)
691
692
693#ifdef __cplusplus
694}
695#endif