vis: use strncpy to copy into fixed sized buffer
[vis.git] / text-regex-tre.c
blob3f02dcd19720c8c5007562414f3f75e3d12af680
1 #include <stdlib.h>
2 #include <string.h>
3 #include <wchar.h>
4 #include <errno.h>
6 #include "text-regex.h"
7 #include "text-motions.h"
9 struct Regex {
10 regex_t regex;
11 tre_str_source str_source;
12 Text *text;
13 Iterator it;
14 size_t end;
17 size_t text_regex_nsub(Regex *r) {
18 if (!r)
19 return 0;
20 return r->regex.re_nsub;
23 static int str_next_char(tre_char_t *c, unsigned int *pos_add, void *context) {
24 Regex *r = context;
25 Iterator *it = &r->it;
26 if (TRE_WCHAR) {
27 mbstate_t ps = { 0 };
28 bool eof = false;
29 size_t start = it->pos;
30 for (;;) {
31 if (it->pos >= r->end) {
32 eof = true;
33 break;
35 size_t rem = r->end - it->pos;
36 size_t plen = it->end - it->text;
37 size_t len = rem < plen ? rem : plen;
38 size_t wclen = mbrtowc(c, it->text, len, &ps);
39 if (wclen == (size_t)-1 && errno == EILSEQ) {
40 *c = L'\0';
41 text_iterator_codepoint_next(it, NULL);
42 break;
43 } else if (wclen == (size_t)-2) {
44 if (!text_iterator_next(it)) {
45 eof = true;
46 break;
48 } else if (wclen == 0) {
49 text_iterator_byte_next(it, NULL);
50 break;
51 } else {
52 if (wclen < plen) {
53 it->text += wclen;
54 it->pos += wclen;
55 } else {
56 text_iterator_next(it);
58 break;
62 if (eof) {
63 *c = L'\0';
64 *pos_add = 1;
65 return 1;
66 } else {
67 *pos_add = it->pos - start;
68 return 0;
70 } else {
71 *pos_add = 1;
72 if (it->pos < r->end && text_iterator_byte_get(it, (char*)c)) {
73 text_iterator_byte_next(it, NULL);
74 return 0;
75 } else {
76 *c = '\0';
77 return 1;
82 static void str_rewind(size_t pos, void *context) {
83 Regex *r = context;
84 r->it = text_iterator_get(r->text, pos);
87 static int str_compare(size_t pos1, size_t pos2, size_t len, void *context) {
88 Regex *r = context;
89 int ret = 1;
90 void *buf1 = malloc(len), *buf2 = malloc(len);
91 if (!buf1 || !buf2)
92 goto err;
93 text_bytes_get(r->text, pos1, len, buf1);
94 text_bytes_get(r->text, pos2, len, buf2);
95 ret = memcmp(buf1, buf2, len);
96 err:
97 free(buf1);
98 free(buf2);
99 return ret;
102 Regex *text_regex_new(void) {
103 Regex *r = calloc(1, sizeof(*r));
104 if (!r)
105 return NULL;
106 r->str_source = (tre_str_source) {
107 .get_next_char = str_next_char,
108 .rewind = str_rewind,
109 .compare = str_compare,
110 .context = r,
112 return r;
115 void text_regex_free(Regex *r) {
116 if (!r)
117 return;
118 tre_regfree(&r->regex);
119 free(r);
122 int text_regex_compile(Regex *regex, const char *string, int cflags) {
123 int r = tre_regcomp(&regex->regex, string, cflags);
124 if (r)
125 tre_regcomp(&regex->regex, "\0\0", 0);
126 return r;
129 int text_regex_match(Regex *r, const char *data, int eflags) {
130 return tre_regexec(&r->regex, data, 0, NULL, eflags);
133 int text_search_range_forward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
134 r->text = txt;
135 r->it = text_iterator_get(txt, pos);
136 r->end = pos+len;
138 regmatch_t match[nmatch];
139 int ret = tre_reguexec(&r->regex, &r->str_source, nmatch, match, eflags);
140 if (!ret) {
141 for (size_t i = 0; i < nmatch; i++) {
142 pmatch[i].start = match[i].rm_so == -1 ? EPOS : pos + match[i].rm_so;
143 pmatch[i].end = match[i].rm_eo == -1 ? EPOS : pos + match[i].rm_eo;
146 return ret;
149 int text_search_range_backward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
150 int ret = REG_NOMATCH;
151 size_t end = pos + len;
153 while (pos < end && !text_search_range_forward(txt, pos, len, r, nmatch, pmatch, eflags)) {
154 ret = 0;
155 // FIXME: assumes nmatch >= 1
156 size_t next = pmatch[0].end;
157 if (next == pos) {
158 next = text_line_next(txt, pos);
159 if (next == pos)
160 break;
162 pos = next;
163 len = end - pos;
166 return ret;