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