This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / elvis / move2.c
CommitLineData
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
21extern long atol();
22
6e657cf2
AM
23#ifdef REGEX
24static regex_t *re = NULL; /* compiled version of the pattern to search for */
25#else
15637ed4 26static regexp *re; /* compiled version of the pattern to search for */
6e657cf2 27#endif
15637ed4
RG
28static prevsf; /* boolean: previous search direction was forward? */
29
30#ifndef NO_EXTENSIONS
31/*ARGSUSED*/
32MARK 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 55MARK 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
100MARK 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
227MARK 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