1*cc73507aSchristos /* $NetBSD: v_search.c,v 1.6 2014/01/26 21:43:45 christos Exp $ */
23a571abcSchristos /*-
33a571abcSchristos * Copyright (c) 1992, 1993, 1994
43a571abcSchristos * The Regents of the University of California. All rights reserved.
53a571abcSchristos * Copyright (c) 1992, 1993, 1994, 1995, 1996
63a571abcSchristos * Keith Bostic. All rights reserved.
73a571abcSchristos *
83a571abcSchristos * See the LICENSE file for redistribution information.
93a571abcSchristos */
103a571abcSchristos
113a571abcSchristos #include "config.h"
123a571abcSchristos
13*cc73507aSchristos #include <sys/cdefs.h>
14*cc73507aSchristos #if 0
153a571abcSchristos #ifndef lint
163a571abcSchristos static const char sccsid[] = "Id: v_search.c,v 10.30 2001/09/11 20:52:46 skimo Exp (Berkeley) Date: 2001/09/11 20:52:46 ";
173a571abcSchristos #endif /* not lint */
18*cc73507aSchristos #else
19*cc73507aSchristos __RCSID("$NetBSD: v_search.c,v 1.6 2014/01/26 21:43:45 christos Exp $");
20*cc73507aSchristos #endif
213a571abcSchristos
223a571abcSchristos #include <sys/types.h>
233a571abcSchristos #include <sys/queue.h>
243a571abcSchristos #include <sys/time.h>
253a571abcSchristos
263a571abcSchristos #include <bitstring.h>
273a571abcSchristos #include <ctype.h>
283a571abcSchristos #include <errno.h>
293a571abcSchristos #include <limits.h>
303a571abcSchristos #include <stdio.h>
313a571abcSchristos #include <stdlib.h>
323a571abcSchristos #include <string.h>
333a571abcSchristos
343a571abcSchristos #include "../common/common.h"
353a571abcSchristos #include "vi.h"
363a571abcSchristos #include "../ipc/ip.h"
373a571abcSchristos
383a571abcSchristos static int v_exaddr __P((SCR *, VICMD *, dir_t));
393a571abcSchristos static int v_search __P((SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t));
403a571abcSchristos
413a571abcSchristos /*
423a571abcSchristos * v_srch -- [count]?RE[? offset]
433a571abcSchristos * Ex address search backward.
443a571abcSchristos *
453a571abcSchristos * PUBLIC: int v_searchb __P((SCR *, VICMD *));
463a571abcSchristos */
473a571abcSchristos int
v_searchb(SCR * sp,VICMD * vp)483a571abcSchristos v_searchb(SCR *sp, VICMD *vp)
493a571abcSchristos {
503a571abcSchristos return (v_exaddr(sp, vp, BACKWARD));
513a571abcSchristos }
523a571abcSchristos
533a571abcSchristos /*
543a571abcSchristos * v_searchf -- [count]/RE[/ offset]
553a571abcSchristos * Ex address search forward.
563a571abcSchristos *
573a571abcSchristos * PUBLIC: int v_searchf __P((SCR *, VICMD *));
583a571abcSchristos */
593a571abcSchristos int
v_searchf(SCR * sp,VICMD * vp)603a571abcSchristos v_searchf(SCR *sp, VICMD *vp)
613a571abcSchristos {
623a571abcSchristos return (v_exaddr(sp, vp, FORWARD));
633a571abcSchristos }
643a571abcSchristos
653a571abcSchristos /*
663a571abcSchristos * v_exaddr --
673a571abcSchristos * Do a vi search (which is really an ex address).
683a571abcSchristos */
693a571abcSchristos static int
v_exaddr(SCR * sp,VICMD * vp,dir_t dir)703a571abcSchristos v_exaddr(SCR *sp, VICMD *vp, dir_t dir)
713a571abcSchristos {
7208d478e3Schristos static EXCMDLIST fake = { .name = L("search") };
733a571abcSchristos EXCMD *cmdp;
743a571abcSchristos WIN *wp;
753a571abcSchristos TEXT *tp;
763a571abcSchristos db_recno_t s_lno;
773a571abcSchristos size_t len, s_cno, tlen;
78defa1437Schristos int error, nb, type;
793a571abcSchristos char buf[20];
803a571abcSchristos CHAR_T *cmd, *t;
8108d478e3Schristos const CHAR_T *w;
823a571abcSchristos size_t wlen;
833a571abcSchristos
843a571abcSchristos /*
853a571abcSchristos * !!!
863a571abcSchristos * If using the search command as a motion, any addressing components
873a571abcSchristos * are lost, i.e. y/ptrn/+2, when repeated, is the same as y/ptrn/.
883a571abcSchristos */
893a571abcSchristos if (F_ISSET(vp, VC_ISDOT))
903a571abcSchristos return (v_search(sp, vp,
913a571abcSchristos NULL, 0, SEARCH_PARSE | SEARCH_MSG | SEARCH_SET, dir));
923a571abcSchristos
933a571abcSchristos /* Get the search pattern. */
943a571abcSchristos if (v_tcmd(sp, vp, dir == BACKWARD ? CH_BSEARCH : CH_FSEARCH,
953a571abcSchristos TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT |
963a571abcSchristos (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0)))
973a571abcSchristos return (1);
983a571abcSchristos
990b5c88f5Schristos tp = TAILQ_FIRST(&sp->tiq);
1003a571abcSchristos
1013a571abcSchristos /* If the user backspaced over the prompt, do nothing. */
1023a571abcSchristos if (tp->term == TERM_BS)
1033a571abcSchristos return (1);
1043a571abcSchristos
1053a571abcSchristos /*
1063a571abcSchristos * If the user was doing an incremental search, then we've already
1073a571abcSchristos * updated the cursor and moved to the right location. Return the
1083a571abcSchristos * correct values, we're done.
1093a571abcSchristos */
1103a571abcSchristos if (tp->term == TERM_SEARCH) {
1113a571abcSchristos vp->m_stop.lno = sp->lno;
1123a571abcSchristos vp->m_stop.cno = sp->cno;
1133a571abcSchristos if (ISMOTION(vp))
1143a571abcSchristos return (v_correct(sp, vp, 0));
1153a571abcSchristos vp->m_final = vp->m_stop;
1163a571abcSchristos return (0);
1173a571abcSchristos }
1183a571abcSchristos
1193a571abcSchristos /*
1203a571abcSchristos * If the user entered <escape> or <carriage-return>, the length is
1213a571abcSchristos * 1 and the right thing will happen, i.e. the prompt will be used
1223a571abcSchristos * as a command character.
1233a571abcSchristos *
1243a571abcSchristos * Build a fake ex command structure.
1253a571abcSchristos */
1263a571abcSchristos wp = sp->wp;
1273a571abcSchristos wp->excmd.cp = tp->lb;
1283a571abcSchristos wp->excmd.clen = tp->len;
1293a571abcSchristos F_INIT(&wp->excmd, E_VISEARCH);
1303a571abcSchristos
1313a571abcSchristos /*
1323a571abcSchristos * XXX
1333a571abcSchristos * Warn if the search wraps. This is a pretty special case, but it's
1343a571abcSchristos * nice feature that wasn't in the original implementations of ex/vi.
1353a571abcSchristos * (It was added at some point to System V's version.) This message
1363a571abcSchristos * is only displayed if there are no keys in the queue. The problem is
1373a571abcSchristos * the command is going to succeed, and the message is informational,
1383a571abcSchristos * not an error. If a macro displays it repeatedly, e.g., the pattern
1393a571abcSchristos * only occurs once in the file and wrapscan is set, you lose big. For
1403a571abcSchristos * example, if the macro does something like:
1413a571abcSchristos *
1423a571abcSchristos * :map K /pattern/^MjK
1433a571abcSchristos *
1443a571abcSchristos * Each search will display the message, but the following "/pattern/"
1453a571abcSchristos * will immediately overwrite it, with strange results. The System V
1463a571abcSchristos * vi displays the "wrapped" message multiple times, but because it's
1473a571abcSchristos * overwritten each time, it's not as noticeable. As we don't discard
1483a571abcSchristos * messages, it's a real problem for us.
1493a571abcSchristos */
1503a571abcSchristos if (!KEYS_WAITING(sp))
1513a571abcSchristos F_SET(&wp->excmd, E_SEARCH_WMSG);
1523a571abcSchristos
1533a571abcSchristos /* Save the current line/column. */
1543a571abcSchristos s_lno = sp->lno;
1553a571abcSchristos s_cno = sp->cno;
1563a571abcSchristos
1573a571abcSchristos /*
1583a571abcSchristos * !!!
1593a571abcSchristos * Historically, vi / and ? commands were full-blown ex addresses,
1603a571abcSchristos * including ';' delimiters, trailing <blank>'s, multiple search
1613a571abcSchristos * strings (separated by semi-colons) and, finally, full-blown z
1623a571abcSchristos * commands after the / and ? search strings. (If the search was
1633a571abcSchristos * being used as a motion, the trailing z command was ignored.
1643a571abcSchristos * Also, we do some argument checking on the z command, to be sure
1653a571abcSchristos * that it's not some other random command.) For multiple search
1663a571abcSchristos * strings, leading <blank>'s at the second and subsequent strings
1673a571abcSchristos * were eaten as well. This has some (unintended?) side-effects:
1683a571abcSchristos * the command /ptrn/;3 is legal and results in moving to line 3.
1693a571abcSchristos * I suppose you could use it to optionally move to line 3...
1703a571abcSchristos *
1713a571abcSchristos * !!!
1723a571abcSchristos * Historically, if any part of the search command failed, the cursor
1733a571abcSchristos * remained unmodified (even if ; was used). We have to play games
1743a571abcSchristos * because the underlying ex parser thinks we're modifying the cursor
1753a571abcSchristos * as we go, but I think we're compatible with historic practice.
1763a571abcSchristos *
1773a571abcSchristos * !!!
1783a571abcSchristos * Historically, the command "/STRING/; " failed, apparently it
1793a571abcSchristos * confused the parser. We're not that compatible.
1803a571abcSchristos */
1813a571abcSchristos cmdp = &wp->excmd;
182defa1437Schristos if (ex_range(sp, cmdp, &error))
1833a571abcSchristos return (1);
1843a571abcSchristos
1853a571abcSchristos /*
1863a571abcSchristos * Remember where any remaining command information is, and clean
1873a571abcSchristos * up the fake ex command.
1883a571abcSchristos */
1893a571abcSchristos cmd = cmdp->cp;
1903a571abcSchristos len = cmdp->clen;
1913a571abcSchristos wp->excmd.clen = 0;
1923a571abcSchristos
193defa1437Schristos if (error)
1943a571abcSchristos goto err2;
1953a571abcSchristos
1963a571abcSchristos /* Copy out the new cursor position and make sure it's okay. */
1973a571abcSchristos switch (cmdp->addrcnt) {
1983a571abcSchristos case 1:
1993a571abcSchristos vp->m_stop = cmdp->addr1;
2003a571abcSchristos break;
2013a571abcSchristos case 2:
2023a571abcSchristos vp->m_stop = cmdp->addr2;
2033a571abcSchristos break;
2043a571abcSchristos }
2053a571abcSchristos if (!db_exist(sp, vp->m_stop.lno)) {
2063a571abcSchristos ex_badaddr(sp, &fake,
2073a571abcSchristos vp->m_stop.lno == 0 ? A_ZERO : A_EOF, NUM_OK);
2083a571abcSchristos goto err2;
2093a571abcSchristos }
2103a571abcSchristos
2113a571abcSchristos /*
2123a571abcSchristos * !!!
2133a571abcSchristos * Historic practice is that a trailing 'z' was ignored if it was a
2143a571abcSchristos * motion command. Should probably be an error, but not worth the
2153a571abcSchristos * effort.
2163a571abcSchristos */
2173a571abcSchristos if (ISMOTION(vp))
2183a571abcSchristos return (v_correct(sp, vp, F_ISSET(cmdp, E_DELTA)));
2193a571abcSchristos
2203a571abcSchristos /*
2213a571abcSchristos * !!!
2223a571abcSchristos * Historically, if it wasn't a motion command, a delta in the search
2233a571abcSchristos * pattern turns it into a first nonblank movement.
2243a571abcSchristos */
2253a571abcSchristos nb = F_ISSET(cmdp, E_DELTA);
2263a571abcSchristos
2273a571abcSchristos /* Check for the 'z' command. */
2283a571abcSchristos if (len != 0) {
2293a571abcSchristos if (*cmd != 'z')
2303a571abcSchristos goto err1;
2313a571abcSchristos
2323a571abcSchristos /* No blanks, just like the z command. */
2333a571abcSchristos for (t = cmd + 1, tlen = len - 1; tlen > 0; ++t, --tlen)
23408d478e3Schristos if (!ISDIGIT((UCHAR_T)*t))
2353a571abcSchristos break;
2363a571abcSchristos if (tlen &&
2373a571abcSchristos (*t == '-' || *t == '.' || *t == '+' || *t == '^')) {
2383a571abcSchristos ++t;
2393a571abcSchristos --tlen;
2403a571abcSchristos type = 1;
2413a571abcSchristos } else
2423a571abcSchristos type = 0;
2433a571abcSchristos if (tlen)
2443a571abcSchristos goto err1;
2453a571abcSchristos
2463a571abcSchristos /* The z command will do the nonblank for us. */
2473a571abcSchristos nb = 0;
2483a571abcSchristos
2493a571abcSchristos /* Default to z+. */
2503a571abcSchristos if (!type &&
2513a571abcSchristos v_event_push(sp, NULL, L("+"), 1, CH_NOMAP | CH_QUOTED))
2523a571abcSchristos return (1);
2533a571abcSchristos
2543a571abcSchristos /* Push the user's command. */
2553a571abcSchristos if (v_event_push(sp, NULL, cmd, len, CH_NOMAP | CH_QUOTED))
2563a571abcSchristos return (1);
2573a571abcSchristos
2583a571abcSchristos /* Push line number so get correct z display. */
2593a571abcSchristos tlen = snprintf(buf,
2603a571abcSchristos sizeof(buf), "%lu", (u_long)vp->m_stop.lno);
2613a571abcSchristos CHAR2INT(sp, buf, tlen, w, wlen);
2623a571abcSchristos if (v_event_push(sp, NULL, w, wlen, CH_NOMAP | CH_QUOTED))
2633a571abcSchristos return (1);
2643a571abcSchristos
2653a571abcSchristos /* Don't refresh until after 'z' happens. */
2663a571abcSchristos F_SET(VIP(sp), VIP_S_REFRESH);
2673a571abcSchristos }
2683a571abcSchristos
2693a571abcSchristos /* Non-motion commands move to the end of the range. */
2703a571abcSchristos vp->m_final = vp->m_stop;
2713a571abcSchristos if (nb) {
2723a571abcSchristos F_CLR(vp, VM_RCM_MASK);
2733a571abcSchristos F_SET(vp, VM_RCM_SETFNB);
2743a571abcSchristos }
2753a571abcSchristos return (0);
2763a571abcSchristos
2773a571abcSchristos err1: msgq(sp, M_ERR,
2783a571abcSchristos "188|Characters after search string, line offset and/or z command");
2793a571abcSchristos err2: vp->m_final.lno = s_lno;
2803a571abcSchristos vp->m_final.cno = s_cno;
2813a571abcSchristos return (1);
2823a571abcSchristos }
2833a571abcSchristos
2843a571abcSchristos /*
2853a571abcSchristos * v_searchN -- N
2863a571abcSchristos * Reverse last search.
2873a571abcSchristos *
2883a571abcSchristos * PUBLIC: int v_searchN __P((SCR *, VICMD *));
2893a571abcSchristos */
2903a571abcSchristos int
v_searchN(SCR * sp,VICMD * vp)2913a571abcSchristos v_searchN(SCR *sp, VICMD *vp)
2923a571abcSchristos {
2933a571abcSchristos dir_t dir;
2943a571abcSchristos
2953a571abcSchristos switch (sp->searchdir) {
2963a571abcSchristos case BACKWARD:
2973a571abcSchristos dir = FORWARD;
2983a571abcSchristos break;
2993a571abcSchristos case FORWARD:
3003a571abcSchristos dir = BACKWARD;
3013a571abcSchristos break;
3023a571abcSchristos default:
3033a571abcSchristos dir = sp->searchdir;
3043a571abcSchristos break;
3053a571abcSchristos }
3063a571abcSchristos return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, dir));
3073a571abcSchristos }
3083a571abcSchristos
3093a571abcSchristos /*
3103a571abcSchristos * v_searchn -- n
3113a571abcSchristos * Repeat last search.
3123a571abcSchristos *
3133a571abcSchristos * PUBLIC: int v_searchn __P((SCR *, VICMD *));
3143a571abcSchristos */
3153a571abcSchristos int
v_searchn(SCR * sp,VICMD * vp)3163a571abcSchristos v_searchn(SCR *sp, VICMD *vp)
3173a571abcSchristos {
3183a571abcSchristos return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir));
3193a571abcSchristos }
3203a571abcSchristos
3213a571abcSchristos /*
3223a571abcSchristos * is_especial --
3233a571abcSchristos * Test if the character is special in an extended RE.
3243a571abcSchristos */
3253a571abcSchristos static int
is_especial(CHAR_T c)3263a571abcSchristos is_especial(CHAR_T c)
3273a571abcSchristos {
3283a571abcSchristos /*
3293a571abcSchristos * !!!
3303a571abcSchristos * Right-brace is not an ERE special according to IEEE 1003.1-2001.
3313a571abcSchristos * Right-parenthesis is a special character (so quoting doesn't hurt),
3323a571abcSchristos * though it has no special meaning in this context, viz. at the
3333a571abcSchristos * beginning of the string. So we need not quote it. Then again,
3343a571abcSchristos * see the BUGS section in regex/re_format.7.
3353a571abcSchristos * The tilde is vi-specific, of course.
3363a571abcSchristos */
3373a571abcSchristos return (STRCHR(L(".[\\()*+?{|^$~"), c) && c);
3383a571abcSchristos }
3393a571abcSchristos
3403a571abcSchristos /*
3413a571abcSchristos * Rear delimiter for word search when the keyword ends in
3423a571abcSchristos * (i.e., consists of) a non-word character. See v_searchw below.
3433a571abcSchristos */
3443a571abcSchristos #define RE_NWSTOP L("([^[:alnum:]_]|$)")
3453a571abcSchristos #define RE_NWSTOP_LEN (SIZE(RE_NWSTOP) - 1)
3463a571abcSchristos
3473a571abcSchristos /*
3483a571abcSchristos * v_searchw -- [count]^A
3493a571abcSchristos * Search for the word under the cursor.
3503a571abcSchristos *
3513a571abcSchristos * PUBLIC: int v_searchw __P((SCR *, VICMD *));
3523a571abcSchristos */
3533a571abcSchristos int
v_searchw(SCR * sp,VICMD * vp)3543a571abcSchristos v_searchw(SCR *sp, VICMD *vp)
3553a571abcSchristos {
35608d478e3Schristos size_t blen, len;
3573a571abcSchristos int rval;
3583a571abcSchristos CHAR_T *bp, *p;
3593a571abcSchristos
36008d478e3Schristos len = VIP(sp)->klen + MAX(RE_WSTART_LEN, 1)
36108d478e3Schristos + MAX(RE_WSTOP_LEN, RE_NWSTOP_LEN);
36208d478e3Schristos
3633a571abcSchristos GET_SPACE_RETW(sp, bp, blen, len);
3643a571abcSchristos p = bp;
3653a571abcSchristos
3663a571abcSchristos /* Only the first character can be non-word, see v_curword. */
3673a571abcSchristos if (inword(VIP(sp)->keyw[0]))
3683a571abcSchristos p = MEMPCPY(p, RE_WSTART, RE_WSTART_LEN);
3693a571abcSchristos else if (is_especial(VIP(sp)->keyw[0]))
3703a571abcSchristos p = MEMPCPY(p, L("\\"), 1);
3713a571abcSchristos
3723a571abcSchristos p = MEMPCPY(p, VIP(sp)->keyw, VIP(sp)->klen);
3733a571abcSchristos
3743a571abcSchristos if (inword(p[-1]))
3753a571abcSchristos p = MEMPCPY(p, RE_WSTOP, RE_WSTOP_LEN);
3763a571abcSchristos else
3773a571abcSchristos /*
3783a571abcSchristos * The keyword is a single non-word character.
3793a571abcSchristos * We want it to stay the same when typing ^A several times
3803a571abcSchristos * in a row, just the way the other cases behave.
3813a571abcSchristos */
3823a571abcSchristos p = MEMPCPY(p, RE_NWSTOP, RE_NWSTOP_LEN);
3833a571abcSchristos
3843a571abcSchristos len = p - bp;
3853a571abcSchristos rval = v_search(sp, vp, bp, len, SEARCH_SET | SEARCH_EXTEND, FORWARD);
3863a571abcSchristos
3873a571abcSchristos FREE_SPACEW(sp, bp, blen);
3883a571abcSchristos return (rval);
3893a571abcSchristos }
3903a571abcSchristos
3913a571abcSchristos /*
3923a571abcSchristos * v_esearch -- <dialog box>
3933a571abcSchristos * Search command from the screen.
3943a571abcSchristos *
3953a571abcSchristos * PUBLIC: int v_esearch __P((SCR *, VICMD *));
3963a571abcSchristos */
3973a571abcSchristos int
v_esearch(SCR * sp,VICMD * vp)3983a571abcSchristos v_esearch(SCR *sp, VICMD *vp)
3993a571abcSchristos {
4003a571abcSchristos int flags;
4013a571abcSchristos
4023a571abcSchristos LF_INIT(SEARCH_NOOPT);
4033a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_EXT))
4043a571abcSchristos LF_SET(SEARCH_EXTEND);
4053a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_IC))
4063a571abcSchristos LF_SET(SEARCH_IC);
4073a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_ICL))
4083a571abcSchristos LF_SET(SEARCH_ICL);
4093a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_INCR))
4103a571abcSchristos LF_SET(SEARCH_INCR);
4113a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_LIT))
4123a571abcSchristos LF_SET(SEARCH_LITERAL);
4133a571abcSchristos if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_WR))
4143a571abcSchristos LF_SET(SEARCH_WRAP);
4153a571abcSchristos return (v_search(sp, vp, vp->ev.e_csp, vp->ev.e_len, flags,
4163a571abcSchristos FL_ISSET(vp->ev.e_flags, VI_SEARCH_REV) ? BACKWARD : FORWARD));
4173a571abcSchristos }
4183a571abcSchristos
4193a571abcSchristos /*
4203a571abcSchristos * v_search --
4213a571abcSchristos * The search commands.
4223a571abcSchristos */
4233a571abcSchristos static int
v_search(SCR * sp,VICMD * vp,CHAR_T * ptrn,size_t plen,u_int flags,dir_t dir)4243a571abcSchristos v_search(SCR *sp, VICMD *vp, CHAR_T *ptrn, size_t plen, u_int flags, dir_t dir)
4253a571abcSchristos {
4263a571abcSchristos /* Display messages. */
4273a571abcSchristos LF_SET(SEARCH_MSG);
4283a571abcSchristos
4293a571abcSchristos /* If it's a motion search, offset past end-of-line is okay. */
4303a571abcSchristos if (ISMOTION(vp))
4313a571abcSchristos LF_SET(SEARCH_EOL);
4323a571abcSchristos
4333a571abcSchristos /*
4343a571abcSchristos * XXX
4353a571abcSchristos * Warn if the search wraps. See the comment above, in v_exaddr().
4363a571abcSchristos */
4373a571abcSchristos if (!KEYS_WAITING(sp))
4383a571abcSchristos LF_SET(SEARCH_WMSG);
4393a571abcSchristos
4403a571abcSchristos switch (dir) {
4413a571abcSchristos case BACKWARD:
4423a571abcSchristos if (b_search(sp,
4433a571abcSchristos &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
4443a571abcSchristos return (1);
4453a571abcSchristos break;
4463a571abcSchristos case FORWARD:
4473a571abcSchristos if (f_search(sp,
4483a571abcSchristos &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags))
4493a571abcSchristos return (1);
4503a571abcSchristos break;
4513a571abcSchristos case NOTSET:
4523a571abcSchristos msgq(sp, M_ERR, "189|No previous search pattern");
4533a571abcSchristos return (1);
4543a571abcSchristos default:
4553a571abcSchristos abort();
4563a571abcSchristos }
4573a571abcSchristos
4583a571abcSchristos /* Correct motion commands, otherwise, simply move to the location. */
4593a571abcSchristos if (ISMOTION(vp)) {
4603a571abcSchristos if (v_correct(sp, vp, 0))
4613a571abcSchristos return(1);
4623a571abcSchristos } else
4633a571abcSchristos vp->m_final = vp->m_stop;
4643a571abcSchristos return (0);
4653a571abcSchristos }
4663a571abcSchristos
4673a571abcSchristos /*
4683a571abcSchristos * v_correct --
4693a571abcSchristos * Handle command with a search as the motion.
4703a571abcSchristos *
4713a571abcSchristos * !!!
4723a571abcSchristos * Historically, commands didn't affect the line searched to/from if the
4733a571abcSchristos * motion command was a search and the final position was the start/end
4743a571abcSchristos * of the line. There were some special cases and vi was not consistent;
4753a571abcSchristos * it was fairly easy to confuse it. For example, given the two lines:
4763a571abcSchristos *
4773a571abcSchristos * abcdefghi
4783a571abcSchristos * ABCDEFGHI
4793a571abcSchristos *
4803a571abcSchristos * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h'
4813a571abcSchristos * 'k' and put would no longer work correctly. In any case, we try to do
4823a571abcSchristos * the right thing, but it's not going to exactly match historic practice.
4833a571abcSchristos *
4843a571abcSchristos * PUBLIC: int v_correct __P((SCR *, VICMD *, int));
4853a571abcSchristos */
4863a571abcSchristos int
v_correct(SCR * sp,VICMD * vp,int isdelta)4873a571abcSchristos v_correct(SCR *sp, VICMD *vp, int isdelta)
4883a571abcSchristos {
4893a571abcSchristos MARK m;
4903a571abcSchristos size_t len;
4913a571abcSchristos
4923a571abcSchristos /*
4933a571abcSchristos * !!!
4943a571abcSchristos * We may have wrapped if wrapscan was set, and we may have returned
4953a571abcSchristos * to the position where the cursor started. Historic vi didn't cope
4963a571abcSchristos * with this well. Yank wouldn't beep, but the first put after the
4973a571abcSchristos * yank would move the cursor right one column (without adding any
4983a571abcSchristos * text) and the second would put a copy of the current line. The
4993a571abcSchristos * change and delete commands would beep, but would leave the cursor
5003a571abcSchristos * on the colon command line. I believe that there are macros that
5013a571abcSchristos * depend on delete, at least, failing. For now, commands that use
5023a571abcSchristos * search as a motion component fail when the search returns to the
5033a571abcSchristos * original cursor position.
5043a571abcSchristos */
5053a571abcSchristos if (vp->m_start.lno == vp->m_stop.lno &&
5063a571abcSchristos vp->m_start.cno == vp->m_stop.cno) {
5073a571abcSchristos msgq(sp, M_BERR, "190|Search wrapped to original position");
5083a571abcSchristos return (1);
5093a571abcSchristos }
5103a571abcSchristos
5113a571abcSchristos /*
5123a571abcSchristos * !!!
5133a571abcSchristos * Searches become line mode operations if there was a delta specified
5143a571abcSchristos * to the search pattern.
5153a571abcSchristos */
5163a571abcSchristos if (isdelta)
5173a571abcSchristos F_SET(vp, VM_LMODE);
5183a571abcSchristos
5193a571abcSchristos /*
5203a571abcSchristos * If the motion is in the reverse direction, switch the start and
5213a571abcSchristos * stop MARK's so that it's in a forward direction. (There's no
5223a571abcSchristos * reason for this other than to make the tests below easier. The
5233a571abcSchristos * code in vi.c:vi() would have done the switch.) Both forward
5243a571abcSchristos * and backward motions can happen for any kind of search command
5253a571abcSchristos * because of the wrapscan option.
5263a571abcSchristos */
5273a571abcSchristos if (vp->m_start.lno > vp->m_stop.lno ||
52808d478e3Schristos (vp->m_start.lno == vp->m_stop.lno &&
52908d478e3Schristos vp->m_start.cno > vp->m_stop.cno)) {
5303a571abcSchristos m = vp->m_start;
5313a571abcSchristos vp->m_start = vp->m_stop;
5323a571abcSchristos vp->m_stop = m;
5334eee468dSchristos }
5343a571abcSchristos
5353a571abcSchristos /*
5363a571abcSchristos * BACKWARD:
5373a571abcSchristos * Delete and yank commands move to the end of the range.
5383a571abcSchristos * Ignore others.
5393a571abcSchristos *
5403a571abcSchristos * FORWARD:
5413a571abcSchristos * Delete and yank commands don't move. Ignore others.
5423a571abcSchristos */
5433a571abcSchristos vp->m_final = vp->m_start;
5443a571abcSchristos
5453a571abcSchristos /*
5463a571abcSchristos * !!!
5473a571abcSchristos * Delta'd searches don't correct based on column positions.
5483a571abcSchristos */
5493a571abcSchristos if (isdelta)
5503a571abcSchristos return (0);
5513a571abcSchristos
5523a571abcSchristos /*
5533a571abcSchristos * !!!
5543a571abcSchristos * Backward searches starting at column 0, and forward searches ending
5553a571abcSchristos * at column 0 are corrected to the last column of the previous line.
5563a571abcSchristos * Otherwise, adjust the starting/ending point to the character before
5573a571abcSchristos * the current one (this is safe because we know the search had to move
5583a571abcSchristos * to succeed).
5593a571abcSchristos *
5603a571abcSchristos * Searches become line mode operations if they start at the first
5613a571abcSchristos * nonblank and end at column 0 of another line.
5623a571abcSchristos */
5633a571abcSchristos if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
5643a571abcSchristos if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
5653a571abcSchristos return (1);
5663a571abcSchristos vp->m_stop.cno = len ? len - 1 : 0;
5673a571abcSchristos len = 0;
5683a571abcSchristos if (nonblank(sp, vp->m_start.lno, &len))
5693a571abcSchristos return (1);
5703a571abcSchristos if (vp->m_start.cno <= len)
5713a571abcSchristos F_SET(vp, VM_LMODE);
5723a571abcSchristos } else
5733a571abcSchristos --vp->m_stop.cno;
5743a571abcSchristos
5753a571abcSchristos return (0);
5763a571abcSchristos }
577