1#pragma once
2
3#include <pw_assert.h>
4#include <pw_interfaces.h>
5#include <pw_utf.h>
6
7#ifdef __cplusplus
8extern "C" {
9#endif
10
11/****************************************************************
12 * Low-level functions
13 */
14
15static inline uint8_t* _pw_string_start(PwValuePtr str)
16/*
17 * Return pointer to the start of internal string data.
18 */
19{
20 if (str->str_params.integral) {
21 return str->str_1;
22 } else if (str->str_params.allocated) {
23 return str->string_data->data;
24 } else {
25 return str->char_ptr;
26 }
27}
28
29static inline uint8_t* _pw_string_start_end(PwValuePtr str, uint8_t** end)
30/*
31 * Return pointer to the start of internal string data
32 * and write final pointer to `end`.
33 */
34{
35 uint8_t* start_ptr;
36 uint8_t char_size = str->str_params.char_size;
37 if (str->str_params.integral) {
38 start_ptr = str->str_1;
39 *end = start_ptr + str->integral_length * char_size;
40 } else if (str->str_params.allocated) {
41 start_ptr = str->string_data->data;
42 *end = start_ptr + str->length * char_size;
43 } else {
44 // static string
45 start_ptr = str->char_ptr;
46 *end = start_ptr + str->length * char_size;
47 }
48 return start_ptr;
49}
50
51static inline uint8_t* _pw_string_start_length(PwValuePtr str, unsigned* length)
52/*
53 * Return pointer to the start of internal string data
54 * and write length of string to `length`.
55 */
56{
57 if (str->str_params.integral) {
58 *length = str->integral_length;
59 return str->str_1;
60 } else if (str->str_params.allocated) {
61 *length = str->length;
62 return str->string_data->data;
63 } else {
64 *length = str->length;
65 return str->char_ptr;
66 }
67}
68
69[[noreturn]]
70void _pw_panic_bad_char_size(uint8_t char_size);
71
72static inline char32_t _pw_get_char(uint8_t* ptr, uint8_t char_size)
73{
74 if (_pw_likely(char_size == 1)) {
75 return *ptr;
76 }
77 if (_pw_likely(char_size == 2)) {
78 return *(uint16_t*) ptr;
79 }
80 if (_pw_likely(char_size == 0)) {
81 return _pw_decode_utf8_char(&ptr);
82 }
83 if (_pw_likely(char_size == 4)) {
84 return *(char32_t*) ptr;
85 }
86 if (_pw_likely(char_size == 3)) {
87 char32_t c = *ptr++;
88 c |= *ptr++ << 8;
89 c |= *ptr << 16;
90 return c;
91 }
92 _pw_panic_bad_char_size(char_size);
93}
94
95static inline char32_t _pw_next_char(uint8_t** ptr, uint8_t char_size)
96{
97 if (_pw_likely(char_size == 1)) {
98 return *(*ptr)++;
99 }
100 if (_pw_likely(char_size == 2)) {
101 return *(* (uint16_t**) ptr)++;
102 }
103 if (_pw_likely(char_size == 0)) {
104 return _pw_decode_utf8_char(ptr);
105 }
106 if (_pw_likely(char_size == 4)) {
107 return *(* (char32_t**) ptr)++;
108 }
109 if (_pw_likely(char_size == 3)) {
110 char32_t c = *(*ptr)++;
111 c |= *(*ptr)++ << 8;
112 c |= *(*ptr)++ << 16;
113 return c;
114 }
115 _pw_panic_bad_char_size(char_size);
116}
117
118static inline char32_t _pw_prev_char(uint8_t** ptr, uint8_t char_size)
119{
120 if (_pw_likely(char_size == 1)) {
121 return *(--*ptr);
122 }
123 if (_pw_likely(char_size == 2)) {
124 return *(--* (uint16_t**) ptr);
125 }
126 if (_pw_likely(char_size == 0)) {
127 return _pw_decode_utf8_char_reverse(ptr);
128 }
129 if (_pw_likely(char_size == 4)) {
130 return *(--* (char32_t**) ptr);
131 }
132 if (_pw_likely(char_size == 3)) {
133 uint8_t* p = *ptr;
134 p -= 3;
135 *ptr = p;
136 char32_t c = *p++;
137 c |= (*p++) << 8;
138 c |= (*p) << 16;
139 return c;
140 }
141 _pw_panic_bad_char_size(char_size);
142}
143
144static inline unsigned _pw_put_char(uint8_t* ptr, char32_t chr, uint8_t char_size)
145{
146 if (_pw_likely(char_size == 1)) {
147 *ptr = (uint8_t) chr;
148 } else if (_pw_likely(char_size == 2)) {
149 *((uint16_t*) ptr) = (uint16_t) chr;
150 } else if (_pw_likely(char_size == 0)) {
151 return pw_char32_to_utf8(chr, (char*) ptr);
152 } else if (_pw_likely(char_size == 4)) {
153 *((char32_t*) ptr) = chr;
154 } else if (_pw_likely(char_size == 3)) {
155 *ptr++ = (uint8_t) chr; chr >>= 8;
156 *ptr++ = (uint8_t) chr; chr >>= 8;
157 *ptr = (uint8_t) chr;
158 } else {
159 _pw_panic_bad_char_size(char_size);
160 }
161 return char_size;
162}
163
164
165/****************************************************************
166 * String iterator.
167 *
168 * The design is TBD
169 */
170
171PW_STRUCT(PwStringIter) {
172 uint8_t* start_ptr;
173 uint8_t* end_ptr;
174 uint8_t* current_ptr;
175 uint8_t char_size;
176};
177
178static inline void _pw_string_iter(PwValuePtr str, PwStringIter* iter)
179{
180 pw_hard_assert(pw_is_string(str));
181 iter->start_ptr = iter->current_ptr = _pw_string_start_end(str, &iter->end_ptr);
182 iter->char_size = str->str_params.char_size;
183}
184
185static inline char32_t _pw_string_iter_current(PwStringIter* iter)
186{
187 return _pw_get_char(iter->current_ptr, iter->char_size);
188}
189
190static inline bool _pw_string_iter_next(PwStringIter* iter, char32_t* c)
191{
192 if (iter->current_ptr < iter->end_ptr) {
193 *c =_pw_next_char(&iter->current_ptr, iter->char_size);
194 return true;
195 } else {
196 return false;
197 }
198}
199
200static inline bool _pw_string_iter_prev(PwStringIter* iter, char32_t* c)
201{
202 if (iter->current_ptr > iter->start_ptr) {
203 *c = _pw_prev_char(&iter->current_ptr, iter->char_size);
204 return true;
205 } else {
206 return false;
207 }
208}
209
210
211/****************************************************************
212 * Basic functions
213 */
214
215char32_t pw_char_at(PwValuePtr str, unsigned position);
216/*
217 * Return character at `position`.
218 * If position is beyond end of line return 0.
219 */
220
221// check if `index` is within string length
222#define pw_string_index_valid(str, index) ((index) < pw_strlen(str))
223
224static inline unsigned pw_strlen(PwValuePtr str)
225/*
226 * Return length of string.
227 */
228{
229 pw_hard_assert(pw_is_string(str));
230 if (str->str_params.integral) {
231 return str->integral_length;
232 } else {
233 return str->length;
234 }
235}
236
237[[nodiscard]] bool pw_substr(PwValuePtr str, unsigned start_pos, unsigned end_pos, PwValuePtr result);
238/*
239 * Get substring from `start_pos` to `end_pos`.
240 */
241
242[[nodiscard]] bool pw_string_erase(PwValuePtr str, unsigned start_pos, unsigned end_pos);
243/*
244 * Erase characters from `start_pos` to `end_pos`.
245 * This may make a copy of string, so checking return value is mandatory.
246 */
247
248[[nodiscard]] bool pw_string_truncate(PwValuePtr str, unsigned position);
249/*
250 * Truncate string at given `position`.
251 * This may make a copy of string, so checking return value is mandatory.
252 */
253
254[[ nodiscard]] bool pw_strchr(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result);
255/*
256 * Find first occurence of `chr` in `str` starting from `start_pos`.
257 *
258 * Return true if character is found and write its position to `result`.
259 * `result` can be nullptr if position is not needed and the function
260 * is called just to check if `chr` is in `str`.
261 */
262
263[[ nodiscard]] bool pw_strchr2(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result, uint8_t* max_char_size);
264/*
265 * Same as `pw_strchr`, but also return maximal char size.
266 */
267
268[[ nodiscard]] bool pw_strrchr(PwValuePtr str, char32_t chr, unsigned end_pos, unsigned* result);
269/*
270 * Find last occurence of `chr` in `str` starting from `end_pos`.
271 *
272 * For the first search `end_pos` should be UINT_MAX.
273 *
274 * Return true if character is found and write its position to `result`.
275 * `result` can be nullptr if position is not needed and the function
276 * is called just to check if `chr` is in `str`.
277 */
278
279[[ nodiscard]] bool pw_strrchr2(PwValuePtr str, char32_t chr, unsigned end_pos, unsigned* result, uint8_t* max_char_size);
280/*
281 * Same as `pw_strrchr`, but also return maximal char size.
282 */
283
284[[ nodiscard]] bool pw_strchri(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result);
285/*
286 * Find first case-insensitive occurence of `chr` in `str` starting from `start_pos`.
287 *
288 * Return true if character is found and write its position to `result`.
289 * `result` can be nullptr if position is not needed and the function
290 * is called just to check if `chr` is in `str`.
291 */
292
293[[nodiscard]] bool pw_string_lstrip(PwValuePtr str);
294[[nodiscard]] bool pw_string_rstrip(PwValuePtr str);
295[[nodiscard]] bool pw_string_strip(PwValuePtr str);
296
297[[nodiscard]] bool pw_string_lstrip_chars(PwValuePtr str, char32_t* chars);
298[[nodiscard]] bool pw_string_rstrip_chars(PwValuePtr str, char32_t* chars);
299[[nodiscard]] bool pw_string_strip_chars(PwValuePtr str, char32_t* chars);
300
301
302[[nodiscard]] bool pw_string_lower(PwValuePtr str);
303[[nodiscard]] bool pw_string_upper(PwValuePtr str);
304
305
306[[nodiscard]] bool pw_string_reverse(PwValuePtr str);
307
308
309#define pw_strcat(result, str, ...) \
310 _pw_strcat_va((result), (str) __VA_OPT__(,) __VA_ARGS__, PwVaEnd())
311
312[[nodiscard]] bool _pw_strcat_va(PwValuePtr result, ...);
313[[nodiscard]] bool _pw_strcat_ap(PwValuePtr result, va_list ap);
314
315unsigned pw_string_skip_spaces(PwValuePtr str, unsigned position);
316/*
317 * Find position of the first non-space character starting from `position`.
318 * If non-space character is not found, the length is returned.
319 */
320
321unsigned pw_string_skip_chars(PwValuePtr str, unsigned position, char32_t* skipchars);
322/*
323 * Find position of the first character not belonging to `skipchars` starting from `position`.
324 * If no `skipchars` encountered, the length is returned.
325 */
326
327bool pw_string_isspace(PwValuePtr str);
328bool pw_string_isdigit(PwValuePtr str);
329bool pw_string_is_ascii_digit(PwValuePtr str);
330/*
331 * Return true if `str` is not empty and contains all digits.
332 */
333
334/****************************************************************
335 * Append functions
336 *
337 * Characters, PwValues, and null-terminated C strings:
338 *
339 * pw_string_append(dest_string, chr);
340 * pw_string_append(dest_string, src_string);
341 *
342 * Raw data (char*, char8_t*, char32_t*):
343 *
344 * pw_string_append2(dest_string, start_ptr, end_ptr);
345 *
346 * C strings are slowest because strlen is called to obtain end_ptr.
347 */
348
349#define pw_string_append(dest, src, ...) _Generic((src), \
350 char: _pw_string_append_c32, \
351 uint8_t: _pw_string_append_c32, \
352 char32_t: _pw_string_append_c32, \
353 int: _pw_string_append_c32, \
354 char*: _pw_string_append1_ascii, \
355 char8_t*: _pw_string_append1_utf8, \
356 char32_t*: _pw_string_append1_utf32, \
357 PwValuePtr: _pw_string_append \
358 )((dest), (src) __VA_OPT__(,) __VA_ARGS__)
359
360[[nodiscard]] bool _pw_string_append_c32 (PwValuePtr dest, char32_t c);
361[[nodiscard]] bool _pw_string_append (PwValuePtr dest, PwValuePtr src);
362[[nodiscard]] bool _pw_string_append_ascii(PwValuePtr dest, char* start_ptr, char* end_ptr);
363[[nodiscard]] bool _pw_string_append_utf8 (PwValuePtr dest, char8_t* start_ptr, char8_t* end_ptr);
364[[nodiscard]] bool _pw_string_append_utf32(PwValuePtr dest, char32_t* start_ptr, char32_t* end_ptr);
365
366[[nodiscard]] static inline bool _pw_string_append1_ascii(PwValuePtr dest, char* start_ptr) { return _pw_string_append_ascii(dest, start_ptr, nullptr); }
367[[nodiscard]] static inline bool _pw_string_append1_utf8 (PwValuePtr dest, char8_t* start_ptr) { return _pw_string_append_utf8 (dest, start_ptr, nullptr); }
368[[nodiscard]] static inline bool _pw_string_append1_utf32(PwValuePtr dest, char32_t* start_ptr) { return _pw_string_append_utf32(dest, start_ptr, nullptr); }
369
370#define pw_string_append2(dest, src, ...) _Generic((src), \
371 char*: _pw_string_append_ascii, \
372 char8_t*: _pw_string_append_utf8, \
373 char32_t*: _pw_string_append_utf32 \
374 )((dest), (src) __VA_OPT__(,) __VA_ARGS__)
375
376
377/****************************************************************
378 * Insert functions
379 * TODO other types
380 */
381
382[[nodiscard]] bool pw_string_insert_chars(PwValuePtr str, unsigned position, char32_t chr, unsigned n);
383
384
385#define pw_string_insert(dest, position, src, ...) _Generic((src), \
386 char: _pw_string_insert_c32, \
387 uint8_t: _pw_string_insert_c32, \
388 char32_t: _pw_string_insert_c32, \
389 int: _pw_string_insert_c32, \
390 char*: _pw_string_insert1_ascii, \
391 char8_t*: _pw_string_insert1_utf8, \
392 char32_t*: _pw_string_insert1_utf32, \
393 PwValuePtr: _pw_string_insert \
394 )((dest), (position), (src) __VA_OPT__(,) __VA_ARGS__)
395
396[[nodiscard]] static inline bool _pw_string_insert_c32(PwValuePtr dest, unsigned position, char32_t c)
397{
398 return pw_string_insert_chars(dest, position, c, 1);
399}
400[[nodiscard]] bool _pw_string_insert (PwValuePtr dest, unsigned position, PwValuePtr src);
401[[nodiscard]] bool _pw_string_insert_ascii(PwValuePtr dest, unsigned position, char* start_ptr, char* end_ptr);
402[[nodiscard]] bool _pw_string_insert_utf8 (PwValuePtr dest, unsigned position, char8_t* start_ptr, char8_t* end_ptr);
403[[nodiscard]] bool _pw_string_insert_utf32(PwValuePtr dest, unsigned position, char32_t* start_ptr, char32_t* end_ptr);
404
405#define pw_string_insert2(dest, position, src, ...) _Generic((src), \
406 char*: _pw_string_insert_ascii, \
407 char8_t*: _pw_string_insert_utf8, \
408 char32_t*: _pw_string_insert_utf32 \
409 )((dest), (position), (src) __VA_OPT__(,) __VA_ARGS__)
410
411[[nodiscard]] static inline bool _pw_string_insert1_ascii(PwValuePtr dest, unsigned position, char* start_ptr) { return _pw_string_insert_ascii(dest, position, start_ptr, nullptr); }
412[[nodiscard]] static inline bool _pw_string_insert1_utf8 (PwValuePtr dest, unsigned position, char8_t* start_ptr) { return _pw_string_insert_utf8 (dest, position, start_ptr, nullptr); }
413[[nodiscard]] static inline bool _pw_string_insert1_utf32(PwValuePtr dest, unsigned position, char32_t* start_ptr) { return _pw_string_insert_utf32(dest, position, start_ptr, nullptr); }
414
415
416/****************************************************************
417 * Append substring.
418 *
419 * Append `src` substring starting from `src_start_pos` to `src_end_pos`.
420 */
421
422[[nodiscard]] bool pw_string_append_substring(PwValuePtr dest, PwValuePtr src, unsigned src_start_pos, unsigned src_end_pos);
423
424
425/****************************************************************
426 * String constructors
427 */
428
429[[nodiscard]] bool pw_create_empty_string(unsigned capacity, uint8_t char_size, PwValuePtr result);
430
431#define pw_create_string(result, initializer) _Generic((initializer), \
432 char*: _pw_create_string_ascii, \
433 char8_t*: _pw_create_string_utf8, \
434 char32_t*: _pw_create_string_utf32, \
435 PwValuePtr: _pw_create_string \
436 )((result), (initializer))
437
438#define CREATE_STR_IMPL \
439 { \
440 pw_destroy(result); \
441 *result = PwString(); \
442 return pw_string_append(result, initializer); \
443 }
444
445[[nodiscard]] static inline bool _pw_create_string (PwValuePtr result, PwValuePtr initializer) CREATE_STR_IMPL
446[[nodiscard]] static inline bool _pw_create_string_ascii(PwValuePtr result, char* initializer) CREATE_STR_IMPL
447[[nodiscard]] static inline bool _pw_create_string_utf8 (PwValuePtr result, char8_t* initializer) CREATE_STR_IMPL
448[[nodiscard]] static inline bool _pw_create_string_utf32(PwValuePtr result, char32_t* initializer) CREATE_STR_IMPL
449
450#undef CREATE_STR_IMPL
451
452/****************************************************************
453 * Case-insensitive comparison.
454 */
455
456#define pw_string_eqi(a, b) _Generic((b), \
457 char*: _pw_string_eqi_ascii, \
458 char8_t*: _pw_string_eqi_utf8, \
459 char32_t*: _pw_string_eqi_utf32, \
460 PwValuePtr: _pw_string_eqi \
461 )((a), (b))
462
463[[nodiscard]] bool _pw_string_eqi (PwValuePtr a, PwValuePtr b);
464[[nodiscard]] bool _pw_string_eqi_z(PwValuePtr a, void* b, uint8_t b_char_size);
465
466[[nodiscard]] static inline bool _pw_string_eqi_ascii(PwValuePtr a, char* b)
467{
468 return _pw_string_eqi_z(a, b, 1);
469}
470[[nodiscard]] static inline bool _pw_string_eqi_utf8 (PwValuePtr a, char8_t* b)
471{
472 return _pw_string_eqi_z(a, b, 0);
473}
474[[nodiscard]] static inline bool _pw_string_eqi_utf32(PwValuePtr a, char32_t* b)
475{
476 return _pw_string_eqi_z(a, b, 4);
477}
478
479/****************************************************************
480 * Substring comparison functions.
481 *
482 * Compare `str_a` from `start_pos` to `end_pos` with `str_b`.
483 */
484
485#define pw_substring_eq(a, start_pos, end_pos, b) _Generic((b), \
486 char*: _pw_substring_eq_ascii, \
487 char8_t*: _pw_substring_eq_utf8, \
488 char32_t*: _pw_substring_eq_utf32, \
489 PwValuePtr: _pw_substring_eq \
490 )((a), (start_pos), (end_pos), (b))
491
492[[nodiscard]] bool _pw_substring_eq (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
493[[nodiscard]] bool _pw_substring_eq_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
494
495[[nodiscard]] static inline bool _pw_substring_eq_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
496{
497 return _pw_substring_eq_z(a, start_pos, end_pos, b, 1);
498}
499[[nodiscard]] static inline bool _pw_substring_eq_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
500{
501 return _pw_substring_eq_z(a, start_pos, end_pos, b, 0);
502}
503[[nodiscard]] static inline bool _pw_substring_eq_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
504{
505 return _pw_substring_eq_z(a, start_pos, end_pos, b, 4);
506}
507
508
509#define pw_substring_eqi(a, start_pos, end_pos, b) _Generic((b), \
510 char*: _pw_substring_eqi_ascii, \
511 char8_t*: _pw_substring_eqi_utf8, \
512 char32_t*: _pw_substring_eqi_utf32, \
513 PwValuePtr: _pw_substring_eqi \
514 )((a), (start_pos), (end_pos), (b))
515
516[[nodiscard]] bool _pw_substring_eqi (PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b);
517[[nodiscard]] bool _pw_substring_eqi_z(PwValuePtr a, unsigned start_pos, unsigned end_pos, void* b, uint8_t b_char_size);
518
519[[nodiscard]] static inline bool _pw_substring_eqi_ascii(PwValuePtr a, unsigned start_pos, unsigned end_pos, char* b)
520{
521 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 1);
522}
523[[nodiscard]] static inline bool _pw_substring_eqi_utf8 (PwValuePtr a, unsigned start_pos, unsigned end_pos, char8_t* b)
524{
525 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 0);
526}
527[[nodiscard]] static inline bool _pw_substring_eqi_utf32(PwValuePtr a, unsigned start_pos, unsigned end_pos, char32_t* b)
528{
529 return _pw_substring_eqi_z(a, start_pos, end_pos, b, 4);
530}
531
532
533#define pw_startswith(str, prefix) _Generic((prefix), \
534 int: _pw_startswith_c32, \
535 char32_t: _pw_startswith_c32, \
536 char*: _pw_startswith_ascii, \
537 char8_t*: _pw_startswith_utf8, \
538 char32_t*: _pw_startswith_utf32, \
539 PwValuePtr: _pw_startswith \
540 )((str), (prefix))
541
542[[nodiscard]] bool _pw_startswith_c32(PwValuePtr str, char32_t prefix);
543[[nodiscard]] bool _pw_startswith (PwValuePtr str, PwValuePtr prefix);
544[[nodiscard]] bool _pw_startswith_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
545
546[[nodiscard]] static inline bool _pw_startswith_ascii(PwValuePtr str, char* prefix)
547{
548 return _pw_startswith_z(str, prefix, 1);
549}
550[[nodiscard]] static inline bool _pw_startswith_utf8(PwValuePtr str, char8_t* prefix)
551{
552 return _pw_startswith_z(str, prefix, 0);
553}
554[[nodiscard]] static inline bool _pw_startswith_utf32(PwValuePtr str, char32_t* prefix)
555{
556 return _pw_startswith_z(str, prefix, 4);
557}
558
559
560#define pw_startswithi(str, prefix) _Generic((prefix), \
561 int: _pw_startswithi_c32, \
562 char32_t: _pw_startswithi_c32, \
563 char*: _pw_startswithi_ascii, \
564 char8_t*: _pw_startswithi_utf8, \
565 char32_t*: _pw_startswithi_utf32, \
566 PwValuePtr: _pw_startswithi \
567 )((str), (prefix))
568
569[[nodiscard]] bool _pw_startswithi_c32(PwValuePtr str, char32_t prefix);
570[[nodiscard]] bool _pw_startswithi (PwValuePtr str, PwValuePtr prefix);
571[[nodiscard]] bool _pw_startswithi_z (PwValuePtr str, void* prefix, uint8_t prefix_char_size);
572
573[[nodiscard]] static inline bool _pw_startswithi_ascii(PwValuePtr str, char* prefix)
574{
575 return _pw_startswithi_z(str, prefix, 1);
576}
577[[nodiscard]] static inline bool _pw_startswithi_utf8(PwValuePtr str, char8_t* prefix)
578{
579 return _pw_startswithi_z(str, prefix, 0);
580}
581[[nodiscard]] static inline bool _pw_startswithi_utf32(PwValuePtr str, char32_t* prefix)
582{
583 return _pw_startswithi_z(str, prefix, 4);
584}
585
586
587#define pw_endswith(str, suffix) _Generic((suffix), \
588 int: _pw_endswith_c32, \
589 char32_t: _pw_endswith_c32, \
590 char*: _pw_endswith_ascii, \
591 char8_t*: _pw_endswith_utf8, \
592 char32_t*: _pw_endswith_utf32, \
593 PwValuePtr: _pw_endswith \
594 )((str), (suffix))
595
596[[nodiscard]] bool _pw_endswith_c32(PwValuePtr str, char32_t suffix);
597[[nodiscard]] bool _pw_endswith (PwValuePtr str, PwValuePtr suffix);
598[[nodiscard]] bool _pw_endswith_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
599
600[[nodiscard]] static inline bool _pw_endswith_ascii(PwValuePtr str, char* suffix)
601{
602 return _pw_endswith_z(str, suffix, 1);
603}
604[[nodiscard]] static inline bool _pw_endswith_utf8(PwValuePtr str, char8_t* suffix)
605{
606 return _pw_endswith_z(str, suffix, 0);
607}
608[[nodiscard]] static inline bool _pw_endswith_utf32(PwValuePtr str, char32_t* suffix)
609{
610 return _pw_endswith_z(str, suffix, 4);
611}
612
613
614#define pw_endswithi(str, suffix) _Generic((suffix), \
615 int: _pw_endswithi_c32, \
616 char32_t: _pw_endswithi_c32, \
617 char*: _pw_endswithi_ascii, \
618 char8_t*: _pw_endswithi_utf8, \
619 char32_t*: _pw_endswithi_utf32, \
620 PwValuePtr: _pw_endswithi \
621 )((str), (suffix))
622
623[[nodiscard]] bool _pw_endswithi_c32(PwValuePtr str, char32_t suffix);
624[[nodiscard]] bool _pw_endswithi (PwValuePtr str, PwValuePtr suffix);
625[[nodiscard]] bool _pw_endswithi_z (PwValuePtr str, void* suffix, uint8_t suffix_char_size);
626
627[[nodiscard]] static inline bool _pw_endswithi_ascii(PwValuePtr str, char* suffix)
628{
629 return _pw_endswithi_z(str, suffix, 1);
630}
631[[nodiscard]] static inline bool _pw_endswithi_utf8(PwValuePtr str, char8_t* suffix)
632{
633 return _pw_endswithi_z(str, suffix, 0);
634}
635[[nodiscard]] static inline bool _pw_endswithi_utf32(PwValuePtr str, char32_t* suffix)
636{
637 return _pw_endswithi_z(str, suffix, 4);
638}
639
640
641/****************************************************************
642 * Substring scanning functions.
643 *
644 * Return true if substring is found, false if not.
645 */
646
647#define pw_strstr(str, substr, start_pos, pos) _Generic((substr), \
648 char*: _pw_strstr_ascii, \
649 char8_t*: _pw_strstr_utf8, \
650 char32_t*: _pw_strstr_utf32, \
651 PwValuePtr: _pw_strstr \
652 )((str), (substr), (start_pos), (pos))
653
654[[nodiscard]] bool _pw_strstr(PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
655
656[[nodiscard]] bool _pw_strstr_z(PwValuePtr str, void* substr, uint8_t substr_char_size, unsigned start_pos, unsigned* pos);
657
658[[nodiscard]] static inline bool _pw_strstr_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos)
659{
660 return _pw_strstr_z(str, substr, 1, start_pos, pos);
661}
662[[nodiscard]] static inline bool _pw_strstr_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos)
663{
664 return _pw_strstr_z(str, substr, 0, start_pos, pos);
665}
666[[nodiscard]] static inline bool _pw_strstr_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos)
667{
668 return _pw_strstr_z(str, substr, 4, start_pos, pos);
669}
670
671#define pw_strstri(str, substr, pos) _Generic((substr), \
672 char*: _pw_strstri_ascii, \
673 char8_t*: _pw_strstri_utf8, \
674 char32_t*: _pw_strstri_utf32, \
675 PwValuePtr: _pw_strstri \
676 )((str), (substr), (start_pos), (pos))
677
678[[nodiscard]] bool _pw_strstri (PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos);
679[[nodiscard]] bool _pw_strstri_ascii(PwValuePtr str, char* substr, unsigned start_pos, unsigned* pos);
680[[nodiscard]] bool _pw_strstri_utf8 (PwValuePtr str, char8_t* substr, unsigned start_pos, unsigned* pos);
681[[nodiscard]] bool _pw_strstri_utf32(PwValuePtr str, char32_t* substr, unsigned start_pos, unsigned* pos);
682
683
684/****************************************************************
685 * Split functions.
686 * Return array of strings.
687 * maxsplit == 0 imposes no limit
688 */
689
690[[nodiscard]] bool _pw_string_split (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
691[[nodiscard]] bool _pw_string_split_chr (PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
692[[nodiscard]] bool _pw_string_rsplit (PwValuePtr str, /* split by spaces */ unsigned maxsplit, PwValuePtr result, uint16_t result_type);
693[[nodiscard]] bool _pw_string_rsplit_chr(PwValuePtr str, char32_t splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
694
695#define pw_string_split(...) _pw_string_split (__VA_ARGS__, PwTypeId_BasicArray)
696#define pw_string_split_chr(...) _pw_string_split_chr (__VA_ARGS__, PwTypeId_BasicArray)
697#define pw_string_rsplit(...) _pw_string_rsplit (__VA_ARGS__, PwTypeId_BasicArray)
698#define pw_string_rsplit_chr(...) _pw_string_rsplit_chr(__VA_ARGS__, PwTypeId_BasicArray)
699
700#define _pw_string_split_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
701 char*: _pw_string_split_any_ascii, \
702 char8_t*: _pw_string_split_any_utf8, \
703 char32_t*: _pw_string_split_any_utf32, \
704 PwValuePtr: _pw_string_split_any_pw \
705 )((str), (splitters), (maxsplit), (result_type))
706
707#define pw_string_split_any(...) _pw_string_split_any(__VA_ARGS__, PwTypeId_BasicArray)
708
709[[nodiscard]] bool _pw_string_split_any_pw (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
710[[nodiscard]] bool _pw_string_split_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
711[[nodiscard]] bool _pw_string_split_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
712[[nodiscard]] bool _pw_string_split_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
713
714#define _pw_string_rsplit_any(str, splitters, maxsplit, result_type) _Generic((splitters), \
715 char*: _pw_string_rsplit_any_ascii, \
716 char8_t*: _pw_string_rsplit_any_utf8, \
717 char32_t*: _pw_string_rsplit_any_utf32, \
718 PwValuePtr: _pw_string_rsplit_any_pw \
719 )((str), (splitters), (maxsplit), (result_type))
720
721#define pw_string_rsplit_any(...) _pw_string_rsplit_any(__VA_ARGS__, PwTypeId_BasicArray)
722
723[[nodiscard]] bool _pw_string_rsplit_any_pw (PwValuePtr str, PwValuePtr splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
724[[nodiscard]] bool _pw_string_rsplit_any_ascii(PwValuePtr str, char* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
725[[nodiscard]] bool _pw_string_rsplit_any_utf8 (PwValuePtr str, char8_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
726[[nodiscard]] bool _pw_string_rsplit_any_utf32(PwValuePtr str, char32_t* splitters, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
727
728#define _pw_string_split_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
729 char*: _pw_string_split_substr_ascii, \
730 char8_t*: _pw_string_split_substr_utf8, \
731 char32_t*: _pw_string_split_substr_utf32, \
732 PwValuePtr: _pw_string_split_substr_pw \
733 )((str), (splitter), (maxsplit), (result_type))
734
735#define pw_string_split_substr(...) _pw_string_split_substr(__VA_ARGS__, PwTypeId_BasicArray)
736
737[[nodiscard]] bool _pw_string_split_substr_pw (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
738[[nodiscard]] bool _pw_string_split_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
739[[nodiscard]] bool _pw_string_split_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
740[[nodiscard]] bool _pw_string_split_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
741
742#define _pw_string_split_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
743 char*: _pw_string_split_substri_ascii, \
744 char8_t*: _pw_string_split_substri_utf8, \
745 char32_t*: _pw_string_split_substri_utf32, \
746 PwValuePtr: _pw_string_split_substri_pw \
747 )((str), (splitter), (maxsplit), (result_type))
748
749#define pw_string_split_substri(...) _pw_string_split_substri(__VA_ARGS__, PwTypeId_BasicArray)
750
751[[nodiscard]] bool _pw_string_split_substri_pw (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
752[[nodiscard]] bool _pw_string_split_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
753[[nodiscard]] bool _pw_string_split_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
754[[nodiscard]] bool _pw_string_split_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
755
756#define _pw_string_rsplit_substr(str, splitter, maxsplit, result_type) _Generic((splitter), \
757 char*: _pw_string_rsplit_substr_ascii, \
758 char8_t*: _pw_string_rsplit_substr_utf8, \
759 char32_t*: _pw_string_rsplit_substr_utf32, \
760 PwValuePtr: _pw_string_rsplit_substr_pw \
761 )((str), (splitter), (maxsplit), (result_type))
762
763#define pw_string_rsplit_substr(...) _pw_string_rsplit_substr(__VA_ARGS__, PwTypeId_BasicArray)
764
765[[nodiscard]] bool _pw_string_rsplit_substr_pw (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
766[[nodiscard]] bool _pw_string_rsplit_substr_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
767[[nodiscard]] bool _pw_string_rsplit_substr_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
768[[nodiscard]] bool _pw_string_rsplit_substr_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
769
770#define _pw_string_rsplit_substri(str, splitter, maxsplit, result_type) _Generic((splitter), \
771 char*: _pw_string_rsplit_substri_ascii, \
772 char8_t*: _pw_string_rsplit_substri_utf8, \
773 char32_t*: _pw_string_rsplit_substri_utf32, \
774 PwValuePtr: _pw_string_rsplit_substri_pw \
775 )((str), (splitter), (maxsplit), (result_type))
776
777#define pw_string_rsplit_substri(...) _pw_string_rsplit_substri(__VA_ARGS__, PwTypeId_BasicArray)
778
779[[nodiscard]] bool _pw_string_rsplit_substri_pw (PwValuePtr str, PwValuePtr splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
780[[nodiscard]] bool _pw_string_rsplit_substri_ascii(PwValuePtr str, char* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
781[[nodiscard]] bool _pw_string_rsplit_substri_utf8 (PwValuePtr str, char8_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
782[[nodiscard]] bool _pw_string_rsplit_substri_utf32(PwValuePtr str, char32_t* splitter, unsigned maxsplit, PwValuePtr result, uint16_t result_type);
783
784
785/****************************************************************
786 * Replacement functions.
787 */
788
789#define pw_string_replace_all(str, substr, replacement) _Generic((substr), \
790 char32_t: _pw_string_replace_all_char32, \
791 char*: _pw_string_replace_all_ascii, \
792 char8_t*: _pw_string_replace_all_utf8, \
793 char32_t*: _pw_string_replace_all_utf32, \
794 PwValuePtr: _pw_string_replace_all \
795 )((str), (substr), (replacement))
796
797[[nodiscard]] bool _pw_string_replace_all(PwValuePtr str, PwValuePtr substr, PwValuePtr replacement);
798
799[[nodiscard]] static inline bool _pw_string_replace_all_char32(PwValuePtr str, char32_t substr, char32_t replacement)
800{
801 char32_t s[] = {substr, 0};
802 _PwValue sub = PwStaticStringUtf32(s);
803 char32_t r[] = {replacement, 0};
804 _PwValue repl = PwStaticStringUtf32(r);
805 return _pw_string_replace_all(str, &sub, &repl);
806}
807
808[[nodiscard]] static inline bool _pw_string_replace_all_ascii(PwValuePtr str, char* substr, char* replacement)
809{
810 _PwValue sub = PwStaticString(substr);
811 _PwValue repl = PwStaticString(replacement);
812 return _pw_string_replace_all(str, &sub, &repl);
813}
814
815[[nodiscard]] static inline bool _pw_string_replace_all_utf8(PwValuePtr str, char8_t* substr, char8_t* replacement)
816{
817 PwValue sub = PW_NULL;
818 if (!pw_create_string(&sub, substr)) {
819 return false;
820 }
821 PwValue repl = PW_NULL;
822 if (!pw_create_string(&repl, replacement)) {
823 return false;
824 }
825 return _pw_string_replace_all(str, &sub, &repl);
826}
827
828[[nodiscard]] static inline bool _pw_string_replace_all_utf32(PwValuePtr str, char32_t* substr, char32_t* replacement)
829{
830 _PwValue sub = PwStaticStringUtf32(substr);
831 _PwValue repl = PwStaticStringUtf32(replacement);
832 return _pw_string_replace_all(str, &sub, &repl);
833}
834
835
836/****************************************************************
837 * printf functions
838 */
839
840[[nodiscard]] bool pw_sprintf(PwValuePtr result, char* format, ...);
841[[nodiscard]] bool pw_vsprintf(PwValuePtr result, char* format, va_list ap);
842/*
843 * printf to String
844 */
845
846[[nodiscard]] bool pw_aprintf(PwValuePtr result, PwMethod_Append_append_string_data* meth_append, char* format, ...);
847[[nodiscard]] bool pw_vaprintf(PwValuePtr result, PwMethod_Append_append_string_data* meth_append, char* format, va_list ap);
848/*
849 * printf appending to the result
850 */
851
852
853/****************************************************************
854 * C strings
855 */
856
857// somewhat ugly macro to define a local variable initialized with a copy of pw string:
858#define PW_CSTRING(variable_name, pw_str) \
859 char variable_name[pw_strlen_in_utf8(pw_str) + 1]; \
860 pw_string_to_utf8((pw_str), variable_name)
861
862
863/****************************************************************
864 * Indentation utilities
865 */
866
867[[nodiscard]] bool pw_indent(PwValuePtr lines, unsigned n);
868[[nodiscard]] bool pw_indent_rstrip(PwValuePtr lines, unsigned n);
869/*
870 * `lines` can be either string or array.
871 * The function indents lines in-place.
872 *
873 * `pw_indent_rstrip` also strips trailing spaces from each line.
874 */
875
876[[nodiscard]] bool pw_dedent(PwValuePtr lines);
877/*
878 * `lines` can be either string or array.
879 * The function dedents lines in-place.
880 *
881 * XXX the function treats tabs as single spaces.
882 */
883
884
885/****************************************************************
886 * Miscellaneous
887 */
888
889[[nodiscard]] bool pw_string_capitalize(PwValuePtr str);
890/*
891 * Capitalize `str` in-place. Make first character upper case and all the rest lower case.
892 *
893 */
894
895#ifdef __cplusplus
896}
897#endif