Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* move2.c */ |
2 | ||
3 | /* Author: | |
4 | * Steve Kirkendall | |
5 | * 14407 SW Teal Blvd. #C | |
6 | * Beaverton, OR 97005 | |
7 | * kirkenda@cs.pdx.edu | |
8 | */ | |
9 | ||
10 | ||
11 | /* This function contains the movement functions that perform RE searching */ | |
12 | ||
13 | #include "config.h" | |
14 | #include "vi.h" | |
6e657cf2 AM |
15 | #ifdef REGEX |
16 | # include <regex.h> | |
17 | #else | |
18 | # include "regexp.h" | |
19 | #endif | |
15637ed4 RG |
20 | |
21 | extern long atol(); | |
22 | ||
6e657cf2 AM |
23 | #ifdef REGEX |
24 | static regex_t *re = NULL; /* compiled version of the pattern to search for */ | |
25 | #else | |
15637ed4 | 26 | static regexp *re; /* compiled version of the pattern to search for */ |
6e657cf2 | 27 | #endif |
15637ed4 RG |
28 | static prevsf; /* boolean: previous search direction was forward? */ |
29 | ||
30 | #ifndef NO_EXTENSIONS | |
31 | /*ARGSUSED*/ | |
32 | MARK m_wsrch(word, m, cnt) | |
33 | char *word; /* the word to search for */ | |
34 | MARK m; /* the starting point */ | |
35 | int cnt; /* ignored */ | |
36 | { | |
37 | char buffer[30]; | |
38 | ||
39 | /* wrap \< and \> around the word */ | |
40 | strcpy(buffer, "/\\<"); | |
41 | strcat(buffer, word); | |
42 | strcat(buffer, "\\>"); | |
43 | ||
44 | /* show the searched-for word on the bottom line */ | |
45 | move(LINES - 1, 0); | |
46 | qaddstr(buffer); | |
47 | clrtoeol(); | |
48 | refresh(); | |
49 | ||
50 | /* search for the word */ | |
51 | return m_fsrch(m, buffer); | |
52 | } | |
53 | #endif | |
54 | ||
08746e8b | 55 | MARK m_nsrch(m, cnt, cmd) |
15637ed4 | 56 | MARK m; /* where to start searching */ |
08746e8b AM |
57 | long cnt; /* number of searches to do */ |
58 | int cmd; /* command character -- 'n' or 'N' */ | |
15637ed4 | 59 | { |
08746e8b | 60 | int oldprevsf; /* original value of prevsf, so we can fix any changes */ |
15637ed4 | 61 | |
08746e8b AM |
62 | DEFAULT(1L); |
63 | ||
64 | /* clear the bottom line. In particular, we want to loose any | |
65 | * "(wrapped)" notice. | |
66 | */ | |
67 | move(LINES - 1, 0); | |
68 | clrtoeol(); | |
69 | ||
70 | /* if 'N' command, then invert the "prevsf" variable */ | |
71 | oldprevsf = prevsf; | |
72 | if (cmd == 'N') | |
15637ed4 | 73 | { |
08746e8b | 74 | prevsf = !prevsf; |
15637ed4 | 75 | } |
08746e8b AM |
76 | |
77 | /* search forward if prevsf -- i.e., if previous search was forward */ | |
78 | while (--cnt >= 0L && m != MARK_UNSET) | |
15637ed4 | 79 | { |
08746e8b AM |
80 | if (prevsf) |
81 | { | |
82 | m = m_fsrch(m, (char *)0); | |
83 | } | |
84 | else | |
85 | { | |
86 | m = m_bsrch(m, (char *)0); | |
87 | } | |
15637ed4 | 88 | } |
08746e8b AM |
89 | |
90 | /* restore the old value of prevsf -- if cmd=='N' then it was inverted, | |
91 | * and the m_fsrch() and m_bsrch() functions force it to a (possibly | |
92 | * incorrect) value. The value of prevsf isn't supposed to be changed | |
93 | * at all here! | |
94 | */ | |
95 | prevsf = oldprevsf; | |
15637ed4 RG |
96 | return m; |
97 | } | |
98 | ||
08746e8b | 99 | |
15637ed4 RG |
100 | MARK m_fsrch(m, ptrn) |
101 | MARK m; /* where to start searching */ | |
102 | char *ptrn; /* pattern to search for */ | |
103 | { | |
104 | long l; /* line# of line to be searched */ | |
105 | char *line; /* text of line to be searched */ | |
106 | int wrapped;/* boolean: has our search wrapped yet? */ | |
107 | int pos; /* where we are in the line */ | |
6e657cf2 AM |
108 | #ifdef REGEX |
109 | regex_t *optpat(); | |
110 | regmatch_t rm[SE_MAX]; | |
111 | int n; | |
112 | #endif | |
15637ed4 RG |
113 | #ifndef CRUNCH |
114 | long delta = INFINITY;/* line offset, for things like "/foo/+1" */ | |
115 | #endif | |
116 | ||
117 | /* remember: "previous search was forward" */ | |
118 | prevsf = TRUE; | |
119 | ||
120 | if (ptrn && *ptrn) | |
121 | { | |
122 | /* locate the closing '/', if any */ | |
123 | line = parseptrn(ptrn); | |
124 | #ifndef CRUNCH | |
125 | if (*line) | |
126 | { | |
127 | delta = atol(line); | |
128 | } | |
129 | #endif | |
130 | ptrn++; | |
131 | ||
6e657cf2 AM |
132 | |
133 | #ifdef REGEX | |
134 | /* XXX where to free re? */ | |
135 | re = optpat(ptrn); | |
136 | #else | |
15637ed4 | 137 | /* free the previous pattern */ |
08746e8b | 138 | if (re) _free_(re); |
15637ed4 RG |
139 | |
140 | /* compile the pattern */ | |
141 | re = regcomp(ptrn); | |
6e657cf2 | 142 | #endif |
15637ed4 RG |
143 | if (!re) |
144 | { | |
145 | return MARK_UNSET; | |
146 | } | |
147 | } | |
148 | else if (!re) | |
149 | { | |
150 | msg("No previous expression"); | |
151 | return MARK_UNSET; | |
152 | } | |
153 | ||
154 | /* search forward for the pattern */ | |
155 | pos = markidx(m) + 1; | |
156 | pfetch(markline(m)); | |
157 | if (pos >= plen) | |
158 | { | |
159 | pos = 0; | |
160 | m = (m | (BLKSIZE - 1)) + 1; | |
161 | } | |
162 | wrapped = FALSE; | |
163 | for (l = markline(m); l != markline(m) + 1 || !wrapped; l++) | |
164 | { | |
165 | /* wrap search */ | |
166 | if (l > nlines) | |
167 | { | |
168 | /* if we wrapped once already, then the search failed */ | |
169 | if (wrapped) | |
170 | { | |
171 | break; | |
172 | } | |
173 | ||
174 | /* else maybe we should wrap now? */ | |
175 | if (*o_wrapscan) | |
176 | { | |
177 | l = 0; | |
178 | wrapped = TRUE; | |
179 | continue; | |
180 | } | |
181 | else | |
182 | { | |
183 | break; | |
184 | } | |
185 | } | |
186 | ||
187 | /* get this line */ | |
188 | line = fetchline(l); | |
189 | ||
190 | /* check this line */ | |
6e657cf2 AM |
191 | #ifdef REGEX |
192 | if (!regexec(re, &line[pos], SE_MAX, rm, (pos == 0) ? 0 : REG_NOTBOL)) | |
193 | #else | |
15637ed4 | 194 | if (regexec(re, &line[pos], (pos == 0))) |
6e657cf2 | 195 | #endif |
15637ed4 RG |
196 | { |
197 | /* match! */ | |
198 | if (wrapped && *o_warn) | |
199 | msg("(wrapped)"); | |
200 | #ifndef CRUNCH | |
201 | if (delta != INFINITY) | |
202 | { | |
203 | l += delta; | |
204 | if (l < 1 || l > nlines) | |
205 | { | |
206 | msg("search offset too big"); | |
207 | return MARK_UNSET; | |
208 | } | |
209 | force_flags = LNMD|INCL; | |
210 | return MARK_AT_LINE(l); | |
211 | } | |
212 | #endif | |
6e657cf2 AM |
213 | #ifdef REGEX |
214 | return MARK_AT_LINE(l) + pos + rm[0].rm_so; | |
215 | #else | |
15637ed4 | 216 | return MARK_AT_LINE(l) + (int)(re->startp[0] - line); |
6e657cf2 | 217 | #endif |
15637ed4 RG |
218 | } |
219 | pos = 0; | |
220 | } | |
221 | ||
222 | /* not found */ | |
223 | msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE"); | |
224 | return MARK_UNSET; | |
225 | } | |
226 | ||
227 | MARK m_bsrch(m, ptrn) | |
228 | MARK m; /* where to start searching */ | |
229 | char *ptrn; /* pattern to search for */ | |
230 | { | |
231 | long l; /* line# of line to be searched */ | |
232 | char *line; /* text of line to be searched */ | |
233 | int wrapped;/* boolean: has our search wrapped yet? */ | |
234 | int pos; /* last acceptable idx for a match on this line */ | |
235 | int last; /* remembered idx of the last acceptable match on this line */ | |
236 | int try; /* an idx at which we strat searching for another match */ | |
6e657cf2 AM |
237 | #ifdef REGEX |
238 | regex_t *optpat(); | |
239 | regmatch_t rm[SE_MAX]; | |
240 | int n; | |
241 | #endif | |
15637ed4 RG |
242 | #ifndef CRUNCH |
243 | long delta = INFINITY;/* line offset, for things like "/foo/+1" */ | |
244 | #endif | |
245 | ||
246 | /* remember: "previous search was not forward" */ | |
247 | prevsf = FALSE; | |
248 | ||
249 | if (ptrn && *ptrn) | |
250 | { | |
251 | /* locate the closing '?', if any */ | |
252 | line = parseptrn(ptrn); | |
253 | #ifndef CRUNCH | |
254 | if (*line) | |
255 | { | |
256 | delta = atol(line); | |
257 | } | |
258 | #endif | |
259 | ptrn++; | |
260 | ||
6e657cf2 AM |
261 | #ifdef REGEX |
262 | /* XXX where to free re? */ | |
263 | re = optpat(ptrn); | |
264 | #else | |
15637ed4 | 265 | /* free the previous pattern, if any */ |
08746e8b | 266 | if (re) _free_(re); |
15637ed4 RG |
267 | |
268 | /* compile the pattern */ | |
269 | re = regcomp(ptrn); | |
474a73df | 270 | #endif |
15637ed4 RG |
271 | if (!re) |
272 | { | |
273 | return MARK_UNSET; | |
274 | } | |
275 | } | |
276 | else if (!re) | |
277 | { | |
278 | msg("No previous expression"); | |
279 | return MARK_UNSET; | |
280 | } | |
281 | ||
282 | /* search backward for the pattern */ | |
283 | pos = markidx(m); | |
284 | wrapped = FALSE; | |
285 | for (l = markline(m); l != markline(m) - 1 || !wrapped; l--) | |
286 | { | |
287 | /* wrap search */ | |
288 | if (l < 1) | |
289 | { | |
290 | if (*o_wrapscan) | |
291 | { | |
292 | l = nlines + 1; | |
293 | wrapped = TRUE; | |
294 | continue; | |
295 | } | |
296 | else | |
297 | { | |
298 | break; | |
299 | } | |
300 | } | |
301 | ||
302 | /* get this line */ | |
303 | line = fetchline(l); | |
304 | ||
305 | /* check this line */ | |
6e657cf2 AM |
306 | #ifdef REGEX |
307 | if (!regexec(re, line, SE_MAX, rm, 0) && rm[0].rm_so < pos) | |
308 | #else | |
15637ed4 | 309 | if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos) |
6e657cf2 | 310 | #endif |
15637ed4 | 311 | { |
8a144d75 | 312 | try = 0; |
15637ed4 RG |
313 | /* match! now find the last acceptable one in this line */ |
314 | do | |
315 | { | |
6e657cf2 | 316 | #ifdef REGEX |
8a144d75 AM |
317 | last = try + rm[0].rm_so; |
318 | try += rm[0].rm_eo; | |
6e657cf2 | 319 | #else |
15637ed4 RG |
320 | last = (int)(re->startp[0] - line); |
321 | try = (int)(re->endp[0] - line); | |
6e657cf2 | 322 | #endif |
15637ed4 | 323 | } while (try > 0 |
6e657cf2 AM |
324 | #ifdef REGEX |
325 | && !regexec(re, &line[try], SE_MAX, rm, REG_NOTBOL) | |
326 | && try + rm[0].rm_so < pos); | |
327 | #else | |
15637ed4 RG |
328 | && regexec(re, &line[try], FALSE) |
329 | && (int)(re->startp[0] - line) < pos); | |
6e657cf2 | 330 | #endif |
15637ed4 RG |
331 | |
332 | if (wrapped && *o_warn) | |
333 | msg("(wrapped)"); | |
334 | #ifndef CRUNCH | |
335 | if (delta != INFINITY) | |
336 | { | |
337 | l += delta; | |
338 | if (l < 1 || l > nlines) | |
339 | { | |
340 | msg("search offset too big"); | |
341 | return MARK_UNSET; | |
342 | } | |
343 | force_flags = LNMD|INCL; | |
344 | return MARK_AT_LINE(l); | |
345 | } | |
346 | #endif | |
347 | return MARK_AT_LINE(l) + last; | |
348 | } | |
349 | pos = BLKSIZE; | |
350 | } | |
351 | ||
352 | /* not found */ | |
353 | msg(*o_wrapscan ? "Not found" : "Hit top without finding RE"); | |
354 | return MARK_UNSET; | |
355 | } | |
356 |