vi: use ren_noeol() in vc_replace()
[neatvi.git] / rset.c
blob7673496aa9201dbe19906b92e91927c3eec9ea6e
1 #include <regex.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "vi.h"
7 /* regular expression set */
8 struct rset {
9 regex_t regex; /* the combined regular expression */
10 int n; /* number of regular expressions in this set */
11 int *grp; /* the group assigned to each subgroup */
12 int *setgrpcnt; /* number of groups in each regular expression */
13 int grpcnt; /* group count */
16 static int re_groupcount(char *s)
18 int n = 0;
19 while (*s) {
20 if (s[0] == '(')
21 n++;
22 if (s[0] == '\\' && s[1])
23 s++;
24 s++;
26 return n;
29 struct rset *rset_make(int n, char **re, int flg)
31 struct rset *rs = malloc(sizeof(*rs));
32 struct sbuf *sb = sbuf_make();
33 int regex_flg = REG_EXTENDED | (flg & RE_ICASE ? REG_ICASE : 0);
34 int i;
35 memset(rs, 0, sizeof(*rs));
36 rs->grp = malloc((n + 1) * sizeof(rs->grp[0]));
37 rs->setgrpcnt = malloc((n + 1) * sizeof(rs->setgrpcnt[0]));
38 rs->grpcnt = 2;
39 rs->n = n;
40 sbuf_chr(sb, '(');
41 for (i = 0; i < n; i++) {
42 if (!re[i]) {
43 rs->grp[i] = -1;
44 rs->setgrpcnt[i] = 0;
45 continue;
47 if (sbuf_len(sb) > 1)
48 sbuf_chr(sb, '|');
49 sbuf_chr(sb, '(');
50 sbuf_str(sb, re[i]);
51 sbuf_chr(sb, ')');
52 rs->grp[i] = rs->grpcnt;
53 rs->setgrpcnt[i] = re_groupcount(re[i]);
54 rs->grpcnt += 1 + rs->setgrpcnt[i];
56 rs->grp[n] = rs->grpcnt;
57 sbuf_chr(sb, ')');
58 if (regcomp(&rs->regex, sbuf_buf(sb), regex_flg)) {
59 free(rs->grp);
60 free(rs->setgrpcnt);
61 free(rs);
62 sbuf_free(sb);
63 return NULL;
65 sbuf_free(sb);
66 return rs;
69 /* return the index of the matching regular expression or -1 if none matches */
70 int rset_find(struct rset *rs, char *s, int n, int *grps, int flg)
72 regmatch_t *subs;
73 int found, i, set = -1;
74 int regex_flg = 0;
75 if (rs->grpcnt <= 2)
76 return -1;
77 if (flg & RE_NOTBOL)
78 regex_flg |= REG_NOTBOL;
79 if (flg & RE_NOTEOL)
80 regex_flg |= REG_NOTEOL;
81 subs = malloc(rs->grpcnt * sizeof(subs[0]));
82 found = !regexec(&rs->regex, s, rs->grpcnt, subs, regex_flg);
83 for (i = 0; found && i < rs->n; i++)
84 if (rs->grp[i] >= 0 && subs[rs->grp[i]].rm_so >= 0)
85 set = i;
86 if (found && set >= 0) {
87 for (i = 0; i < n; i++) {
88 int grp = rs->grp[set] + i;
89 if (i < rs->setgrpcnt[set] + 1) {
90 grps[i * 2] = subs[grp].rm_so;
91 grps[i * 2 + 1] = subs[grp].rm_eo;
92 } else {
93 grps[i * 2 + 0] = -1;
94 grps[i * 2 + 1] = -1;
98 free(subs);
99 return set;
102 void rset_free(struct rset *rs)
104 regfree(&rs->regex);
105 free(rs->setgrpcnt);
106 free(rs->grp);
107 free(rs);