led: messages and ex prompts are always left-to-right
[neatvi.git] / rset.c
blob553b4fd332fbf327af3fdf237b297d54478f0ce0
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "regex.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] == '[') {
23 int dep = 0;
24 s += s[1] == '^' ? 3 : 2;
25 while (s[0] && (s[0] != ']' || dep)) {
26 if (s[0] == '[')
27 dep++;
28 if (s[0] == ']')
29 dep--;
30 s++;
33 if (s[0] == '\\' && s[1])
34 s++;
35 s++;
37 return n;
40 struct rset *rset_make(int n, char **re, int flg)
42 struct rset *rs = malloc(sizeof(*rs));
43 struct sbuf *sb = sbuf_make();
44 int regex_flg = REG_EXTENDED | (flg & RE_ICASE ? REG_ICASE : 0);
45 int i;
46 memset(rs, 0, sizeof(*rs));
47 rs->grp = malloc((n + 1) * sizeof(rs->grp[0]));
48 rs->setgrpcnt = malloc((n + 1) * sizeof(rs->setgrpcnt[0]));
49 rs->grpcnt = 2;
50 rs->n = n;
51 sbuf_chr(sb, '(');
52 for (i = 0; i < n; i++) {
53 if (!re[i]) {
54 rs->grp[i] = -1;
55 rs->setgrpcnt[i] = 0;
56 continue;
58 if (sbuf_len(sb) > 1)
59 sbuf_chr(sb, '|');
60 sbuf_chr(sb, '(');
61 sbuf_str(sb, re[i]);
62 sbuf_chr(sb, ')');
63 rs->grp[i] = rs->grpcnt;
64 rs->setgrpcnt[i] = re_groupcount(re[i]);
65 rs->grpcnt += 1 + rs->setgrpcnt[i];
67 rs->grp[n] = rs->grpcnt;
68 sbuf_chr(sb, ')');
69 if (regcomp(&rs->regex, sbuf_buf(sb), regex_flg)) {
70 free(rs->grp);
71 free(rs->setgrpcnt);
72 free(rs);
73 sbuf_free(sb);
74 return NULL;
76 sbuf_free(sb);
77 return rs;
80 /* return the index of the matching regular expression or -1 if none matches */
81 int rset_find(struct rset *rs, char *s, int n, int *grps, int flg)
83 regmatch_t *subs;
84 int found, i, set = -1;
85 int regex_flg = 0;
86 if (rs->grpcnt <= 2)
87 return -1;
88 if (flg & RE_NOTBOL)
89 regex_flg |= REG_NOTBOL;
90 if (flg & RE_NOTEOL)
91 regex_flg |= REG_NOTEOL;
92 subs = malloc(rs->grpcnt * sizeof(subs[0]));
93 found = !regexec(&rs->regex, s, rs->grpcnt, subs, regex_flg);
94 for (i = 0; found && i < rs->n; i++)
95 if (rs->grp[i] >= 0 && subs[rs->grp[i]].rm_so >= 0)
96 set = i;
97 if (found && set >= 0) {
98 for (i = 0; i < n; i++) {
99 int grp = rs->grp[set] + i;
100 if (i < rs->setgrpcnt[set] + 1) {
101 grps[i * 2] = subs[grp].rm_so;
102 grps[i * 2 + 1] = subs[grp].rm_eo;
103 } else {
104 grps[i * 2 + 0] = -1;
105 grps[i * 2 + 1] = -1;
109 free(subs);
110 return set;
113 void rset_free(struct rset *rs)
115 regfree(&rs->regex);
116 free(rs->setgrpcnt);
117 free(rs->grp);
118 free(rs);
121 /* read a regular expression enclosed in a delimiter */
122 char *re_read(char **src)
124 struct sbuf *sbuf = sbuf_make();
125 char *s = *src;
126 int delim = (unsigned char) *s++;
127 if (!delim)
128 return NULL;
129 while (*s && *s != delim) {
130 if (s[0] == '\\' && s[1])
131 if (*(++s) != delim)
132 sbuf_chr(sbuf, '\\');
133 sbuf_chr(sbuf, (unsigned char) *s++);
135 *src = *s ? s + 1 : s;
136 return sbuf_done(sbuf);