only clean out gs when last window goes
[nvi.git] / vi / v_search.c
blob38c9128d25df8c7e19a6ecd407d2393344363df6
1 /*-
2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: v_search.c,v 10.24 2000/06/25 17:34:41 skimo Exp $ (Berkeley) $Date: 2000/06/25 17:34:41 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include "../common/common.h"
29 #include "vi.h"
30 #include "../ipc/ip.h"
32 static int v_exaddr __P((SCR *, VICMD *, dir_t));
33 static int v_search __P((SCR *, VICMD *, char *, size_t, u_int, dir_t));
36 * v_srch -- [count]?RE[? offset]
37 * Ex address search backward.
39 * PUBLIC: int v_searchb __P((SCR *, VICMD *));
41 int
42 v_searchb(sp, vp)
43 SCR *sp;
44 VICMD *vp;
46 return (v_exaddr(sp, vp, BACKWARD));
50 * v_searchf -- [count]/RE[/ offset]
51 * Ex address search forward.
53 * PUBLIC: int v_searchf __P((SCR *, VICMD *));
55 int
56 v_searchf(sp, vp)
57 SCR *sp;
58 VICMD *vp;
60 return (v_exaddr(sp, vp, FORWARD));
64 * v_exaddr --
65 * Do a vi search (which is really an ex address).
67 static int
68 v_exaddr(sp, vp, dir)
69 SCR *sp;
70 VICMD *vp;
71 dir_t dir;
73 static EXCMDLIST fake = { "search" };
74 EXCMD *cmdp;
75 WIN *wp;
76 TEXT *tp;
77 db_recno_t s_lno;
78 size_t len, s_cno, tlen;
79 int err, nb, type;
80 char *cmd, *t, buf[20];
83 * !!!
84 * If using the search command as a motion, any addressing components
85 * are lost, i.e. y/ptrn/+2, when repeated, is the same as y/ptrn/.
87 if (F_ISSET(vp, VC_ISDOT))
88 return (v_search(sp, vp,
89 NULL, 0, SEARCH_PARSE | SEARCH_MSG | SEARCH_SET, dir));
91 /* Get the search pattern. */
92 if (v_tcmd(sp, vp, dir == BACKWARD ? CH_BSEARCH : CH_FSEARCH,
93 TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT |
94 (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0)))
95 return (1);
97 tp = sp->tiq.cqh_first;
99 /* If the user backspaced over the prompt, do nothing. */
100 if (tp->term == TERM_BS)
101 return (1);
104 * If the user was doing an incremental search, then we've already
105 * updated the cursor and moved to the right location. Return the
106 * correct values, we're done.
108 if (tp->term == TERM_SEARCH) {
109 vp->m_stop.lno = sp->lno;
110 vp->m_stop.cno = sp->cno;
111 if (ISMOTION(vp))
112 return (v_correct(sp, vp, 0));
113 vp->m_final = vp->m_stop;
114 return (0);
118 * If the user entered <escape> or <carriage-return>, the length is
119 * 1 and the right thing will happen, i.e. the prompt will be used
120 * as a command character.
122 * Build a fake ex command structure.
124 wp = sp->wp;
125 wp->excmd.cp = tp->lb;
126 wp->excmd.clen = tp->len;
127 F_INIT(&wp->excmd, E_VISEARCH);
130 * XXX
131 * Warn if the search wraps. This is a pretty special case, but it's
132 * nice feature that wasn't in the original implementations of ex/vi.
133 * (It was added at some point to System V's version.) This message
134 * is only displayed if there are no keys in the queue. The problem is
135 * the command is going to succeed, and the message is informational,
136 * not an error. If a macro displays it repeatedly, e.g., the pattern
137 * only occurs once in the file and wrapscan is set, you lose big. For
138 * example, if the macro does something like:
140 * :map K /pattern/^MjK
142 * Each search will display the message, but the following "/pattern/"
143 * will immediately overwrite it, with strange results. The System V
144 * vi displays the "wrapped" message multiple times, but because it's
145 * overwritten each time, it's not as noticeable. As we don't discard
146 * messages, it's a real problem for us.
148 if (!KEYS_WAITING(sp))
149 F_SET(&wp->excmd, E_SEARCH_WMSG);
151 /* Save the current line/column. */
152 s_lno = sp->lno;
153 s_cno = sp->cno;
156 * !!!
157 * Historically, vi / and ? commands were full-blown ex addresses,
158 * including ';' delimiters, trailing <blank>'s, multiple search
159 * strings (separated by semi-colons) and, finally, full-blown z
160 * commands after the / and ? search strings. (If the search was
161 * being used as a motion, the trailing z command was ignored.
162 * Also, we do some argument checking on the z command, to be sure
163 * that it's not some other random command.) For multiple search
164 * strings, leading <blank>'s at the second and subsequent strings
165 * were eaten as well. This has some (unintended?) side-effects:
166 * the command /ptrn/;3 is legal and results in moving to line 3.
167 * I suppose you could use it to optionally move to line 3...
169 * !!!
170 * Historically, if any part of the search command failed, the cursor
171 * remained unmodified (even if ; was used). We have to play games
172 * because the underlying ex parser thinks we're modifying the cursor
173 * as we go, but I think we're compatible with historic practice.
175 * !!!
176 * Historically, the command "/STRING/; " failed, apparently it
177 * confused the parser. We're not that compatible.
179 cmdp = &wp->excmd;
180 if (ex_range(sp, cmdp, &err))
181 return (1);
184 * Remember where any remaining command information is, and clean
185 * up the fake ex command.
187 cmd = cmdp->cp;
188 len = cmdp->clen;
189 wp->excmd.clen = 0;
191 if (err)
192 goto err2;
194 /* Copy out the new cursor position and make sure it's okay. */
195 switch (cmdp->addrcnt) {
196 case 1:
197 vp->m_stop = cmdp->addr1;
198 break;
199 case 2:
200 vp->m_stop = cmdp->addr2;
201 break;
203 if (!db_exist(sp, vp->m_stop.lno)) {
204 ex_badaddr(sp, &fake,
205 vp->m_stop.lno == 0 ? A_ZERO : A_EOF, NUM_OK);
206 goto err2;
210 * !!!
211 * Historic practice is that a trailing 'z' was ignored if it was a
212 * motion command. Should probably be an error, but not worth the
213 * effort.
215 if (ISMOTION(vp))
216 return (v_correct(sp, vp, F_ISSET(cmdp, E_DELTA)));
219 * !!!
220 * Historically, if it wasn't a motion command, a delta in the search
221 * pattern turns it into a first nonblank movement.
223 nb = F_ISSET(cmdp, E_DELTA);
225 /* Check for the 'z' command. */
226 if (len != 0) {
227 if (*cmd != 'z')
228 goto err1;
230 /* No blanks, just like the z command. */
231 for (t = cmd + 1, tlen = len - 1; tlen > 0; ++t, --tlen)
232 if (!isdigit(*t))
233 break;
234 if (tlen &&
235 (*t == '-' || *t == '.' || *t == '+' || *t == '^')) {
236 ++t;
237 --tlen;
238 type = 1;
239 } else
240 type = 0;
241 if (tlen)
242 goto err1;
244 /* The z command will do the nonblank for us. */
245 nb = 0;
247 /* Default to z+. */
248 if (!type &&
249 v_event_push(sp, NULL, "+", 1, CH_NOMAP | CH_QUOTED))
250 return (1);
252 /* Push the user's command. */
253 if (v_event_push(sp, NULL, cmd, len, CH_NOMAP | CH_QUOTED))
254 return (1);
256 /* Push line number so get correct z display. */
257 tlen = snprintf(buf,
258 sizeof(buf), "%lu", (u_long)vp->m_stop.lno);
259 if (v_event_push(sp, NULL, buf, tlen, CH_NOMAP | CH_QUOTED))
260 return (1);
262 /* Don't refresh until after 'z' happens. */
263 F_SET(VIP(sp), VIP_S_REFRESH);
266 /* Non-motion commands move to the end of the range. */
267 vp->m_final = vp->m_stop;
268 if (nb) {
269 F_CLR(vp, VM_RCM_MASK);
270 F_SET(vp, VM_RCM_SETFNB);
272 return (0);
274 err1: msgq(sp, M_ERR,
275 "188|Characters after search string, line offset and/or z command");
276 err2: vp->m_final.lno = s_lno;
277 vp->m_final.cno = s_cno;
278 return (1);
282 * v_searchN -- N
283 * Reverse last search.
285 * PUBLIC: int v_searchN __P((SCR *, VICMD *));
288 v_searchN(sp, vp)
289 SCR *sp;
290 VICMD *vp;
292 dir_t dir;
294 switch (sp->searchdir) {
295 case BACKWARD:
296 dir = FORWARD;
297 break;
298 case FORWARD:
299 dir = BACKWARD;
300 break;
301 default:
302 dir = sp->searchdir;
303 break;
305 return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, dir));
309 * v_searchn -- n
310 * Repeat last search.
312 * PUBLIC: int v_searchn __P((SCR *, VICMD *));
315 v_searchn(sp, vp)
316 SCR *sp;
317 VICMD *vp;
319 return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir));
323 * v_searchw -- [count]^A
324 * Search for the word under the cursor.
326 * PUBLIC: int v_searchw __P((SCR *, VICMD *));
329 v_searchw(sp, vp)
330 SCR *sp;
331 VICMD *vp;
333 size_t blen, len;
334 int rval;
335 char *bp;
337 len = VIP(sp)->klen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
338 GET_SPACE_RET(sp, bp, blen, len);
339 len = snprintf(bp, blen, "%s%s%s", RE_WSTART, VIP(sp)->keyw, RE_WSTOP);
341 rval = v_search(sp, vp, bp, len, SEARCH_SET, FORWARD);
343 FREE_SPACE(sp, bp, blen);
344 return (rval);
348 * v_esearch -- <dialog box>
349 * Search command from the screen.
351 * PUBLIC: int v_esearch __P((SCR *, VICMD *));
354 v_esearch(sp, vp)
355 SCR *sp;
356 VICMD *vp;
358 MARK m;
359 int flags;
361 m.lno = sp->lno;
362 m.cno = sp->cno;
364 LF_INIT(SEARCH_NOOPT);
365 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_EXT))
366 LF_SET(SEARCH_EXTEND);
367 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_IC))
368 LF_SET(SEARCH_IC);
369 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_ICL))
370 LF_SET(SEARCH_ICL);
371 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_INCR))
372 LF_SET(SEARCH_INCR);
373 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_LIT))
374 LF_SET(SEARCH_LITERAL);
375 if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_WR))
376 LF_SET(SEARCH_WRAP);
377 return (v_search(sp, vp, vp->ev.e_csp, vp->ev.e_len, flags,
378 FL_ISSET(vp->ev.e_flags, VI_SEARCH_REV) ? BACKWARD : FORWARD));
382 * v_search --
383 * The search commands.
385 static int
386 v_search(sp, vp, ptrn, plen, flags, dir)
387 SCR *sp;
388 VICMD *vp;
389 u_int flags;
390 char *ptrn;
391 size_t plen;
392 dir_t dir;
394 /* Display messages. */
395 LF_SET(SEARCH_MSG);
397 /* If it's a motion search, offset past end-of-line is okay. */
398 if (ISMOTION(vp))
399 LF_SET(SEARCH_EOL);
402 * XXX
403 * Warn if the search wraps. See the comment above, in v_exaddr().
405 if (!KEYS_WAITING(sp))
406 LF_SET(SEARCH_WMSG);
408 switch (dir) {
409 case BACKWARD:
410 if (b_search(sp,
411 &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
412 return (1);
413 break;
414 case FORWARD:
415 if (f_search(sp,
416 &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
417 return (1);
418 break;
419 case NOTSET:
420 msgq(sp, M_ERR, "189|No previous search pattern");
421 return (1);
422 default:
423 abort();
426 /* Correct motion commands, otherwise, simply move to the location. */
427 if (ISMOTION(vp)) {
428 if (v_correct(sp, vp, 0))
429 return(1);
430 } else
431 vp->m_final = vp->m_stop;
432 return (0);
436 * v_correct --
437 * Handle command with a search as the motion.
439 * !!!
440 * Historically, commands didn't affect the line searched to/from if the
441 * motion command was a search and the final position was the start/end
442 * of the line. There were some special cases and vi was not consistent;
443 * it was fairly easy to confuse it. For example, given the two lines:
445 * abcdefghi
446 * ABCDEFGHI
448 * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
449 * 'k' and put would no longer work correctly. In any case, we try to do
450 * the right thing, but it's not going to exactly match historic practice.
452 * PUBLIC: int v_correct __P((SCR *, VICMD *, int));
455 v_correct(sp, vp, isdelta)
456 SCR *sp;
457 VICMD *vp;
458 int isdelta;
460 dir_t dir;
461 MARK m;
462 size_t len;
465 * !!!
466 * We may have wrapped if wrapscan was set, and we may have returned
467 * to the position where the cursor started. Historic vi didn't cope
468 * with this well. Yank wouldn't beep, but the first put after the
469 * yank would move the cursor right one column (without adding any
470 * text) and the second would put a copy of the current line. The
471 * change and delete commands would beep, but would leave the cursor
472 * on the colon command line. I believe that there are macros that
473 * depend on delete, at least, failing. For now, commands that use
474 * search as a motion component fail when the search returns to the
475 * original cursor position.
477 if (vp->m_start.lno == vp->m_stop.lno &&
478 vp->m_start.cno == vp->m_stop.cno) {
479 msgq(sp, M_BERR, "190|Search wrapped to original position");
480 return (1);
484 * !!!
485 * Searches become line mode operations if there was a delta specified
486 * to the search pattern.
488 if (isdelta)
489 F_SET(vp, VM_LMODE);
492 * If the motion is in the reverse direction, switch the start and
493 * stop MARK's so that it's in a forward direction. (There's no
494 * reason for this other than to make the tests below easier. The
495 * code in vi.c:vi() would have done the switch.) Both forward
496 * and backward motions can happen for any kind of search command
497 * because of the wrapscan option.
499 if (vp->m_start.lno > vp->m_stop.lno ||
500 vp->m_start.lno == vp->m_stop.lno &&
501 vp->m_start.cno > vp->m_stop.cno) {
502 m = vp->m_start;
503 vp->m_start = vp->m_stop;
504 vp->m_stop = m;
505 dir = BACKWARD;
506 } else
507 dir = FORWARD;
510 * BACKWARD:
511 * Delete and yank commands move to the end of the range.
512 * Ignore others.
514 * FORWARD:
515 * Delete and yank commands don't move. Ignore others.
517 vp->m_final = vp->m_start;
520 * !!!
521 * Delta'd searches don't correct based on column positions.
523 if (isdelta)
524 return (0);
527 * !!!
528 * Backward searches starting at column 0, and forward searches ending
529 * at column 0 are corrected to the last column of the previous line.
530 * Otherwise, adjust the starting/ending point to the character before
531 * the current one (this is safe because we know the search had to move
532 * to succeed).
534 * Searches become line mode operations if they start at the first
535 * nonblank and end at column 0 of another line.
537 if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
538 if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
539 return (1);
540 vp->m_stop.cno = len ? len - 1 : 0;
541 len = 0;
542 if (nonblank(sp, vp->m_start.lno, &len))
543 return (1);
544 if (vp->m_start.cno <= len)
545 F_SET(vp, VM_LMODE);
546 } else
547 --vp->m_stop.cno;
549 return (0);