discard the old line before updating the screen so that the line
[nvi.git] / vi / v_search.c
blob89d5999dbbe6dd5f753eeb6aad13947fdab2858c
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: v_search.c,v 8.16 1993/12/09 19:43:18 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:43:18 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include "vi.h"
19 #include "vcmd.h"
21 static int bcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
22 static int fcorrect __P((SCR *, EXF *, VICMDARG *, MARK *, MARK *, u_int));
23 static int getptrn __P((SCR *, EXF *, int, char **));
26 * v_searchn -- n
27 * Repeat last search.
29 int
30 v_searchn(sp, ep, vp, fm, tm, rp)
31 SCR *sp;
32 EXF *ep;
33 VICMDARG *vp;
34 MARK *fm, *tm, *rp;
36 int flags;
38 flags = SEARCH_MSG;
39 if (F_ISSET(vp, VC_C | VC_D | VC_Y))
40 flags |= SEARCH_EOL;
41 switch (sp->searchdir) {
42 case BACKWARD:
43 if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
44 return (1);
45 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
46 bcorrect(sp, ep, vp, fm, rp, flags))
47 return (1);
48 break;
49 case FORWARD:
50 if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
51 return (1);
52 if (F_ISSET(vp, VC_C | VC_D | VC_Y| VC_SH) &&
53 fcorrect(sp, ep, vp, fm, rp, flags))
54 return (1);
55 break;
56 case NOTSET:
57 msgq(sp, M_ERR, "No previous search pattern.");
58 return (1);
59 default:
60 abort();
62 return (0);
66 * v_searchN -- N
67 * Reverse last search.
69 int
70 v_searchN(sp, ep, vp, fm, tm, rp)
71 SCR *sp;
72 EXF *ep;
73 VICMDARG *vp;
74 MARK *fm, *tm, *rp;
76 int flags;
78 flags = SEARCH_MSG;
79 if (F_ISSET(vp, VC_C | VC_D | VC_Y))
80 flags |= SEARCH_EOL;
81 switch (sp->searchdir) {
82 case BACKWARD:
83 if (f_search(sp, ep, fm, rp, NULL, NULL, &flags))
84 return (1);
85 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
86 fcorrect(sp, ep, vp, fm, rp, flags))
87 return (1);
88 break;
89 case FORWARD:
90 if (b_search(sp, ep, fm, rp, NULL, NULL, &flags))
91 return (1);
92 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
93 bcorrect(sp, ep, vp, fm, rp, flags))
94 return (1);
95 break;
96 case NOTSET:
97 msgq(sp, M_ERR, "No previous search pattern.");
98 return (1);
99 default:
100 abort();
102 return (0);
106 * v_searchw -- [count]^A
107 * Search for the word under the cursor.
110 v_searchw(sp, ep, vp, fm, tm, rp)
111 SCR *sp;
112 EXF *ep;
113 VICMDARG *vp;
114 MARK *fm, *tm, *rp;
116 size_t blen, len;
117 u_int flags;
118 int rval;
119 char *bp;
121 len = vp->kbuflen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
122 GET_SPACE_RET(sp, bp, blen, len);
123 (void)snprintf(bp, blen, "%s%s%s", RE_WSTART, vp->keyword, RE_WSTOP);
125 flags = SEARCH_MSG;
126 rval = f_search(sp, ep, fm, rp, bp, NULL, &flags);
128 FREE_SPACE(sp, bp, blen);
129 if (rval)
130 return (1);
131 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
132 fcorrect(sp, ep, vp, fm, rp, flags))
133 return (1);
134 return (0);
138 * v_searchb -- [count]?RE[? offset]
139 * Search backward.
142 v_searchb(sp, ep, vp, fm, tm, rp)
143 SCR *sp;
144 EXF *ep;
145 VICMDARG *vp;
146 MARK *fm, *tm, *rp;
148 int flags;
149 char *ptrn;
151 if (F_ISSET(vp, VC_ISDOT))
152 ptrn = NULL;
153 else {
154 if (getptrn(sp, ep, '?', &ptrn))
155 return (1);
156 if (ptrn == NULL)
157 return (0);
160 flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
161 if (F_ISSET(vp, VC_C | VC_D | VC_Y))
162 flags |= SEARCH_EOL;
163 if (b_search(sp, ep, fm, rp, ptrn, NULL, &flags))
164 return (1);
165 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
166 bcorrect(sp, ep, vp, fm, rp, flags))
167 return (1);
168 return (0);
172 * v_searchf -- [count]/RE[/ offset]
173 * Search forward.
176 v_searchf(sp, ep, vp, fm, tm, rp)
177 SCR *sp;
178 EXF *ep;
179 VICMDARG *vp;
180 MARK *fm, *tm, *rp;
182 int flags;
183 char *ptrn;
185 if (F_ISSET(vp, VC_ISDOT))
186 ptrn = NULL;
187 else {
188 if (getptrn(sp, ep, '/', &ptrn))
189 return (1);
190 if (ptrn == NULL)
191 return (0);
194 flags = SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | SEARCH_TERM;
195 if (F_ISSET(vp, VC_C | VC_D | VC_Y))
196 flags |= SEARCH_EOL;
197 if (f_search(sp, ep, fm, rp, ptrn, NULL, &flags))
198 return (1);
199 if (F_ISSET(vp, VC_C | VC_D | VC_Y | VC_SH) &&
200 fcorrect(sp, ep, vp, fm, rp, flags))
201 return (1);
202 return (0);
206 * getptrn --
207 * Get the search pattern.
209 static int
210 getptrn(sp, ep, prompt, storep)
211 SCR *sp;
212 EXF *ep;
213 int prompt;
214 char **storep;
216 TEXT *tp;
218 if (sp->s_get(sp, ep, &sp->tiq, prompt,
219 TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT) != INP_OK)
220 return (1);
222 /* Len is 0 if backspaced over the prompt, 1 if only CR entered. */
223 tp = sp->tiq.cqh_first;
224 if (tp->len == 0)
225 *storep = NULL;
226 else
227 *storep = tp->lb;
228 return (0);
232 * !!!
233 * Historically, commands didn't affect the line searched to if the motion
234 * command was a search and the pattern match was the start or end of the
235 * line. There were some special cases, however, concerning search to the
236 * start of end of a line.
238 * Vi was not, however, consistent, and it was fairly easy to confuse it.
239 * For example, given the two lines:
241 * abcdefghi
242 * ABCDEFGHI
244 * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
245 * 'k' and put would no longer work correctly. In any case, we try to do
246 * the right thing, but it's not likely exactly match historic practice.
250 * bcorrect --
251 * Handle command with a backward search as the motion.
253 static int
254 bcorrect(sp, ep, vp, fm, rp, flags)
255 SCR *sp;
256 EXF *ep;
257 VICMDARG *vp;
258 MARK *fm, *rp;
259 u_int flags;
261 size_t len;
262 char *p;
265 * !!!
266 * Correct backward searches which start at column 0 to be one
267 * past the last column of the previous line.
269 * Backward searches become line mode operations if they start
270 * at column 0 and end at column 0 of another line.
272 if (fm->lno > rp->lno && fm->cno == 0) {
273 if ((p = file_gline(sp, ep, --fm->lno, &len)) == NULL) {
274 GETLINE_ERR(sp, rp->lno);
275 return (1);
277 if (rp->cno == 0)
278 F_SET(vp, VC_LMODE);
279 fm->cno = len;
283 * !!!
284 * Commands would become line mode operations if there was a delta
285 * specified to the search pattern.
287 if (LF_ISSET(SEARCH_DELTA)) {
288 F_SET(vp, VC_LMODE);
289 return (0);
291 return (0);
295 * fcorrect --
296 * Handle command with a forward search as the motion.
298 static int
299 fcorrect(sp, ep, vp, fm, rp, flags)
300 SCR *sp;
301 EXF *ep;
302 VICMDARG *vp;
303 MARK *fm, *rp;
304 u_int flags;
306 size_t len;
307 char *p;
310 * !!!
311 * Correct forward searches which end at column 0 to be one
312 * past the last column of the previous line.
314 * Forward searches become line mode operations if they start
315 * at column 0 and end at column 0 of another line.
317 if (fm->lno < rp->lno && rp->cno == 0) {
318 if ((p = file_gline(sp, ep, --rp->lno, &len)) == NULL) {
319 GETLINE_ERR(sp, rp->lno);
320 return (1);
322 if (fm->cno == 0)
323 F_SET(vp, VC_LMODE);
324 rp->cno = len;
328 * !!!
329 * Commands would become line mode operations if there was a delta
330 * specified to the search pattern.
332 if (LF_ISSET(SEARCH_DELTA)) {
333 F_SET(vp, VC_LMODE);
334 return (0);
337 return (0);