diff options
| author | Tyge Løvset <[email protected]> | 2022-01-09 23:03:20 +0100 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2022-01-09 23:10:48 +0100 |
| commit | 4925e503aa2234a3ad804256713276199d58dd0d (patch) | |
| tree | 786ff3fa691e35d652b5a80f03024e1837d590f4 | |
| parent | 7838ca9236fa019fc7018f3a6a78972b1872468b (diff) | |
| download | STC-modified-4925e503aa2234a3ad804256713276199d58dd0d.tar.gz STC-modified-4925e503aa2234a3ad804256713276199d58dd0d.zip | |
Probably stable API for cregex.h
| -rw-r--r-- | examples/regex_match.c | 4 | ||||
| -rw-r--r-- | include/stc/cregex.h | 52 | ||||
| -rw-r--r-- | tests/cregex_test.c | 367 |
3 files changed, 397 insertions, 26 deletions
diff --git a/examples/regex_match.c b/examples/regex_match.c index 887f4ddf..dca8a127 100644 --- a/examples/regex_match.c +++ b/examples/regex_match.c @@ -17,14 +17,14 @@ int main() {
re = cregex_new("[+-]?([0-9]*\\.)?[0-9]+([Ee][-+]?[0-9]+)?");
cregex_match match;
- if (cregex_find(re, s, &match)) {
+ if (cregex_find(&re, s, &match)) {
printf("Found digits at position %zu-%zu\n", match.start, match.end);
} else {
printf("Could not find any digits\n");
}
csview sv = {s, 0};
- while (cregex_find_next_v(re, s, &sv)) {
+ while (cregex_find_next_v(&re, s, &sv)) {
printf(c_PRIsv " ; ", c_ARGsv(sv));
}
puts("");
diff --git a/include/stc/cregex.h b/include/stc/cregex.h index fb9b4010..82e9a60c 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -33,6 +33,7 @@ typedef struct { union cregex_node *nodes; + const char* input; } cregex; typedef struct { @@ -63,30 +64,34 @@ STC_API cregex cregex_new(const char *re); STC_API cregex_error_t cregex_error(void); /* check if input s matches re */ -STC_API bool cregex_is_match(cregex rx, const char *s); +STC_API bool cregex_is_match(cregex *rx, const char *s); /* find the next matching substring in s */ -STC_API bool cregex_find_next(cregex rx, const char *s, cregex_match *m); -STC_API bool cregex_find_next_v(cregex rx, const char *s, csview *sv); +STC_API bool cregex_find_next(cregex *rx, const char *s, cregex_match *m); + +/* find the next matching substring in s, return as csview */ +STC_API bool cregex_find_next_v(cregex *rx, const char *s, csview *sv); /* find the first matching substring in s */ -STC_INLINE bool cregex_find(cregex rx, const char *s, cregex_match *m) { +STC_INLINE bool cregex_find(cregex *rx, const char *s, cregex_match *m) { m->start = m->end = 0; return cregex_find_next(rx, s, m); } -STC_INLINE bool cregex_find_v(cregex rx, const char *s, csview *sv) { +STC_INLINE bool cregex_find_v(cregex *rx, const char *s, csview *sv) { sv->str = s, sv->size = 0; return cregex_find_next_v(rx, s, sv); } /* get captured slice from capture group number index */ -STC_API cregex_match cregex_capture(cregex rx, size_t index); +STC_API bool cregex_capture(cregex rx, size_t index, cregex_match *m); /* get captured slice from capture group number index as a csview */ -STC_INLINE csview cregex_capture_v(cregex rx, const char* s, size_t index) { - cregex_match cap = cregex_capture(rx, index); - return c_make(csview){s + cap.start, cap.end - cap.start}; +STC_INLINE bool cregex_capture_v(cregex rx, size_t index, csview *sv) { + cregex_match m; + bool ret = cregex_capture(rx, index, &m); + *sv = c_make(csview){rx.input + m.start, m.end - m.start}; + return ret; } /* get amount of capture groups inside of @@ -872,31 +877,31 @@ STC_DEF cregex_error_t cregex_error(void) return _rx_CompileException.err; } -STC_DEF bool cregex_is_match(cregex rx, const char *s) +STC_DEF bool cregex_is_match(cregex* rx, const char *s) { - bool res = _rx_is_match(rx.nodes, s, s, &s); + rx->input = s; + bool res = _rx_is_match(rx->nodes, s, s, &s); return res && *s == 0; } -STC_DEF bool cregex_find_next(cregex rx, const char *s, cregex_match *m) +STC_DEF bool cregex_find_next(cregex *rx, const char *s, cregex_match *m) { - const char *it = s + m->end, *end = it, *next; + const char *it = s + m->end, *next; + rx->input = s; - for (; *it; end = it, it = utf8_next(it)) { - if (_rx_is_match(rx.nodes, s, it, &next)) { + for (; *it; it = utf8_next(it)) { + if (_rx_is_match(rx->nodes, s, it, &next)) { m->start = it - s; m->end = next - s; return true; } } - m->start = m->end = end - s; return false; } -STC_API bool cregex_find_next_v(cregex rx, const char *s, csview *sv) +STC_API bool cregex_find_next_v(cregex *rx, const char *s, csview *sv) { - cregex_match m; - m.start = sv->str - s, m.end = m.start + sv->size; + cregex_match m = { (size_t)(sv->str - s), m.start + sv->size }; bool res = cregex_find_next(rx, s, &m); *sv = c_make(csview){s + m.start, m.end - m.start}; @@ -961,15 +966,14 @@ static cregex_node *_rx_find_capture_node(cregex_node *node, size_t index) } } -STC_DEF cregex_match cregex_capture(cregex rx, size_t index) +STC_DEF bool cregex_capture(cregex rx, size_t index, cregex_match *m) { _rx_CapNode *cap = (_rx_CapNode *)_rx_find_capture_node(rx.nodes, index); - if (cap == NULL) { - return c_make(cregex_match){0, 0}; - } + if (!cap) return false; - return cap->cap; + *m = cap->cap; + return true; } #endif diff --git a/tests/cregex_test.c b/tests/cregex_test.c new file mode 100644 index 00000000..54973ee2 --- /dev/null +++ b/tests/cregex_test.c @@ -0,0 +1,367 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +//#include <check.h> +#include <stc/cregex.h> + +#define START_TEST(f) void f(void) +#define END_TEST + +#define ck_assert(x) assert(x) +#define ck_assert_uint_ne(a, b) assert(a != b) +#define ck_assert_uint_eq(a, b) if (!((a) == (b))) printf("%u == %u: ", a, b), assert((a) == (b)) +#define ck_assert_int_ne(a, b) assert(a != b) +#define ck_assert_int_eq(a, b) assert(a == b) +#define ck_assert_ptr_ne(a, b) assert(a != b) +#define ck_assert_ptr_eq(a, b) assert(a == b) + + +START_TEST(compile_match_char) +{ + cregex re = cregex_new("äsdf"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "äsdf", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 5); // ä is two bytes wide + + ck_assert(cregex_find(&re, "zäsdf", &match)); + ck_assert_uint_eq(match.start, 1); + ck_assert_uint_eq(match.end, 6); + + ck_assert(cregex_find(&re, "äsdf", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 5); + + cregex_drop(&re); +} +END_TEST + +START_TEST(compile_match_anchors) +{ + cregex re[1] = {cregex_new("^äs.f$")}; + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(re, "äsdf", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 5); + + ck_assert(cregex_find(re, "äs♥f", &match)); + ck_assert(cregex_find(re, "äsöf", &match)); + + cregex_drop(re); +} +END_TEST + +START_TEST(compile_match_quantifiers) +{ + c_auto (cregex, re) { + re = cregex_new("ä+"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "ääb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 4); + + ck_assert(cregex_find(&re, "bäbb", &match)); + ck_assert_uint_eq(match.start, 1); + ck_assert_uint_eq(match.end, 3); + + ck_assert(!cregex_find(&re, "bbb", &match)); + } + c_auto (cregex, re) { + re = cregex_new("bä*"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "bääb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 5); + + ck_assert(cregex_find(&re, "bäbb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 3); + + ck_assert(cregex_find(&re, "bbb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 1); + } +} +END_TEST + +START_TEST(compile_match_complex_quants) +{ + c_auto (cregex, re1, re2, re3, re4) + { + re1 = cregex_new("ä{1,3}"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + re2 = cregex_new("ä{1}"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + re3 = cregex_new("ä{,}"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + re4 = cregex_new("ä{,3}"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re1, "ääb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 4); + ck_assert(cregex_find(&re1, "äääb", &match)); + ck_assert(cregex_find(&re1, "äb", &match)); + ck_assert(!cregex_find(&re1, "b", &match)); + + ck_assert(cregex_find(&re2, "ää", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 2); + ck_assert(cregex_find(&re2, "bbäb", &match)); + ck_assert(!cregex_find(&re2, "bbbb", &match)); + + ck_assert(cregex_find(&re3, "ääääääääääb", &match)); + ck_assert_uint_eq(match.start, 0); + ck_assert_uint_eq(match.end, 20); + ck_assert(cregex_find(&re3, "b", &match)); + + ck_assert(cregex_find(&re4, "bä", &match)); + ck_assert(cregex_find(&re4, "bää", &match)); + ck_assert(cregex_find(&re4, "bäää", &match)); + } +} +END_TEST + +START_TEST(compile_match_escaped_chars) +{ + cregex re = cregex_new("\\n\\r\\t\\{"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "\n\r\t{", &match)); + ck_assert(!cregex_find(&re, "\n\r\t", &match)); + + cregex_drop(&re); +} +END_TEST + +START_TEST(compile_match_class_simple) +{ + c_auto (cregex, re1, re2, re3) + { + re1 = cregex_new("\\s"); + ck_assert_int_eq(cregex_error(), cregex_OK); + re2 = cregex_new("\\w"); + ck_assert_int_eq(cregex_error(), cregex_OK); + re3 = cregex_new("\\D"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re1, " ", &match)); + ck_assert(cregex_find(&re1, "\r", &match)); + ck_assert(cregex_find(&re1, "\n", &match)); + + ck_assert(cregex_find(&re2, "a", &match)); + ck_assert(cregex_find(&re2, "0", &match)); + ck_assert(cregex_find(&re2, "_", &match)); + + ck_assert(cregex_find(&re3, "k", &match)); + ck_assert(!cregex_find(&re3, "0", &match)); + } +} +END_TEST + +START_TEST(compile_match_or) +{ + c_auto (cregex, re, re2) + { + re = cregex_new("as|df"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "as", &match)); + ck_assert(cregex_find(&re, "df", &match)); + + re2 = cregex_new("(as|df)"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + ck_assert(cregex_find(&re2, "as", &match)); + ck_assert(cregex_find(&re2, "df", &match)); + } +} +END_TEST + +START_TEST(compile_match_class_complex_0) +{ + cregex re = cregex_new("[asdf]"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "a", &match)); + ck_assert(cregex_find(&re, "s", &match)); + ck_assert(cregex_find(&re, "d", &match)); + ck_assert(cregex_find(&re, "f", &match)); + + cregex_drop(&re); +} +END_TEST + +START_TEST(compile_match_class_complex_1) +{ + cregex re = cregex_new("[a-zä0-9öA-Z]"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "a", &match)); + ck_assert(cregex_find(&re, "5", &match)); + ck_assert(cregex_find(&re, "A", &match)); + ck_assert(cregex_find(&re, "ä", &match)); + ck_assert(cregex_find(&re, "ö", &match)); + + cregex_drop(&re); +} +END_TEST + +START_TEST(compile_match_cap) +{ + cregex re = cregex_new("(abc)d"); + ck_assert_int_eq(cregex_error(), cregex_OK); + + cregex_match match; + ck_assert(cregex_find(&re, "abcd", &match)); + ck_assert(cregex_find(&re, "llljabcdkk", &match)); + ck_assert(!cregex_find(&re, "abc", &match)); + + cregex_drop(&re); +} +END_TEST + +START_TEST(invalid_quantifier) +{ + ck_assert_ptr_eq(cregex_new("+").nodes, NULL); + ck_assert_int_eq(cregex_error(), cregex_EARLY_QUANTIFIER); +} +END_TEST + +/* Test that invalid utf8 sequences cause a + * cregex_INVALID_UTF8 error */ +START_TEST(invalid_utf8) +{ + char s1[3] = "ä"; + s1[1] = 65; // invalid continuation byte + + ck_assert_ptr_eq(cregex_new(s1).nodes, NULL); + ck_assert_int_eq(cregex_error(), cregex_INVALID_UTF8); +} +END_TEST + +START_TEST(search_all) +{ + c_auto (cregex, re) + { + re = cregex_new("ab"); + cregex_match m = {0}; + bool res; + + res = cregex_find_next(&re, "ab,ab,ab", &m); + ck_assert(res && m.start == 0); + res = cregex_find_next(&re, "ab,ab,ab", &m); + ck_assert(res && m.start == 3); + res = cregex_find_next(&re, "ab,ab,ab", &m); + ck_assert(res && m.start == 6); + res = cregex_find_next(&re, "ab,ab,ab", &m); + ck_assert(!res); + } +} +END_TEST + +START_TEST(captures_len) +{ + c_auto (cregex, re) { + cregex re = cregex_new("(ab(cd))(ef)"); + ck_assert_uint_eq(cregex_capture_size(re), 3); + } +} +END_TEST + +START_TEST(captures_cap) +{ + c_auto (cregex, re) { + re = cregex_new("(ab)((cd)+)"); + ck_assert_uint_eq(cregex_capture_size(re), 3); + + cregex_match match; + ck_assert(cregex_find(&re, "xxabcdcde", &match)); + + cregex_match cap0, cap1; + cregex_capture(re, 0, &cap0); + cregex_capture(re, 1, &cap1); + + ck_assert_uint_eq(cap0.start, 2); + ck_assert_uint_eq(cap0.end, 4); + ck_assert_uint_eq(cap1.start, 4); + ck_assert_uint_eq(cap1.end, 8); + + ck_assert(!cregex_is_match(&re, "abcdcde")); + ck_assert(cregex_is_match(&re, "abcdcdcd")); + } +} +END_TEST + +/* +Suite *cregex_test_suite(void) +{ + Suite *ret = suite_create("mregexp"); + TCase *tcase = tcase_create("mregexp"); + + tcase_add_test(tcase, compile_match_char); + tcase_add_test(tcase, invalid_utf8); + tcase_add_test(tcase, compile_match_anchors); + tcase_add_test(tcase, compile_match_quantifiers); + tcase_add_test(tcase, invalid_quantifier); + tcase_add_test(tcase, compile_match_complex_quants); + tcase_add_test(tcase, compile_match_escaped_chars); + tcase_add_test(tcase, compile_match_class_simple); + tcase_add_test(tcase, compile_match_class_complex_0); + tcase_add_test(tcase, compile_match_class_complex_1); + tcase_add_test(tcase, compile_match_cap); + tcase_add_test(tcase, search_all); + tcase_add_test(tcase, captures_len); + tcase_add_test(tcase, captures_cap); + tcase_add_test(tcase, compile_match_or); + + suite_add_tcase(ret, tcase); + return ret; +} + +int main(void) +{ + SRunner *sr = srunner_create(cregex_test_suite()); + srunner_run_all(sr, CK_NORMAL); + int fails = srunner_ntests_failed(sr); + srunner_free(sr); + return fails ? EXIT_FAILURE : EXIT_SUCCESS; +} +*/ + +int main() +{ + compile_match_char(); + invalid_utf8(); + compile_match_anchors(); + compile_match_quantifiers(); + invalid_quantifier(); + compile_match_complex_quants(); + compile_match_escaped_chars(); + compile_match_class_simple(); + compile_match_class_complex_0(); + compile_match_class_complex_1(); + compile_match_cap(); + search_all(); + captures_len(); + captures_cap(); + compile_match_or(); + printf("All tests succesful.\n"); +} |
