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}