GCC Code Coverage Report


Directory: src/gate/
File: src/gate/regexpressions.c
Date: 2026-10-19 17:06:30
Exec Total Coverage
Lines: 177 220 80.5%
Functions: 16 18 88.9%
Branches: 129 209 61.7%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/regexpressions.h"
30 #include "gate/results.h"
31
32 /*
33 This is a GATE framework port of
34 kokke's public domain code 'tiny-regex-c'
35 which is based on Rob-Pike's regex-code.
36 */
37
38 /* Private functions: */
39 7 static gate_bool_t match_digit(char c)
40 {
41
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
7 return ((c >= '0') && (c <= '9'));
42 }
43 3 static gate_bool_t match_alpha(char c)
44 {
45
4/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
46 }
47 3 static gate_bool_t match_whitespace(char c)
48 {
49
7/12
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
3 return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\f') || (c == '\v'));
50 }
51 3 static gate_bool_t match_alphanum(char c)
52 {
53
4/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
3 return ((c == '_') || match_alpha(c) || match_digit(c));
54 }
55 108 static gate_bool_t match_range(char c, const char* str)
56 {
57
4/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 23 times.
108 return ((c != '-') && (str[0] != '\0') && (str[0] != '-')
58
3/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
62 && (str[1] == '-') && (str[2] != '\0')
59
5/6
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 14 times.
216 && ((c >= str[0]) && (c <= str[2])));
60 }
61 ✗ static gate_bool_t is_meta_char(char c)
62 {
63 ✗ return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D'));
64 }
65
66 ✗ static gate_bool_t match_meta_char(char c, const char* str)
67 {
68 ✗ switch (str[0])
69 {
70 ✗ case 'd': return match_digit(c);
71 ✗ case 'D': return !match_digit(c);
72 ✗ case 'w': return match_alphanum(c);
73 ✗ case 'W': return !match_alphanum(c);
74 ✗ case 's': return match_whitespace(c);
75 ✗ case 'S': return !match_whitespace(c);
76 ✗ default: return (c == str[0]);
77 }
78 }
79
80 108 static gate_bool_t match_char_class(char c, const char* str)
81 {
82 do
83 {
84
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 92 times.
108 if (match_range(c, str))
85 {
86 16 return true;
87 }
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 else if (str[0] == '\\')
89 {
90 /* Escape-char: increment str-ptr and match on next char */
91 ✗ str += 1;
92 ✗ if (match_meta_char(c, str))
93 {
94 ✗ return true;
95 }
96 ✗ else if ((c == str[0]) && !is_meta_char(c))
97 {
98 ✗ return true;
99 }
100 }
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 else if (c == str[0])
102 {
103 ✗ if (c == '-')
104 {
105 ✗ return ((str[-1] == '\0') || (str[1] == '\0'));
106 }
107 else
108 {
109 ✗ return true;
110 }
111 }
112
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
92 } while (*str++ != '\0');
113
114 23 return false;
115 }
116
117 147 static gate_bool_t match_one(gate_regex_token_t token, char c)
118 {
119
9/10
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 91 times.
147 switch (token.type)
120 {
121 6 case GATE_REGEX_DOT: return true;
122 39 case GATE_REGEX_CHAR_CLASS: return match_char_class(c, (const char*)token.content.ptr);
123 ✗ case GATE_REGEX_INV_CHAR_CLASS: return !match_char_class(c, (const char*)token.content.ptr);
124 4 case GATE_REGEX_DIGIT: return match_digit(c);
125 1 case GATE_REGEX_NOT_DIGIT: return !match_digit(c);
126 2 case GATE_REGEX_ALPHA: return match_alphanum(c);
127 1 case GATE_REGEX_NOT_ALPHA: return !match_alphanum(c);
128 1 case GATE_REGEX_WHITESPACE: return match_whitespace(c);
129 2 case GATE_REGEX_NOT_WHITESPACE: return !match_whitespace(c);
130 91 default: return (token.content.chr == c);
131 }
132 }
133
134 static gate_bool_t match_pattern(gate_regex_token_t* pattern, const char* text, gate_size_t textlen, int* match_length);
135
136 2 static gate_bool_t match_star(gate_regex_token_t token, gate_regex_token_t* pattern, const char* text, gate_size_t textlen, int* match_length)
137 {
138 2 int prelen = *match_length;
139 2 int textpos = 0;
140
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1 times.
9 while ((textpos < (int)textlen) && match_one(token, text[textpos]))
141 {
142 7 ++textpos;
143 7 ++(*match_length);
144 }
145
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 while (textpos >= 0)
146 {
147
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
3 if (match_pattern(pattern, &text[textpos], textlen - textpos, match_length))
148 {
149 2 return true;
150 }
151 1 --textpos;
152 1 --(*match_length);
153 }
154
155 ✗ *match_length = prelen;
156 ✗ return false;
157 }
158
159 9 static gate_bool_t match_plus(gate_regex_token_t token, gate_regex_token_t* pattern, const char* text, gate_size_t textlen, int* match_length)
160 {
161 9 gate_size_t textpos = 0;
162
163
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 8 times.
24 while ((textpos < textlen) && match_one(token, text[textpos]))
164 {
165 15 ++textpos;
166 15 ++(*match_length);
167 }
168
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
15 while (textpos > 0)
169 {
170
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 6 times.
11 if (match_pattern(pattern, &text[textpos], textlen - textpos, match_length))
171 {
172 5 return true;
173 }
174 6 --textpos;
175 6 --(*match_length);
176 }
177 4 return false;
178 }
179
180 17 static gate_bool_t match_question(gate_regex_token_t token, gate_regex_token_t* pattern, const char* text, gate_size_t textlen, int* match_length)
181 {
182
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (token.type == GATE_REGEX_UNUSED)
183 {
184 16 return true;
185 }
186
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (match_pattern(pattern, text, textlen, match_length))
187 {
188 1 return true;
189 }
190 ✗ if ((textlen != 0) && match_one(token, text[0]))
191 {
192 ✗ if (match_pattern(pattern, &text[1], textlen - 1, match_length))
193 {
194 ✗ ++(*match_length);
195 ✗ return true;
196 }
197 }
198 ✗ return false;
199 }
200
201
202 108 static gate_bool_t match_pattern(gate_regex_token_t* pattern, const char* text, gate_size_t textlen, int* match_length)
203 {
204 108 int pre = *match_length;
205
206 108 gate_size_t pattern_index = 0;
207 108 gate_size_t textpos = 0;
208 do
209 {
210
4/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 136 times.
153 if ((pattern[pattern_index].type == GATE_REGEX_UNUSED) || (pattern[pattern_index].type == GATE_REGEX_QUESTIONMARK))
211 {
212 17 return match_question(pattern[pattern_index], &pattern[pattern_index + 2], &text[textpos], textlen - textpos, match_length);
213 }
214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 134 times.
136 else if (pattern[pattern_index + 1].type == GATE_REGEX_STAR)
215 {
216 2 return match_star(pattern[pattern_index + 0], &pattern[pattern_index + 2], &text[textpos], textlen - textpos, match_length);
217 }
218
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 125 times.
134 else if (pattern[pattern_index + 1].type == GATE_REGEX_PLUS)
219 {
220 9 return match_plus(pattern[pattern_index + 0], &pattern[pattern_index + 2], &text[textpos], textlen - textpos, match_length);
221 }
222
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
125 else if ((pattern[pattern_index + 0].type == GATE_REGEX_END) && pattern[pattern_index + 1].type == GATE_REGEX_UNUSED)
223 {
224 5 return (textpos >= textlen);
225 }
226 120 ++(*match_length);
227
4/4
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 71 times.
120 } while ((textpos < textlen) && match_one(pattern[pattern_index++], text[textpos++]));
228
229 75 *match_length = pre;
230 75 return false;
231 }
232
233
234 25 gate_result_t gate_regex_init(gate_regex_t regex, gate_string_t const* pattern)
235 {
236 25 gate_result_t result = GATE_RESULT_OK;
237
238 do
239 {
240 25 gate_index_t buffer_index = 1; /* int ccl_bufidx = 1; */
241 25 gate_index_t pattern_index = 0; /* int i = 0; // index into pattern */
242 25 gate_index_t compiled_index = 0; /* int j = 0; // index into re_compiled */
243
244 char const* ptr_pattern;
245 gate_size_t pattern_length;
246 gate_regex_token_t* ptr_compiled;
247 unsigned char* ptr_buffer;
248
249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (regex == NULL)
250 {
251 ✗ result = GATE_RESULT_INVALIDARG;
252 ✗ break;
253 }
254 25 gate_mem_clear(regex, sizeof(struct gate_regex_class));
255
256 25 ptr_pattern = &regex->pattern[0];
257 25 pattern_length = gate_string_to_buffer(pattern, regex->pattern, sizeof(regex->pattern));
258
259 25 ptr_compiled = &regex->compiled[0];
260 25 ptr_buffer = &regex->buffer[0];
261
262
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
105 while ((result == GATE_RESULT_OK)
263
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 25 times.
105 && (pattern_index < (gate_index_t)pattern_length)
264
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 && (compiled_index + 1 < GATE_REGEX_MAX_COMPILED))
265 {
266 80 char current_char = ptr_pattern[pattern_index];
267
268
9/9
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 43 times.
80 switch (current_char)
269 {
270 /* Meta-characters: */
271 6 case '^': { ptr_compiled[compiled_index].type = GATE_REGEX_BEGIN; break; }
272 6 case '$': { ptr_compiled[compiled_index].type = GATE_REGEX_END; break; }
273 1 case '.': { ptr_compiled[compiled_index].type = GATE_REGEX_DOT; break; }
274 2 case '*': { ptr_compiled[compiled_index].type = GATE_REGEX_STAR; break; }
275 5 case '+': { ptr_compiled[compiled_index].type = GATE_REGEX_PLUS; break; }
276 1 case '?': { ptr_compiled[compiled_index].type = GATE_REGEX_QUESTIONMARK;break; }
277 /*case '|': { ptr_compiled[compiled_index].type = GATE_REGEX_BRANCH; break; } <-- not working properly */
278 /* Escaped character-classes (\s \w ...): */
279 9 case '\\':
280 {
281
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (pattern_index + 1 < (gate_index_t)pattern_length)
282 {
283 /* Skip the escape-char '\\' */
284 9 ++pattern_index;
285 /* ... and check the next */
286 9 current_char = ptr_pattern[pattern_index];
287
7/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 3 times.
9 switch (current_char)
288 {
289 /* Meta-character: */
290 1 case 'd': { ptr_compiled[compiled_index].type = GATE_REGEX_DIGIT; break; }
291 1 case 'D': { ptr_compiled[compiled_index].type = GATE_REGEX_NOT_DIGIT; break; }
292 1 case 'w': { ptr_compiled[compiled_index].type = GATE_REGEX_ALPHA; break; }
293 1 case 'W': { ptr_compiled[compiled_index].type = GATE_REGEX_NOT_ALPHA; break; }
294 1 case 's': { ptr_compiled[compiled_index].type = GATE_REGEX_WHITESPACE; break; }
295 1 case 'S': { ptr_compiled[compiled_index].type = GATE_REGEX_NOT_WHITESPACE; break; }
296 /* Escaped character, e.g. '.' or '$' */
297 3 default:
298 {
299 3 ptr_compiled[compiled_index].type = GATE_REGEX_CHAR;
300 3 ptr_compiled[compiled_index].content.chr = current_char;
301 3 break;
302 }
303 }
304 }
305 else
306 {
307 ✗ result = GATE_RESULT_INVALIDINPUT;
308 }
309 9 break;
310 }
311
312 /* Character class: */
313 7 case '[':
314 {
315
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (pattern_index + 1 < (gate_index_t)pattern_length)
316 {
317 /* Remember where the char-buffer starts. */
318 7 gate_index_t buffer_begin = buffer_index;
319
320 /* Look-ahead to determine if negated */
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ptr_pattern[pattern_index + 1] == '^')
322 {
323 ✗ ptr_compiled[compiled_index].type = GATE_REGEX_INV_CHAR_CLASS;
324 ✗ ++pattern_index; /* Increment i to avoid including '^' in the char-buffer */
325 }
326 else
327 {
328 7 ptr_compiled[compiled_index].type = GATE_REGEX_CHAR_CLASS;
329 }
330
331 /* Copy characters inside [..] to buffer */
332
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 while (pattern_index + 1 < (gate_index_t)pattern_length)
333 {
334 28 ++pattern_index;
335 28 current_char = ptr_pattern[pattern_index];
336
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 21 times.
28 if (current_char == ']')
337 {
338 /* end of character class reached*/
339 7 break;
340 }
341
342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (current_char == '\\')
343 {
344 ✗ if (buffer_index >= GATE_REGEX_MAX_CHAR_CLASS_LEN - 1)
345 {
346 ✗ result = GATE_RESULT_OUTOFBOUNDS;
347 ✗ break;
348 }
349
350 ✗ ptr_buffer[buffer_index++] = ptr_pattern[pattern_index++];
351 }
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 else if (buffer_index >= GATE_REGEX_MAX_CHAR_CLASS_LEN)
353 {
354 ✗ result = GATE_RESULT_OUTOFBOUNDS;
355 ✗ break;
356 }
357 21 ptr_buffer[buffer_index++] = ptr_pattern[pattern_index];
358 }
359
360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (buffer_index >= GATE_REGEX_MAX_CHAR_CLASS_LEN)
361 {
362 /* Catches cases such as [00000000000000000000000000000000000000][ */
363 //fputs("exceeded internal buffer!\n", stderr);
364 ✗ result = GATE_RESULT_OUTOFBOUNDS;
365 ✗ break;
366 }
367 /* Null-terminate string end */
368 7 ptr_buffer[buffer_index++] = 0;
369 7 ptr_compiled[compiled_index].content.ptr = &ptr_buffer[buffer_begin];
370 }
371 else
372 {
373 ✗ result = GATE_RESULT_INVALIDINPUT;
374 }
375 7 break;
376 }
377
378 /* Other characters: */
379 43 default:
380 {
381 43 ptr_compiled[compiled_index].type = GATE_REGEX_CHAR;
382 43 ptr_compiled[compiled_index].content.chr = current_char;
383 43 break;
384 }
385 }
386
387 80 ++pattern_index;
388 80 ++compiled_index;
389 }
390
391 // finally completed
392 } while (0);
393
394 25 return result;
395 }
396
397
398 24 gate_result_t gate_regex_create(gate_regex_t* new_regex, gate_string_t const* pattern)
399 {
400 gate_result_t result;
401 24 gate_regex_t regex = (gate_regex_t)gate_mem_alloc(sizeof(struct gate_regex_class));
402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (NULL == regex)
403 {
404 ✗ return GATE_RESULT_OUTOFMEMORY;
405 }
406 24 result = gate_regex_init(regex, pattern);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (GATE_FAILED(result))
408 {
409 ✗ gate_mem_dealloc(regex);
410 }
411 else
412 {
413 24 *new_regex = regex;
414 }
415
416 24 return result;
417 }
418
419 2 gate_result_t gate_regex_clone(gate_regex_t* new_regex, gate_regex_t source)
420 {
421 2 gate_result_t result = GATE_RESULT_INVALIDARG;
422
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if ((source != NULL) && (new_regex != NULL))
423 {
424 gate_string_t pattern;
425 2 gate_string_create_static(&pattern, source->pattern);
426 2 result = gate_regex_create(new_regex, &pattern);
427 }
428 2 return result;
429 }
430
431 27 gate_result_t gate_regex_match(gate_regex_t regex, gate_string_t const* text, gate_size_t* ptr_match_pos, gate_size_t* ptr_match_length)
432 {
433 27 gate_result_t ret = GATE_RESULT_NOMATCH;
434
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 if ((regex != NULL) && (text != NULL))
435 {
436 27 int match_length = 0;
437 27 gate_size_t text_length = gate_string_length(text);
438
439
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 19 times.
27 if (regex->compiled[0].type == GATE_REGEX_BEGIN)
440 {
441
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5 times.
8 if (match_pattern(&regex->compiled[1], gate_string_ptr(text, 0), text_length, &match_length))
442 {
443
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_match_pos)
444 {
445 3 *ptr_match_pos = 0;
446 }
447
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_match_length)
448 {
449 3 *ptr_match_length = (gate_size_t)match_length;
450 }
451 3 ret = GATE_RESULT_OK;
452 }
453 }
454 else
455 {
456 19 int index = -1;
457 19 gate_size_t text_pos = 0;
458 do
459 {
460 85 ++index;
461
2/2
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 69 times.
85 if (match_pattern(&regex->compiled[0], gate_string_ptr(text, text_pos), text_length - text_pos, &match_length))
462 {
463
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (text_pos < text_length)
464 {
465
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (ptr_match_pos)
466 {
467 16 *ptr_match_pos = (gate_size_t)index;
468 }
469
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (ptr_match_length)
470 {
471 16 *ptr_match_length = (gate_size_t)match_length;
472 }
473 16 ret = GATE_RESULT_OK;
474 }
475 16 break;
476 }
477
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 3 times.
69 } while (text_pos++ < text->length);
478 }
479 }
480 27 return ret;
481 }
482
483 24 void gate_regex_release(gate_regex_t regex)
484 {
485
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (regex != NULL)
486 {
487 24 gate_mem_dealloc(regex);
488 }
489 24 }
490