aboutsummaryrefslogtreecommitdiff
path: root/text-regex-tre.c
blob: 0ac8b381f4c854b8b6efb5455da24857edfcff7b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdlib.h>
#include <string.h>

#include "text-regex.h"
#include "text-motions.h"

struct Regex {
	regex_t regex;
	tre_str_source str_source;
	Text *text;
	Iterator it;
	size_t end;
};

size_t text_regex_nsub(Regex *r) {
       if (!r)
               return 0;
       return r->regex.re_nsub;
}

static int str_next_char(tre_char_t *c, unsigned int *pos_add, void *context) {
	Regex *r = context;
	*pos_add = 1;
	if (r->it.pos < r->end && text_iterator_byte_get(&r->it, (char*)c)) {
		text_iterator_byte_next(&r->it, NULL);
		return 0;
	} else {
		*c = '\0';
		return 1;
	}
}

static void str_rewind(size_t pos, void *context) {
	Regex *r = context;
	r->it = text_iterator_get(r->text, pos);
}

static int str_compare(size_t pos1, size_t pos2, size_t len, void *context) {
	Regex *r = context;
	int ret = 1;
	void *buf1 = malloc(len), *buf2 = malloc(len);
	if (!buf1 || !buf2)
		goto err;
	text_bytes_get(r->text, pos1, len, buf1);
	text_bytes_get(r->text, pos2, len, buf2);
	ret = memcmp(buf1, buf2, len);
err:
	free(buf1);
	free(buf2);
	return ret;
}

Regex *text_regex_new(void) {
	Regex *r = calloc(1, sizeof(*r));
	if (!r)
		return NULL;
	r->str_source = (tre_str_source) {
		.get_next_char = str_next_char,
		.rewind = str_rewind,
		.compare = str_compare,
		.context = r,
	};
	return r;
}

void text_regex_free(Regex *r) {
	if (!r)
		return;
	tre_regfree(&r->regex);
	free(r);
}

int text_regex_compile(Regex *regex, const char *string, int cflags) {
	int r = tre_regcomp(&regex->regex, string, cflags);
	if (r)
		tre_regcomp(&regex->regex, "\0\0", 0);
	return r;
}

int text_regex_match(Regex *r, const char *data, int eflags) {
	return tre_regexec(&r->regex, data, 0, NULL, eflags);
}

int text_search_range_forward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
	r->text = txt;
	r->it = text_iterator_get(txt, pos);
	r->end = pos+len;

	regmatch_t match[nmatch];
	int ret = tre_reguexec(&r->regex, &r->str_source, nmatch, match, eflags);
	if (!ret) {
		for (size_t i = 0; i < nmatch; i++) {
			pmatch[i].start = match[i].rm_so == -1 ? EPOS : pos + match[i].rm_so;
			pmatch[i].end = match[i].rm_eo == -1 ? EPOS : pos + match[i].rm_eo;
		}
	}
	return ret;
}

int text_search_range_backward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
	int ret = REG_NOMATCH;
	size_t end = pos + len;

	while (pos < end && !text_search_range_forward(txt, pos, len, r, nmatch, pmatch, eflags)) {
		ret = 0;
		// FIXME: assumes nmatch >= 1
		size_t next = pmatch[0].end;
		if (next == pos) {
			next = text_line_next(txt, pos);
			if (next == pos)
				break;
		}
		pos = next;
		len = end - pos;
	}

	return ret;
}