xref: /openbsd/usr.bin/vi/vi/v_search.c (revision a0b15055)
1 /*	$OpenBSD: v_search.c,v 1.14 2016/01/06 22:28:52 millert Exp $	*/
2 
3 /*-
4  * Copyright (c) 1992, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1992, 1993, 1994, 1995, 1996
7  *	Keith Bostic.  All rights reserved.
8  *
9  * See the LICENSE file for redistribution information.
10  */
11 
12 #include "config.h"
13 
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
17 
18 #include <bitstring.h>
19 #include <ctype.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "../common/common.h"
27 #include "vi.h"
28 
29 static int v_exaddr(SCR *, VICMD *, dir_t);
30 static int v_search(SCR *, VICMD *, char *, size_t, u_int, dir_t);
31 
32 /*
33  * v_srch -- [count]?RE[? offset]
34  *	Ex address search backward.
35  *
36  * PUBLIC: int v_searchb(SCR *, VICMD *);
37  */
38 int
v_searchb(SCR * sp,VICMD * vp)39 v_searchb(SCR *sp, VICMD *vp)
40 {
41 	return (v_exaddr(sp, vp, BACKWARD));
42 }
43 
44 /*
45  * v_searchf -- [count]/RE[/ offset]
46  *	Ex address search forward.
47  *
48  * PUBLIC: int v_searchf(SCR *, VICMD *);
49  */
50 int
v_searchf(SCR * sp,VICMD * vp)51 v_searchf(SCR *sp, VICMD *vp)
52 {
53 	return (v_exaddr(sp, vp, FORWARD));
54 }
55 
56 /*
57  * v_exaddr --
58  *	Do a vi search (which is really an ex address).
59  */
60 static int
v_exaddr(SCR * sp,VICMD * vp,dir_t dir)61 v_exaddr(SCR *sp, VICMD *vp, dir_t dir)
62 {
63 	static EXCMDLIST fake = { "search" };
64 	EXCMD *cmdp;
65 	GS *gp;
66 	TEXT *tp;
67 	recno_t s_lno;
68 	size_t len, s_cno, tlen;
69 	int err, nb, type;
70 	char *cmd, *t, buf[20];
71 
72 	/*
73 	 * !!!
74 	 * If using the search command as a motion, any addressing components
75 	 * are lost, i.e. y/ptrn/+2, when repeated, is the same as y/ptrn/.
76 	 */
77 	if (F_ISSET(vp, VC_ISDOT))
78 		return (v_search(sp, vp,
79 		    NULL, 0, SEARCH_PARSE | SEARCH_MSG | SEARCH_SET, dir));
80 
81 	/* Get the search pattern. */
82 	if (v_tcmd(sp, vp, dir == BACKWARD ? CH_BSEARCH : CH_FSEARCH,
83 	    TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT |
84 	    (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0)))
85 		return (1);
86 
87 	tp = TAILQ_FIRST(&sp->tiq);
88 
89 	/* If the user backspaced over the prompt, do nothing. */
90 	if (tp->term == TERM_BS)
91 		return (1);
92 
93 	/*
94 	 * If the user was doing an incremental search, then we've already
95 	 * updated the cursor and moved to the right location.  Return the
96 	 * correct values, we're done.
97 	 */
98 	if (tp->term == TERM_SEARCH) {
99 		vp->m_stop.lno = sp->lno;
100 		vp->m_stop.cno = sp->cno;
101 		if (ISMOTION(vp))
102 			return (v_correct(sp, vp, 0));
103 		vp->m_final = vp->m_stop;
104 		return (0);
105 	}
106 
107 	/*
108 	 * If the user entered <escape> or <carriage-return>, the length is
109 	 * 1 and the right thing will happen, i.e. the prompt will be used
110 	 * as a command character.
111 	 *
112 	 * Build a fake ex command structure.
113 	 */
114 	gp = sp->gp;
115 	gp->excmd.cp = tp->lb;
116 	gp->excmd.clen = tp->len;
117 	F_INIT(&gp->excmd, E_VISEARCH);
118 
119 	/*
120 	 * XXX
121 	 * Warn if the search wraps.  This is a pretty special case, but it's
122 	 * nice feature that wasn't in the original implementations of ex/vi.
123 	 * (It was added at some point to System V's version.)  This message
124 	 * is only displayed if there are no keys in the queue. The problem is
125 	 * the command is going to succeed, and the message is informational,
126 	 * not an error.  If a macro displays it repeatedly, e.g., the pattern
127 	 * only occurs once in the file and wrapscan is set, you lose big.  For
128 	 * example, if the macro does something like:
129 	 *
130 	 *	:map K /pattern/^MjK
131 	 *
132 	 * Each search will display the message, but the following "/pattern/"
133 	 * will immediately overwrite it, with strange results.  The System V
134 	 * vi displays the "wrapped" message multiple times, but because it's
135 	 * overwritten each time, it's not as noticeable.  As we don't discard
136 	 * messages, it's a real problem for us.
137 	 */
138 	if (!KEYS_WAITING(sp))
139 		F_SET(&gp->excmd, E_SEARCH_WMSG);
140 
141 	/* Save the current line/column. */
142 	s_lno = sp->lno;
143 	s_cno = sp->cno;
144 
145 	/*
146 	 * !!!
147 	 * Historically, vi / and ? commands were full-blown ex addresses,
148 	 * including ';' delimiters, trailing <blank>'s, multiple search
149 	 * strings (separated by semi-colons) and, finally, full-blown z
150 	 * commands after the / and ? search strings.  (If the search was
151 	 * being used as a motion, the trailing z command was ignored.
152 	 * Also, we do some argument checking on the z command, to be sure
153 	 * that it's not some other random command.) For multiple search
154 	 * strings, leading <blank>'s at the second and subsequent strings
155 	 * were eaten as well.  This has some (unintended?) side-effects:
156 	 * the command /ptrn/;3 is legal and results in moving to line 3.
157 	 * I suppose you could use it to optionally move to line 3...
158 	 *
159 	 * !!!
160 	 * Historically, if any part of the search command failed, the cursor
161 	 * remained unmodified (even if ; was used).  We have to play games
162 	 * because the underlying ex parser thinks we're modifying the cursor
163 	 * as we go, but I think we're compatible with historic practice.
164 	 *
165 	 * !!!
166 	 * Historically, the command "/STRING/;   " failed, apparently it
167 	 * confused the parser.  We're not that compatible.
168 	 */
169 	cmdp = &gp->excmd;
170 	if (ex_range(sp, cmdp, &err))
171 		return (1);
172 
173 	/*
174 	 * Remember where any remaining command information is, and clean
175 	 * up the fake ex command.
176 	 */
177 	cmd = cmdp->cp;
178 	len = cmdp->clen;
179 	gp->excmd.clen = 0;
180 
181 	if (err)
182 		goto err2;
183 
184 	/* Copy out the new cursor position and make sure it's okay. */
185 	switch (cmdp->addrcnt) {
186 	case 1:
187 		vp->m_stop = cmdp->addr1;
188 		break;
189 	case 2:
190 		vp->m_stop = cmdp->addr2;
191 		break;
192 	}
193 	if (!db_exist(sp, vp->m_stop.lno)) {
194 		ex_badaddr(sp, &fake,
195 		    vp->m_stop.lno == 0 ? A_ZERO : A_EOF, NUM_OK);
196 		goto err2;
197 	}
198 
199 	/*
200 	 * !!!
201 	 * Historic practice is that a trailing 'z' was ignored if it was a
202 	 * motion command.  Should probably be an error, but not worth the
203 	 * effort.
204 	 */
205 	if (ISMOTION(vp))
206 		return (v_correct(sp, vp, F_ISSET(cmdp, E_DELTA)));
207 
208 	/*
209 	 * !!!
210 	 * Historically, if it wasn't a motion command, a delta in the search
211 	 * pattern turns it into a first nonblank movement.
212 	 */
213 	nb = F_ISSET(cmdp, E_DELTA);
214 
215 	/* Check for the 'z' command. */
216 	if (len != 0) {
217 		if (*cmd != 'z')
218 			goto err1;
219 
220 		/* No blanks, just like the z command. */
221 		for (t = cmd + 1, tlen = len - 1; tlen > 0; ++t, --tlen)
222 			if (!isdigit(*t))
223 				break;
224 		if (tlen &&
225 		    (*t == '-' || *t == '.' || *t == '+' || *t == '^')) {
226 			++t;
227 			--tlen;
228 			type = 1;
229 		} else
230 			type = 0;
231 		if (tlen)
232 			goto err1;
233 
234 		/* The z command will do the nonblank for us. */
235 		nb = 0;
236 
237 		/* Default to z+. */
238 		if (!type &&
239 		    v_event_push(sp, NULL, "+", 1, CH_NOMAP | CH_QUOTED))
240 			return (1);
241 
242 		/* Push the user's command. */
243 		if (v_event_push(sp, NULL, cmd, len, CH_NOMAP | CH_QUOTED))
244 			return (1);
245 
246 		/* Push line number so get correct z display. */
247 		tlen = snprintf(buf,
248 		    sizeof(buf), "%lu", (u_long)vp->m_stop.lno);
249 		if (tlen >= sizeof(buf))
250 			tlen = sizeof(buf) - 1;
251 		if (v_event_push(sp, NULL, buf, tlen, CH_NOMAP | CH_QUOTED))
252 			return (1);
253 
254 		/* Don't refresh until after 'z' happens. */
255 		F_SET(VIP(sp), VIP_S_REFRESH);
256 	}
257 
258 	/* Non-motion commands move to the end of the range. */
259 	vp->m_final = vp->m_stop;
260 	if (nb) {
261 		F_CLR(vp, VM_RCM_MASK);
262 		F_SET(vp, VM_RCM_SETFNB);
263 	}
264 	return (0);
265 
266 err1:	msgq(sp, M_ERR,
267 	    "Characters after search string, line offset and/or z command");
268 err2:	vp->m_final.lno = s_lno;
269 	vp->m_final.cno = s_cno;
270 	return (1);
271 }
272 
273 /*
274  * v_searchN -- N
275  *	Reverse last search.
276  *
277  * PUBLIC: int v_searchN(SCR *, VICMD *);
278  */
279 int
v_searchN(SCR * sp,VICMD * vp)280 v_searchN(SCR *sp, VICMD *vp)
281 {
282 	dir_t dir;
283 
284 	switch (sp->searchdir) {
285 	case BACKWARD:
286 		dir = FORWARD;
287 		break;
288 	case FORWARD:
289 		dir = BACKWARD;
290 		break;
291 	default:
292 		dir = sp->searchdir;
293 		break;
294 	}
295 	return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, dir));
296 }
297 
298 /*
299  * v_searchn -- n
300  *	Repeat last search.
301  *
302  * PUBLIC: int v_searchn(SCR *, VICMD *);
303  */
304 int
v_searchn(SCR * sp,VICMD * vp)305 v_searchn(SCR *sp, VICMD *vp)
306 {
307 	return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir));
308 }
309 
310 /*
311  * v_searchw -- [count]^A
312  *	Search for the word under the cursor.
313  *
314  * PUBLIC: int v_searchw(SCR *, VICMD *);
315  */
316 int
v_searchw(SCR * sp,VICMD * vp)317 v_searchw(SCR *sp, VICMD *vp)
318 {
319 	size_t blen, len;
320 	int rval;
321 	char *bp;
322 
323 	len = VIP(sp)->klen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
324 	GET_SPACE_RET(sp, bp, blen, len);
325 	len = snprintf(bp, blen, "%s%s%s", RE_WSTART, VIP(sp)->keyw, RE_WSTOP);
326 	if (len >= blen)
327 		len = blen - 1;
328 
329 	rval = v_search(sp, vp, bp, len, SEARCH_SET, FORWARD);
330 
331 	FREE_SPACE(sp, bp, blen);
332 	return (rval);
333 }
334 
335 /*
336  * v_search --
337  *	The search commands.
338  */
339 static int
v_search(SCR * sp,VICMD * vp,char * ptrn,size_t plen,u_int flags,dir_t dir)340 v_search(SCR *sp, VICMD *vp, char *ptrn, size_t plen, u_int flags, dir_t dir)
341 {
342 	/* Display messages. */
343 	LF_SET(SEARCH_MSG);
344 
345 	/* If it's a motion search, offset past end-of-line is okay. */
346 	if (ISMOTION(vp))
347 		LF_SET(SEARCH_EOL);
348 
349 	/*
350 	 * XXX
351 	 * Warn if the search wraps.  See the comment above, in v_exaddr().
352 	 */
353 	if (!KEYS_WAITING(sp))
354 		LF_SET(SEARCH_WMSG);
355 
356 	switch (dir) {
357 	case BACKWARD:
358 		if (b_search(sp,
359 		    &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
360 			return (1);
361 		break;
362 	case FORWARD:
363 		if (f_search(sp,
364 		    &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
365 			return (1);
366 		break;
367 	case NOTSET:
368 		msgq(sp, M_ERR, "No previous search pattern");
369 		return (1);
370 	default:
371 		abort();
372 	}
373 
374 	/* Correct motion commands, otherwise, simply move to the location. */
375 	if (ISMOTION(vp)) {
376 		if (v_correct(sp, vp, 0))
377 			return(1);
378 	} else
379 		vp->m_final = vp->m_stop;
380 	return (0);
381 }
382 
383 /*
384  * v_correct --
385  *	Handle command with a search as the motion.
386  *
387  * !!!
388  * Historically, commands didn't affect the line searched to/from if the
389  * motion command was a search and the final position was the start/end
390  * of the line.  There were some special cases and vi was not consistent;
391  * it was fairly easy to confuse it.  For example, given the two lines:
392  *
393  *	abcdefghi
394  *	ABCDEFGHI
395  *
396  * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
397  * 'k' and put would no longer work correctly.  In any case, we try to do
398  * the right thing, but it's not going to exactly match historic practice.
399  *
400  * PUBLIC: int v_correct(SCR *, VICMD *, int);
401  */
402 int
v_correct(SCR * sp,VICMD * vp,int isdelta)403 v_correct(SCR *sp, VICMD *vp, int isdelta)
404 {
405 	MARK m;
406 	size_t len;
407 
408 	/*
409 	 * !!!
410 	 * We may have wrapped if wrapscan was set, and we may have returned
411 	 * to the position where the cursor started.  Historic vi didn't cope
412 	 * with this well.  Yank wouldn't beep, but the first put after the
413 	 * yank would move the cursor right one column (without adding any
414 	 * text) and the second would put a copy of the current line.  The
415 	 * change and delete commands would beep, but would leave the cursor
416 	 * on the colon command line.  I believe that there are macros that
417 	 * depend on delete, at least, failing.  For now, commands that use
418 	 * search as a motion component fail when the search returns to the
419 	 * original cursor position.
420 	 */
421 	if (vp->m_start.lno == vp->m_stop.lno &&
422 	    vp->m_start.cno == vp->m_stop.cno) {
423 		msgq(sp, M_BERR, "Search wrapped to original position");
424 		return (1);
425 	}
426 
427 	/*
428 	 * !!!
429 	 * Searches become line mode operations if there was a delta specified
430 	 * to the search pattern.
431 	 */
432 	if (isdelta)
433 		F_SET(vp, VM_LMODE);
434 
435 	/*
436 	 * If the motion is in the reverse direction, switch the start and
437 	 * stop MARK's so that it's in a forward direction.  (There's no
438 	 * reason for this other than to make the tests below easier.  The
439 	 * code in vi.c:vi() would have done the switch.)  Both forward
440 	 * and backward motions can happen for any kind of search command
441 	 * because of the wrapscan option.
442 	 */
443 	if (vp->m_start.lno > vp->m_stop.lno ||
444 	    (vp->m_start.lno == vp->m_stop.lno &&
445 	    vp->m_start.cno > vp->m_stop.cno)) {
446 		m = vp->m_start;
447 		vp->m_start = vp->m_stop;
448 		vp->m_stop = m;
449 	}
450 
451 	/*
452 	 * BACKWARD:
453 	 *	Delete and yank commands move to the end of the range.
454 	 *	Ignore others.
455 	 *
456 	 * FORWARD:
457 	 *	Delete and yank commands don't move.  Ignore others.
458 	 */
459 	vp->m_final = vp->m_start;
460 
461 	/*
462 	 * !!!
463 	 * Delta'd searches don't correct based on column positions.
464 	 */
465 	if (isdelta)
466 		return (0);
467 
468 	/*
469 	 * !!!
470 	 * Backward searches starting at column 0, and forward searches ending
471 	 * at column 0 are corrected to the last column of the previous line.
472 	 * Otherwise, adjust the starting/ending point to the character before
473 	 * the current one (this is safe because we know the search had to move
474 	 * to succeed).
475 	 *
476 	 * Searches become line mode operations if they start at the first
477 	 * nonblank and end at column 0 of another line.
478 	 */
479 	if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
480 		if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
481 			return (1);
482 		vp->m_stop.cno = len ? len - 1 : 0;
483 		len = 0;
484 		if (nonblank(sp, vp->m_start.lno, &len))
485 			return (1);
486 		if (vp->m_start.cno <= len)
487 			F_SET(vp, VM_LMODE);
488 	} else
489 		--vp->m_stop.cno;
490 
491 	return (0);
492 }
493