1#include "include/pw.h"
2#include "include/pwlib/ctype.h"
3#include "src/types/string/string_internal.h"
4
5#define SUBSTREQI(STR_CHAR_TYPE, STR_CHAR_SIZE, SUBSTR_CHAR_TYPE, SUBSTR_CHAR_SIZE) \
6 static bool substreqi_##STR_CHAR_SIZE##_##SUBSTR_CHAR_SIZE(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr) \
7 { \
8 while (substr_start_ptr < substr_end_ptr) { \
9 if (pw_char_lower(*((STR_CHAR_TYPE*) str_start_ptr)) != pw_char_lower(*((SUBSTR_CHAR_TYPE*) substr_start_ptr))) { \
10 return false; \
11 } \
12 str_start_ptr += STR_CHAR_SIZE; \
13 substr_start_ptr += SUBSTR_CHAR_SIZE; \
14 } \
15 return true; \
16 }
17SUBSTREQI(uint8_t, 1, uint8_t, 1)
18SUBSTREQI(uint8_t, 1, uint16_t, 2)
19SUBSTREQI(uint8_t, 1, char32_t, 4)
20SUBSTREQI(uint16_t, 2, uint8_t, 1)
21SUBSTREQI(uint16_t, 2, uint16_t, 2)
22SUBSTREQI(uint16_t, 2, char32_t, 4)
23SUBSTREQI(char32_t, 4, uint8_t, 1)
24SUBSTREQI(char32_t, 4, uint16_t, 2)
25SUBSTREQI(char32_t, 4, char32_t, 4)
26
27#define SUBSTREQI_N_3(STR_CHAR_TYPE, STR_CHAR_SIZE) \
28 static bool substreqi_##STR_CHAR_SIZE##_3(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr) \
29 { \
30 while (substr_start_ptr < substr_end_ptr) { \
31 char32_t c = *substr_start_ptr++; \
32 c |= (*substr_start_ptr++) << 8; \
33 c |= (*substr_start_ptr++) << 16; \
34 if (pw_char_lower(*((STR_CHAR_TYPE*) str_start_ptr)) != pw_char_lower(c)) { \
35 return false; \
36 } \
37 str_start_ptr += STR_CHAR_SIZE; \
38 } \
39 return true; \
40 }
41SUBSTREQI_N_3(uint8_t, 1)
42SUBSTREQI_N_3(uint16_t, 2)
43SUBSTREQI_N_3(char32_t, 4)
44
45#define SUBSTREQI_3_N(SUBSTR_CHAR_TYPE, SUBSTR_CHAR_SIZE) \
46 static bool substreqi_3_##SUBSTR_CHAR_SIZE(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr) \
47 { \
48 while (substr_start_ptr < substr_end_ptr) { \
49 char32_t c = *str_start_ptr++; \
50 c |= (*str_start_ptr++) << 8; \
51 c |= (*str_start_ptr++) << 16; \
52 if (pw_char_lower(c) != pw_char_lower(*((SUBSTR_CHAR_TYPE*) substr_start_ptr))) { \
53 return false; \
54 } \
55 substr_start_ptr += SUBSTR_CHAR_SIZE; \
56 } \
57 return true; \
58 }
59SUBSTREQI_3_N(uint8_t, 1)
60SUBSTREQI_3_N(uint16_t, 2)
61SUBSTREQI_3_N(char32_t, 4)
62
63static bool substreqi_3_3(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
64{
65 while (substr_start_ptr < substr_end_ptr) {
66 char32_t c1 = *str_start_ptr++;
67 c1 |= (*str_start_ptr++) << 8;
68 c1 |= (*str_start_ptr++) << 16;
69 char32_t c2 = *substr_start_ptr++; \
70 c2 |= (*substr_start_ptr++) << 8; \
71 c2 |= (*substr_start_ptr++) << 16; \
72 if (pw_char_lower(c1) != pw_char_lower(c2)) {
73 return false;
74 }
75 }
76 return true;
77}
78
79// Comparison with UTF-8 string.
80
81#define SUBSTREQ_UTF8(CHAR_TYPE, CHAR_SIZE) \
82 static bool substreqi_##CHAR_SIZE##_0(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr) \
83 { \
84 while(substr_start_ptr < substr_end_ptr) { \
85 char32_t c = _pw_decode_utf8_char(&substr_start_ptr); \
86 if (pw_char_lower(c) != pw_char_lower(*((CHAR_TYPE*) str_start_ptr))) { \
87 return false; \
88 } \
89 str_start_ptr += CHAR_SIZE; \
90 } \
91 return true; \
92 }
93SUBSTREQ_UTF8(uint8_t, 1)
94SUBSTREQ_UTF8(uint16_t, 2)
95SUBSTREQ_UTF8(char32_t, 4)
96
97static bool substreqi_3_0(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
98{
99 while(substr_start_ptr < substr_end_ptr) {
100 char32_t c1 = _pw_decode_utf8_char(&substr_start_ptr);
101 char32_t c2 = *str_start_ptr++;
102 c2 |= (*str_start_ptr++) << 8;
103 c2 |= (*str_start_ptr++) << 16;
104 if (pw_char_lower(c1) != pw_char_lower(c2)) {
105 return false;
106 }
107 }
108 return true;
109}
110
111
112SubstrEq _pw_substreqi_variants[5][5] = {
113 {
114 nullptr,
115 nullptr,
116 nullptr,
117 nullptr,
118 nullptr
119 },
120 {
121 substreqi_1_0,
122 substreqi_1_1,
123 substreqi_1_2,
124 substreqi_1_3,
125 substreqi_1_4
126 },
127 {
128 substreqi_2_0,
129 substreqi_2_1,
130 substreqi_2_2,
131 substreqi_2_3,
132 substreqi_2_4
133 },
134 {
135 substreqi_3_0,
136 substreqi_3_1,
137 substreqi_3_2,
138 substreqi_3_3,
139 substreqi_3_4
140 },
141 {
142 substreqi_4_0,
143 substreqi_4_1,
144 substreqi_4_2,
145 substreqi_4_3,
146 substreqi_4_4
147 }
148};
149
150
151/****************************************************************
152 * High-level functions
153 */
154
155[[nodiscard]] bool _pw_substring_eqi(PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b)
156{
157 pw_assert(pw_is_string(a));
158 unsigned a_length;
159 uint8_t* a_ptr = _pw_string_start_length(a, &a_length);
160
161 if (_pw_unlikely(end_pos > a_length)) {
162 end_pos = a_length;
163 }
164 if (_pw_unlikely(end_pos < start_pos)) {
165 return false;
166 }
167 unsigned substr_length = end_pos - start_pos;
168 unsigned b_length = pw_strlen(b);
169 if (_pw_unlikely(substr_length != b_length)) {
170 return false;
171 }
172 if (_pw_unlikely(substr_length == 0)) {
173 return true;
174 }
175 uint8_t* b_end_ptr;
176 uint8_t* b_start_ptr = _pw_string_start_end(b, &b_end_ptr);
177 SubstrEq fn_substreqi = _pw_substreqi_variants[a->str_params.char_size][b->str_params.char_size];
178 return fn_substreqi(a_ptr + start_pos * a->str_params.char_size, b_start_ptr, b_end_ptr);
179}
180
181[[nodiscard]] bool _pw_startswithi_c32(PwValuePtr str, char32_t prefix)
182{
183 pw_assert(pw_is_string(str));
184 unsigned length = pw_strlen(str);
185 if (_pw_unlikely(length == 0)) {
186 return false;
187 }
188 return pw_char_lower(_pw_get_char(_pw_string_start(str), str->str_params.char_size)) == pw_char_lower(prefix);
189}
190
191[[nodiscard]] bool _pw_startswithi(PwValuePtr str, PwValuePtr prefix)
192{
193 return _pw_substring_eqi(str, 0, pw_strlen(prefix), prefix);
194}
195
196[[nodiscard]] bool _pw_endswithi_c32(PwValuePtr str, char32_t prefix)
197{
198 pw_assert(pw_is_string(str));
199 unsigned length;
200 uint8_t* ptr = _pw_string_start_length(str, &length);
201 if (_pw_unlikely(length == 0)) {
202 return false;
203 }
204 uint8_t char_size = str->str_params.char_size;
205 return pw_char_lower(prefix) == pw_char_lower(_pw_get_char(ptr + (length - 1) * char_size, char_size));
206}
207
208[[nodiscard]] bool _pw_endswithi(PwValuePtr str, PwValuePtr suffix)
209{
210 unsigned str_len = pw_strlen(str);
211 unsigned suffix_len = pw_strlen(suffix);
212 if (_pw_unlikely(str_len < suffix_len)) {
213 return false;
214 }
215 return _pw_substring_eqi(str, str_len - suffix_len, str_len, suffix);
216}