search.c - ledit - Text editor (WIP) | |
git clone git://lumidify.org/ledit.git (fast, but not encrypted) | |
git clone https://lumidify.org/ledit.git (encrypted, but very slow) | |
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/… | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
search.c (5173B) | |
--- | |
1 #include <string.h> | |
2 | |
3 #include "view.h" | |
4 #include "buffer.h" | |
5 #include "search.h" | |
6 #include "memory.h" | |
7 | |
8 /* FIXME: make sure only whole utf8 chars are matched | |
9 -> actually, isn't this always the case as long as the | |
10 pattern is valid utf8 because of the structure of utf8? */ | |
11 static char *last_search = NULL; | |
12 static size_t last_search_len = 0; | |
13 enum { | |
14 FORWARD, | |
15 BACKWARD | |
16 } last_dir = FORWARD; | |
17 | |
18 void | |
19 search_cleanup(void) { | |
20 free(last_search); | |
21 last_search = NULL; | |
22 last_search_len = 0; | |
23 } | |
24 | |
25 void | |
26 set_search_forward(char *pattern) { | |
27 last_dir = FORWARD; | |
28 free(last_search); | |
29 last_search = ledit_strdup(pattern); | |
30 last_search_len = strlen(last_search); | |
31 } | |
32 | |
33 void | |
34 set_search_backward(char *pattern) { | |
35 last_dir = BACKWARD; | |
36 free(last_search); | |
37 last_search = ledit_strdup(pattern); | |
38 last_search_len = strlen(last_search); | |
39 } | |
40 | |
41 static search_state | |
42 search_forward(ledit_view *view, size_t *line_ret, size_t *byte_ret, siz… | |
43 *line_ret = view->cur_line; | |
44 *byte_ret = view->cur_index; | |
45 *len_ret = last_search_len; | |
46 /* if last_search is empty, strstr will find the ending '\0' */ | |
47 if (last_search == NULL || last_search[0] == '\0') | |
48 return SEARCH_NO_PATTERN; | |
49 size_t line = view->cur_line; | |
50 /* start one byte later so it doesn't get stuck on a match | |
51 note: in certain cases, this may not be a valid index */ | |
52 size_t byte = view->cur_index + 1; | |
53 char *res; | |
54 ledit_line *lline = buffer_get_line(view->buffer, line); | |
55 buffer_normalize_line(lline); | |
56 if (byte < lline->len && (res = strstr(lline->text + byte, last_… | |
57 *line_ret = line; | |
58 *byte_ret = (size_t)(res - lline->text); | |
59 return SEARCH_NORMAL; | |
60 } | |
61 for (size_t i = line + 1; i < view->lines_num; i++) { | |
62 lline = buffer_get_line(view->buffer, i); | |
63 buffer_normalize_line(lline); | |
64 if ((res = strstr(lline->text, last_search)) != NULL) { | |
65 *line_ret = i; | |
66 *byte_ret = (size_t)(res - lline->text); | |
67 return SEARCH_NORMAL; | |
68 } | |
69 } | |
70 for (size_t i = 0; i < line; i++) { | |
71 lline = buffer_get_line(view->buffer, i); | |
72 buffer_normalize_line(lline); | |
73 if ((res = strstr(lline->text, last_search)) != NULL) { | |
74 *line_ret = i; | |
75 *byte_ret = (size_t)(res - lline->text); | |
76 return SEARCH_WRAPPED; | |
77 } | |
78 } | |
79 lline = buffer_get_line(view->buffer, line); | |
80 buffer_normalize_line(lline); | |
81 if ((res = strstr(lline->text, last_search)) != NULL) { | |
82 *line_ret = line; | |
83 *byte_ret = (size_t)(res - lline->text); | |
84 return SEARCH_WRAPPED; | |
85 } | |
86 return SEARCH_NOT_FOUND; | |
87 } | |
88 | |
89 /* FIXME: this is insanely inefficient */ | |
90 /* FIXME: just go backwards char-by-char and compare or knuth-morris-pra… | |
91 static search_state | |
92 search_backward(ledit_view *view, size_t *line_ret, size_t *byte_ret, si… | |
93 *line_ret = view->cur_line; | |
94 *byte_ret = view->cur_index; | |
95 *len_ret = last_search_len; | |
96 if (last_search == NULL || last_search[0] == '\0') | |
97 return SEARCH_NO_PATTERN; | |
98 size_t line = view->cur_line; | |
99 size_t byte = view->cur_index; | |
100 ledit_line *lline = buffer_get_line(view->buffer, line); | |
101 buffer_normalize_line(lline); | |
102 char *last = NULL, *res = lline->text; | |
103 while ((res = strstr(res, last_search)) != NULL && res < lline->… | |
104 last = res; | |
105 res++; | |
106 } | |
107 if (last != NULL) { | |
108 *line_ret = line; | |
109 /* FIXME: check if this is safe */ | |
110 *byte_ret = (size_t)(last - lline->text); | |
111 return SEARCH_NORMAL; | |
112 } | |
113 for (size_t i = line; i > 0; i--) { | |
114 lline = buffer_get_line(view->buffer, i-1); | |
115 buffer_normalize_line(lline); | |
116 res = lline->text; | |
117 while ((res = strstr(res, last_search)) != NULL) { | |
118 last = res; | |
119 res++; | |
120 } | |
121 if (last != NULL) { | |
122 *line_ret = i-1; | |
123 *byte_ret = (size_t)(last - lline->text); | |
124 return SEARCH_NORMAL; | |
125 } | |
126 } | |
127 for (size_t i = view->lines_num - 1; i > line; i--) { | |
128 lline = buffer_get_line(view->buffer, i); | |
129 buffer_normalize_line(lline); | |
130 res = lline->text; | |
131 while ((res = strstr(res, last_search)) != NULL) { | |
132 last = res; | |
133 res++; | |
134 } | |
135 if (last != NULL) { | |
136 *line_ret = i; | |
137 *byte_ret = (size_t)(last - lline->text); | |
138 return SEARCH_WRAPPED; | |
139 } | |
140 } | |
141 lline = buffer_get_line(view->buffer, line); | |
142 buffer_normalize_line(lline); | |
143 res = lline->text + byte; | |
144 while ((res = strstr(res, last_search)) != NULL) { | |
145 last = res; | |
146 res++; | |
147 } | |
148 if (last != NULL) { | |
149 *line_ret = line; | |
150 *byte_ret = (size_t)(last - lline->text); | |
151 return SEARCH_WRAPPED; | |
152 } | |
153 return SEARCH_NOT_FOUND; | |
154 } | |
155 | |
156 search_state | |
157 ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byte_ret, … | |
158 if (last_dir == FORWARD) | |
159 return search_forward(view, line_ret, byte_ret, len_ret); | |
160 else | |
161 return search_backward(view, line_ret, byte_ret, len_ret… | |
162 } | |
163 | |
164 search_state | |
165 ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byte_ret, … | |
166 if (last_dir == FORWARD) | |
167 return search_backward(view, line_ret, byte_ret, len_ret… | |
168 else | |
169 return search_forward(view, line_ret, byte_ret, len_ret); | |
170 } | |
171 | |
172 char * | |
173 search_state_to_str(search_state s) { | |
174 switch (s) { | |
175 case SEARCH_NORMAL: | |
176 return "Found match"; | |
177 case SEARCH_WRAPPED: | |
178 return "Search wrapped"; | |
179 case SEARCH_NOT_FOUND: | |
180 return "Pattern not found"; | |
181 case SEARCH_NO_PATTERN: | |
182 return "No previous search pattern"; | |
183 default: | |
184 return "This message should not be shown. " | |
185 "Please bug lumidify about it."; | |
186 } | |
187 } |