README: mention prompt history
[neatvi.git] / rstr.c
blob8c3ca556df527a04264ba01222422d1177274c10
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "vi.h"
7 struct rstr {
8 struct rset *rs; /* only for regex patterns */
9 char *str; /* for simple, non-regex patterns */
10 int icase; /* ignore case */
11 int lbeg, lend; /* match line beg/end */
12 int wbeg, wend; /* match word beg/end */
15 /* return zero if a simple pattern is given */
16 static int rstr_simple(struct rstr *rs, char *re)
18 char *beg;
19 char *end;
20 rs->lbeg = re[0] == '^';
21 if (rs->lbeg)
22 re++;
23 rs->wbeg = re[0] == '\\' && re[1] == '<';
24 if (rs->wbeg)
25 re += 2;
26 beg = re;
27 while (re[0] && !strchr("\\.*+?[]{}()$", (unsigned char) re[0]))
28 re++;
29 end = re;
30 rs->wend = re[0] == '\\' && re[1] == '>';
31 if (rs->wend)
32 re += 2;
33 rs->lend = re[0] == '$';
34 if (rs->lend)
35 re++;
36 if (!re[0]) {
37 int len = end - beg;
38 rs->str = malloc(len + 1);
39 memcpy(rs->str, beg, len);
40 rs->str[len] = '\0';
41 return 0;
43 return 1;
46 struct rstr *rstr_make(char *re, int flg)
48 struct rstr *rs = malloc(sizeof(*rs));
49 memset(rs, 0, sizeof(*rs));
50 rs->icase = flg & RE_ICASE;
51 if (rstr_simple(rs, re))
52 rs->rs = rset_make(1, &re, flg);
53 if (!rs->rs && !rs->str) {
54 free(rs);
55 return NULL;
57 return rs;
60 static int isword(char *s)
62 int c = (unsigned char) s[0];
63 return isalnum(c) || c == '_' || c > 127;
66 static int match_case(char *s, char *r, int icase)
68 for (; *r && *s; s++, r++) {
69 if (!icase && *s != *r)
70 return 1;
71 if (icase && tolower((unsigned char) *s) != tolower((unsigned char) *r))
72 return 1;
74 return *r;
77 /* return zero if an occurrence is found */
78 int rstr_find(struct rstr *rs, char *s, int n, int *grps, int flg)
80 int len;
81 char *beg, *end;
82 char *r;
83 if (rs->rs)
84 return rset_find(rs->rs, s, n, grps, flg);
85 if ((rs->lbeg && (flg & RE_NOTBOL)) || (rs->lend && (flg & RE_NOTEOL)))
86 return -1;
87 len = strlen(rs->str);
88 beg = s;
89 end = s + strlen(s) - len - 1;
90 if (end < beg)
91 return -1;
92 if (rs->lend)
93 beg = end;
94 if (rs->lbeg)
95 end = s;
96 for (r = beg; r <= end; r++) {
97 if (rs->wbeg && r > s && (isword(r - 1) || !isword(r)))
98 continue;
99 if (rs->wend && r[len] && (!isword(r + len - 1) || isword(r + len)))
100 continue;
101 if (!match_case(r, rs->str, rs->icase)) {
102 if (n >= 1) {
103 grps[0] = r - s;
104 grps[1] = r - s + len;
106 return 0;
109 return -1;
112 void rstr_free(struct rstr *rs)
114 if (rs->rs)
115 rset_free(rs->rs);
116 free(rs->str);
117 free(rs);