1#include "include/pw.h"
2#include "src/types/string/string_internal.h"
3
4bool _pw_strstr_z(PwValuePtr str, void* substr, uint8_t substr_char_size, unsigned start_pos, unsigned* pos)
5{
6 unsigned str_len = pw_strlen(str);
7 if (_pw_unlikely(start_pos >= str_len)) {
8 return false;
9 }
10 uint8_t str_char_size = str->char_size;
11 uint8_t* str_end_ptr;
12 uint8_t* str_start_ptr = _pw_string_start_end(str, &str_end_ptr);
13 str_start_ptr += start_pos * str_char_size;
14 str_len -= start_pos;
15
16 char32_t start_codepoint = _pw_get_char((uint8_t*) substr, substr_char_size);
17 if (_pw_unlikely(start_codepoint == 0 || start_codepoint >= (1ULL << (8 * str_char_size)))) {
18 return false;
19 }
20
21 StrChr fn_strchr = _pw_strchr_variants[str_char_size];
22 StrEqualZ fn_equalz = _pw_str_equalz_variants[str_char_size][substr_char_size];
23
24 for (uint8_t* str_ptr = str_start_ptr; str_start_ptr < str_end_ptr; ) {
25
26 uint8_t* maybe_substr = fn_strchr(str_ptr, str_end_ptr, start_codepoint);
27 if (!maybe_substr) {
28 break;
29 }
30 unsigned offset = (maybe_substr - str_start_ptr) / str_char_size;
31 if (fn_equalz(maybe_substr, str_len - offset, (uint8_t*) substr) != PW_NEQ) { // partial and full matches are ok
32 if (pos) {
33 *pos = start_pos + offset;
34 }
35 return true;
36 }
37 str_ptr = maybe_substr + str_char_size;
38 str_len--;
39 }
40 return false;
41}