vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

text-regex.c

(2688B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 
      4 #include "text-regex.h"
      5 
      6 struct Regex {
      7 	regex_t regex;
      8 };
      9 
     10 Regex *text_regex_new(void) {
     11 	Regex *r = calloc(1, sizeof(Regex));
     12 	if (!r)
     13 		return NULL;
     14 	regcomp(&r->regex, "\0\0", 0); /* this should not match anything */
     15 	return r;
     16 }
     17 
     18 int text_regex_compile(Regex *regex, const char *string, int cflags) {
     19 	int r = regcomp(&regex->regex, string, cflags);
     20 	if (r)
     21 		regcomp(&regex->regex, "\0\0", 0);
     22 	return r;
     23 }
     24 
     25 size_t text_regex_nsub(Regex *r) {
     26 	if (!r)
     27 		return 0;
     28 	return r->regex.re_nsub;
     29 }
     30 
     31 void text_regex_free(Regex *r) {
     32 	if (!r)
     33 		return;
     34 	regfree(&r->regex);
     35 	free(r);
     36 }
     37 
     38 int text_regex_match(Regex *r, const char *data, int eflags) {
     39 	return regexec(&r->regex, data, 0, NULL, eflags);
     40 }
     41 
     42 int text_search_range_forward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
     43 	char *buf = text_bytes_alloc0(txt, pos, len);
     44 	if (!buf)
     45 		return REG_NOMATCH;
     46 	char *cur = buf, *end = buf + len;
     47 	int ret = REG_NOMATCH;
     48 	regmatch_t match[MAX_REGEX_SUB];
     49 	for (size_t junk = len; len > 0; len -= junk, pos += junk) {
     50 		ret = regexec(&r->regex, cur, nmatch, match, eflags);
     51 		if (!ret) {
     52 			for (size_t i = 0; i < nmatch; i++) {
     53 				pmatch[i].start = match[i].rm_so == -1 ? EPOS : pos + match[i].rm_so;
     54 				pmatch[i].end = match[i].rm_eo == -1 ? EPOS : pos + match[i].rm_eo;
     55 			}
     56 			break;
     57 		}
     58 		char *next = memchr(cur, 0, len);
     59 		if (!next)
     60 			break;
     61 		while (!*next && next != end)
     62 			next++;
     63 		junk = next - cur;
     64 		cur = next;
     65 	}
     66 	free(buf);
     67 	return ret;
     68 }
     69 
     70 int text_search_range_backward(Text *txt, size_t pos, size_t len, Regex *r, size_t nmatch, RegexMatch pmatch[], int eflags) {
     71 	char *buf = text_bytes_alloc0(txt, pos, len);
     72 	if (!buf)
     73 		return REG_NOMATCH;
     74 	char *cur = buf, *end = buf + len;
     75 	int ret = REG_NOMATCH;
     76 	regmatch_t match[MAX_REGEX_SUB];
     77 	for (size_t junk = len; len > 0; len -= junk, pos += junk) {
     78 		char *next;
     79 		if (!regexec(&r->regex, cur, nmatch, match, eflags)) {
     80 			ret = 0;
     81 			for (size_t i = 0; i < nmatch; i++) {
     82 				pmatch[i].start = match[i].rm_so == -1 ? EPOS : pos + match[i].rm_so;
     83 				pmatch[i].end = match[i].rm_eo == -1 ? EPOS : pos + match[i].rm_eo;
     84 			}
     85 
     86 			if (match[0].rm_so == 0 && match[0].rm_eo == 0) {
     87 				/* empty match at the beginning of cur, advance to next line */
     88 				next = strchr(cur, '\n');
     89 				if (!next)
     90 					break;
     91 				next++;
     92 			} else {
     93 				next = cur + match[0].rm_eo;
     94 			}
     95 		} else {
     96 			next = memchr(cur, 0, len);
     97 			if (!next)
     98 				break;
     99 			while (!*next && next != end)
    100 				next++;
    101 		}
    102 		junk = next - cur;
    103 		cur = next;
    104 		if (cur[-1] == '\n')
    105 			eflags &= ~REG_NOTBOL;
    106 		else
    107 			eflags |= REG_NOTBOL;
    108 	}
    109 	free(buf);
    110 	return ret;
    111 }