119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: v_search.c,v 10.31 2012/02/08 07:26:59 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <ctype.h> 2219304Speter#include <errno.h> 2319304Speter#include <limits.h> 2419304Speter#include <stdio.h> 2519304Speter#include <stdlib.h> 2619304Speter#include <string.h> 2719304Speter 2819304Speter#include "../common/common.h" 2919304Speter#include "vi.h" 3019304Speter 3119304Speterstatic int v_exaddr __P((SCR *, VICMD *, dir_t)); 32254225Speterstatic int v_search __P((SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t)); 3319304Speter 3419304Speter/* 3519304Speter * v_srch -- [count]?RE[? offset] 3619304Speter * Ex address search backward. 3719304Speter * 3819304Speter * PUBLIC: int v_searchb __P((SCR *, VICMD *)); 3919304Speter */ 4019304Speterint 41254225Speterv_searchb(SCR *sp, VICMD *vp) 4219304Speter{ 4319304Speter return (v_exaddr(sp, vp, BACKWARD)); 4419304Speter} 4519304Speter 4619304Speter/* 4719304Speter * v_searchf -- [count]/RE[/ offset] 4819304Speter * Ex address search forward. 4919304Speter * 5019304Speter * PUBLIC: int v_searchf __P((SCR *, VICMD *)); 5119304Speter */ 5219304Speterint 53254225Speterv_searchf(SCR *sp, VICMD *vp) 5419304Speter{ 5519304Speter return (v_exaddr(sp, vp, FORWARD)); 5619304Speter} 5719304Speter 5819304Speter/* 5919304Speter * v_exaddr -- 6019304Speter * Do a vi search (which is really an ex address). 6119304Speter */ 6219304Speterstatic int 63254225Speterv_exaddr(SCR *sp, VICMD *vp, dir_t dir) 6419304Speter{ 65254225Speter static EXCMDLIST fake = { L("search") }; 6619304Speter EXCMD *cmdp; 6719304Speter GS *gp; 6819304Speter TEXT *tp; 6919304Speter recno_t s_lno; 7019304Speter size_t len, s_cno, tlen; 7119304Speter int err, nb, type; 72254225Speter char buf[20]; 73254225Speter CHAR_T *cmd, *t; 74254225Speter CHAR_T *w; 75254225Speter size_t wlen; 7619304Speter 7719304Speter /* 7819304Speter * !!! 7919304Speter * If using the search command as a motion, any addressing components 8019304Speter * are lost, i.e. y/ptrn/+2, when repeated, is the same as y/ptrn/. 8119304Speter */ 8219304Speter if (F_ISSET(vp, VC_ISDOT)) 8319304Speter return (v_search(sp, vp, 8419304Speter NULL, 0, SEARCH_PARSE | SEARCH_MSG | SEARCH_SET, dir)); 8519304Speter 8619304Speter /* Get the search pattern. */ 8719304Speter if (v_tcmd(sp, vp, dir == BACKWARD ? CH_BSEARCH : CH_FSEARCH, 8819304Speter TXT_BS | TXT_CR | TXT_ESCAPE | TXT_PROMPT | 8919304Speter (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0))) 9019304Speter return (1); 9119304Speter 92254225Speter tp = TAILQ_FIRST(sp->tiq); 9319304Speter 9419304Speter /* If the user backspaced over the prompt, do nothing. */ 9519304Speter if (tp->term == TERM_BS) 9619304Speter return (1); 9719304Speter 9819304Speter /* 9919304Speter * If the user was doing an incremental search, then we've already 10019304Speter * updated the cursor and moved to the right location. Return the 10119304Speter * correct values, we're done. 10219304Speter */ 10319304Speter if (tp->term == TERM_SEARCH) { 10419304Speter vp->m_stop.lno = sp->lno; 10519304Speter vp->m_stop.cno = sp->cno; 10619304Speter if (ISMOTION(vp)) 10719304Speter return (v_correct(sp, vp, 0)); 10819304Speter vp->m_final = vp->m_stop; 10919304Speter return (0); 11019304Speter } 11119304Speter 11219304Speter /* 11319304Speter * If the user entered <escape> or <carriage-return>, the length is 11419304Speter * 1 and the right thing will happen, i.e. the prompt will be used 11519304Speter * as a command character. 11619304Speter * 11719304Speter * Build a fake ex command structure. 11819304Speter */ 11919304Speter gp = sp->gp; 12019304Speter gp->excmd.cp = tp->lb; 12119304Speter gp->excmd.clen = tp->len; 12219304Speter F_INIT(&gp->excmd, E_VISEARCH); 12319304Speter 12419304Speter /* 12519304Speter * XXX 12619304Speter * Warn if the search wraps. This is a pretty special case, but it's 12719304Speter * nice feature that wasn't in the original implementations of ex/vi. 12819304Speter * (It was added at some point to System V's version.) This message 12919304Speter * is only displayed if there are no keys in the queue. The problem is 13019304Speter * the command is going to succeed, and the message is informational, 13119304Speter * not an error. If a macro displays it repeatedly, e.g., the pattern 13219304Speter * only occurs once in the file and wrapscan is set, you lose big. For 13319304Speter * example, if the macro does something like: 13419304Speter * 13519304Speter * :map K /pattern/^MjK 13619304Speter * 13719304Speter * Each search will display the message, but the following "/pattern/" 13819304Speter * will immediately overwrite it, with strange results. The System V 13919304Speter * vi displays the "wrapped" message multiple times, but because it's 14019304Speter * overwritten each time, it's not as noticeable. As we don't discard 14119304Speter * messages, it's a real problem for us. 14219304Speter */ 14319304Speter if (!KEYS_WAITING(sp)) 14419304Speter F_SET(&gp->excmd, E_SEARCH_WMSG); 14519304Speter 14619304Speter /* Save the current line/column. */ 14719304Speter s_lno = sp->lno; 14819304Speter s_cno = sp->cno; 14919304Speter 15019304Speter /* 15119304Speter * !!! 15219304Speter * Historically, vi / and ? commands were full-blown ex addresses, 15319304Speter * including ';' delimiters, trailing <blank>'s, multiple search 15419304Speter * strings (separated by semi-colons) and, finally, full-blown z 15519304Speter * commands after the / and ? search strings. (If the search was 15619304Speter * being used as a motion, the trailing z command was ignored. 15719304Speter * Also, we do some argument checking on the z command, to be sure 15819304Speter * that it's not some other random command.) For multiple search 15919304Speter * strings, leading <blank>'s at the second and subsequent strings 16019304Speter * were eaten as well. This has some (unintended?) side-effects: 16119304Speter * the command /ptrn/;3 is legal and results in moving to line 3. 16219304Speter * I suppose you could use it to optionally move to line 3... 16319304Speter * 16419304Speter * !!! 16519304Speter * Historically, if any part of the search command failed, the cursor 16619304Speter * remained unmodified (even if ; was used). We have to play games 16719304Speter * because the underlying ex parser thinks we're modifying the cursor 16819304Speter * as we go, but I think we're compatible with historic practice. 16919304Speter * 17019304Speter * !!! 17119304Speter * Historically, the command "/STRING/; " failed, apparently it 17219304Speter * confused the parser. We're not that compatible. 17319304Speter */ 17419304Speter cmdp = &gp->excmd; 17519304Speter if (ex_range(sp, cmdp, &err)) 17619304Speter return (1); 17719304Speter 17819304Speter /* 17919304Speter * Remember where any remaining command information is, and clean 18019304Speter * up the fake ex command. 18119304Speter */ 18219304Speter cmd = cmdp->cp; 18319304Speter len = cmdp->clen; 18419304Speter gp->excmd.clen = 0; 18519304Speter 18619304Speter if (err) 18719304Speter goto err2; 18819304Speter 18919304Speter /* Copy out the new cursor position and make sure it's okay. */ 19019304Speter switch (cmdp->addrcnt) { 19119304Speter case 1: 19219304Speter vp->m_stop = cmdp->addr1; 19319304Speter break; 19419304Speter case 2: 19519304Speter vp->m_stop = cmdp->addr2; 19619304Speter break; 19719304Speter } 19819304Speter if (!db_exist(sp, vp->m_stop.lno)) { 19919304Speter ex_badaddr(sp, &fake, 20019304Speter vp->m_stop.lno == 0 ? A_ZERO : A_EOF, NUM_OK); 20119304Speter goto err2; 20219304Speter } 20319304Speter 20419304Speter /* 20519304Speter * !!! 20619304Speter * Historic practice is that a trailing 'z' was ignored if it was a 20719304Speter * motion command. Should probably be an error, but not worth the 20819304Speter * effort. 20919304Speter */ 21019304Speter if (ISMOTION(vp)) 21119304Speter return (v_correct(sp, vp, F_ISSET(cmdp, E_DELTA))); 21219304Speter 21319304Speter /* 21419304Speter * !!! 21519304Speter * Historically, if it wasn't a motion command, a delta in the search 21619304Speter * pattern turns it into a first nonblank movement. 21719304Speter */ 21819304Speter nb = F_ISSET(cmdp, E_DELTA); 21919304Speter 22019304Speter /* Check for the 'z' command. */ 22119304Speter if (len != 0) { 22219304Speter if (*cmd != 'z') 22319304Speter goto err1; 22419304Speter 22519304Speter /* No blanks, just like the z command. */ 22619304Speter for (t = cmd + 1, tlen = len - 1; tlen > 0; ++t, --tlen) 22719304Speter if (!isdigit(*t)) 22819304Speter break; 22919304Speter if (tlen && 23019304Speter (*t == '-' || *t == '.' || *t == '+' || *t == '^')) { 23119304Speter ++t; 23219304Speter --tlen; 23319304Speter type = 1; 23419304Speter } else 23519304Speter type = 0; 23619304Speter if (tlen) 23719304Speter goto err1; 23819304Speter 23919304Speter /* The z command will do the nonblank for us. */ 24019304Speter nb = 0; 24119304Speter 24219304Speter /* Default to z+. */ 24319304Speter if (!type && 244254225Speter v_event_push(sp, NULL, L("+"), 1, CH_NOMAP | CH_QUOTED)) 24519304Speter return (1); 24619304Speter 24719304Speter /* Push the user's command. */ 24819304Speter if (v_event_push(sp, NULL, cmd, len, CH_NOMAP | CH_QUOTED)) 24919304Speter return (1); 25019304Speter 25119304Speter /* Push line number so get correct z display. */ 25219304Speter tlen = snprintf(buf, 25319304Speter sizeof(buf), "%lu", (u_long)vp->m_stop.lno); 254254225Speter CHAR2INT(sp, buf, tlen, w, wlen); 255254225Speter if (v_event_push(sp, NULL, w, wlen, CH_NOMAP | CH_QUOTED)) 25619304Speter return (1); 25719304Speter 25819304Speter /* Don't refresh until after 'z' happens. */ 25919304Speter F_SET(VIP(sp), VIP_S_REFRESH); 26019304Speter } 26119304Speter 26219304Speter /* Non-motion commands move to the end of the range. */ 26319304Speter vp->m_final = vp->m_stop; 26419304Speter if (nb) { 26519304Speter F_CLR(vp, VM_RCM_MASK); 26619304Speter F_SET(vp, VM_RCM_SETFNB); 26719304Speter } 26819304Speter return (0); 26919304Speter 27019304Spetererr1: msgq(sp, M_ERR, 27119304Speter "188|Characters after search string, line offset and/or z command"); 27219304Spetererr2: vp->m_final.lno = s_lno; 27319304Speter vp->m_final.cno = s_cno; 27419304Speter return (1); 27519304Speter} 27619304Speter 27719304Speter/* 27819304Speter * v_searchN -- N 27919304Speter * Reverse last search. 28019304Speter * 28119304Speter * PUBLIC: int v_searchN __P((SCR *, VICMD *)); 28219304Speter */ 28319304Speterint 284254225Speterv_searchN(SCR *sp, VICMD *vp) 28519304Speter{ 28619304Speter dir_t dir; 28719304Speter 28819304Speter switch (sp->searchdir) { 28919304Speter case BACKWARD: 29019304Speter dir = FORWARD; 29119304Speter break; 29219304Speter case FORWARD: 29319304Speter dir = BACKWARD; 29419304Speter break; 29519304Speter default: 29619304Speter dir = sp->searchdir; 29719304Speter break; 29819304Speter } 29919304Speter return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, dir)); 30019304Speter} 30119304Speter 30219304Speter/* 30319304Speter * v_searchn -- n 30419304Speter * Repeat last search. 30519304Speter * 30619304Speter * PUBLIC: int v_searchn __P((SCR *, VICMD *)); 30719304Speter */ 30819304Speterint 309254225Speterv_searchn(SCR *sp, VICMD *vp) 31019304Speter{ 31119304Speter return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir)); 31219304Speter} 31319304Speter 31419304Speter/* 315254225Speter * is_special -- 316254225Speter * Test if the character is special in a basic RE. 317254225Speter */ 318254225Speterstatic int 319254225Speteris_special(CHAR_T c) 320254225Speter{ 321254225Speter /* 322254225Speter * !!! 323254225Speter * `*' and `$' are ordinary when appear at the beginning of a RE, 324254225Speter * but it's safe to distinguish them from the ordinary characters. 325254225Speter * The tilde is vi-specific, of course. 326254225Speter */ 327254225Speter return (STRCHR(L(".[*\\^$~"), c) && c); 328254225Speter} 329254225Speter 330254225Speter/* 331254225Speter * Rear delimiter for word search when the keyword ends in 332254225Speter * (i.e., consists of) a non-word character. See v_searchw below. 333254225Speter */ 334254225Speter#define RE_NWSTOP L("([^[:alnum:]_]|$)") 335254225Speter#define RE_NWSTOP_LEN (SIZE(RE_NWSTOP) - 1) 336254225Speter 337254225Speter/* 33819304Speter * v_searchw -- [count]^A 33919304Speter * Search for the word under the cursor. 34019304Speter * 34119304Speter * PUBLIC: int v_searchw __P((SCR *, VICMD *)); 34219304Speter */ 34319304Speterint 344254225Speterv_searchw(SCR *sp, VICMD *vp) 34519304Speter{ 34619304Speter size_t blen, len; 34719304Speter int rval; 348254225Speter CHAR_T *bp, *p; 34919304Speter 350254225Speter /* An upper bound for the SIZE of the RE under construction. */ 351254225Speter len = VIP(sp)->klen + MAX(RE_WSTART_LEN, 1) 352254225Speter + MAX(RE_WSTOP_LEN, RE_NWSTOP_LEN); 353254225Speter GET_SPACE_RETW(sp, bp, blen, len); 354254225Speter p = bp; 35519304Speter 356254225Speter /* Only the first character can be non-word, see v_curword. */ 357254225Speter if (inword(VIP(sp)->keyw[0])) { 358254225Speter MEMCPY(p, RE_WSTART, RE_WSTART_LEN); 359254225Speter p += RE_WSTART_LEN; 360254225Speter } else if (is_special(VIP(sp)->keyw[0])) { 361254225Speter MEMCPY(p, L("\\"), 1); 362254225Speter p += 1; 363254225Speter } 364254225Speter 365254225Speter MEMCPY(p, VIP(sp)->keyw, VIP(sp)->klen); 366254225Speter p += VIP(sp)->klen; 367254225Speter 368254225Speter if (inword(p[-1])) { 369254225Speter MEMCPY(p, RE_WSTOP, RE_WSTOP_LEN); 370254225Speter p += RE_WSTOP_LEN; 371254225Speter } else { 372254225Speter /* 373254225Speter * The keyword is a single non-word character. 374254225Speter * We want it to stay the same when typing ^A several times 375254225Speter * in a row, just the way the other cases behave. 376254225Speter */ 377254225Speter MEMCPY(p, RE_NWSTOP, RE_NWSTOP_LEN); 378254225Speter p += RE_NWSTOP_LEN; 379254225Speter } 380254225Speter 381254225Speter len = p - bp; 38219304Speter rval = v_search(sp, vp, bp, len, SEARCH_SET, FORWARD); 38319304Speter 384254225Speter FREE_SPACEW(sp, bp, blen); 38519304Speter return (rval); 38619304Speter} 38719304Speter 38819304Speter/* 38919304Speter * v_search -- 39019304Speter * The search commands. 39119304Speter */ 39219304Speterstatic int 393254225Speterv_search(SCR *sp, VICMD *vp, CHAR_T *ptrn, size_t plen, u_int flags, dir_t dir) 39419304Speter{ 39519304Speter /* Display messages. */ 39619304Speter LF_SET(SEARCH_MSG); 39719304Speter 39819304Speter /* If it's a motion search, offset past end-of-line is okay. */ 39919304Speter if (ISMOTION(vp)) 40019304Speter LF_SET(SEARCH_EOL); 40119304Speter 40219304Speter /* 40319304Speter * XXX 40419304Speter * Warn if the search wraps. See the comment above, in v_exaddr(). 40519304Speter */ 40619304Speter if (!KEYS_WAITING(sp)) 40719304Speter LF_SET(SEARCH_WMSG); 40819304Speter 40919304Speter switch (dir) { 41019304Speter case BACKWARD: 41119304Speter if (b_search(sp, 41219304Speter &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags)) 41319304Speter return (1); 41419304Speter break; 41519304Speter case FORWARD: 41619304Speter if (f_search(sp, 41719304Speter &vp->m_start, &vp->m_stop, ptrn, plen, NULL, flags)) 41819304Speter return (1); 41919304Speter break; 42019304Speter case NOTSET: 42119304Speter msgq(sp, M_ERR, "189|No previous search pattern"); 42219304Speter return (1); 42319304Speter default: 42419304Speter abort(); 42519304Speter } 42619304Speter 42719304Speter /* Correct motion commands, otherwise, simply move to the location. */ 42819304Speter if (ISMOTION(vp)) { 42919304Speter if (v_correct(sp, vp, 0)) 43019304Speter return(1); 43119304Speter } else 43219304Speter vp->m_final = vp->m_stop; 43319304Speter return (0); 43419304Speter} 43519304Speter 43619304Speter/* 43719304Speter * v_correct -- 43819304Speter * Handle command with a search as the motion. 43919304Speter * 44019304Speter * !!! 44119304Speter * Historically, commands didn't affect the line searched to/from if the 44219304Speter * motion command was a search and the final position was the start/end 44319304Speter * of the line. There were some special cases and vi was not consistent; 44419304Speter * it was fairly easy to confuse it. For example, given the two lines: 44519304Speter * 44619304Speter * abcdefghi 44719304Speter * ABCDEFGHI 44819304Speter * 44919304Speter * placing the cursor on the 'A' and doing y?$ would so confuse it that 'h' 45019304Speter * 'k' and put would no longer work correctly. In any case, we try to do 45119304Speter * the right thing, but it's not going to exactly match historic practice. 45219304Speter * 45319304Speter * PUBLIC: int v_correct __P((SCR *, VICMD *, int)); 45419304Speter */ 45519304Speterint 456254225Speterv_correct(SCR *sp, VICMD *vp, int isdelta) 45719304Speter{ 45819304Speter dir_t dir; 45919304Speter MARK m; 46019304Speter size_t len; 46119304Speter 46219304Speter /* 46319304Speter * !!! 46419304Speter * We may have wrapped if wrapscan was set, and we may have returned 46519304Speter * to the position where the cursor started. Historic vi didn't cope 46619304Speter * with this well. Yank wouldn't beep, but the first put after the 46719304Speter * yank would move the cursor right one column (without adding any 46819304Speter * text) and the second would put a copy of the current line. The 46919304Speter * change and delete commands would beep, but would leave the cursor 47019304Speter * on the colon command line. I believe that there are macros that 47119304Speter * depend on delete, at least, failing. For now, commands that use 47219304Speter * search as a motion component fail when the search returns to the 47319304Speter * original cursor position. 47419304Speter */ 47519304Speter if (vp->m_start.lno == vp->m_stop.lno && 47619304Speter vp->m_start.cno == vp->m_stop.cno) { 47719304Speter msgq(sp, M_BERR, "190|Search wrapped to original position"); 47819304Speter return (1); 47919304Speter } 48019304Speter 48119304Speter /* 48219304Speter * !!! 48319304Speter * Searches become line mode operations if there was a delta specified 48419304Speter * to the search pattern. 48519304Speter */ 48619304Speter if (isdelta) 48719304Speter F_SET(vp, VM_LMODE); 48819304Speter 48919304Speter /* 49019304Speter * If the motion is in the reverse direction, switch the start and 49119304Speter * stop MARK's so that it's in a forward direction. (There's no 49219304Speter * reason for this other than to make the tests below easier. The 49319304Speter * code in vi.c:vi() would have done the switch.) Both forward 49419304Speter * and backward motions can happen for any kind of search command 49519304Speter * because of the wrapscan option. 49619304Speter */ 49719304Speter if (vp->m_start.lno > vp->m_stop.lno || 498254225Speter (vp->m_start.lno == vp->m_stop.lno && 499254225Speter vp->m_start.cno > vp->m_stop.cno)) { 50019304Speter m = vp->m_start; 50119304Speter vp->m_start = vp->m_stop; 50219304Speter vp->m_stop = m; 50319304Speter dir = BACKWARD; 50419304Speter } else 50519304Speter dir = FORWARD; 50619304Speter 50719304Speter /* 50819304Speter * BACKWARD: 50919304Speter * Delete and yank commands move to the end of the range. 51019304Speter * Ignore others. 51119304Speter * 51219304Speter * FORWARD: 51319304Speter * Delete and yank commands don't move. Ignore others. 51419304Speter */ 51519304Speter vp->m_final = vp->m_start; 51619304Speter 51719304Speter /* 51819304Speter * !!! 51919304Speter * Delta'd searches don't correct based on column positions. 52019304Speter */ 52119304Speter if (isdelta) 52219304Speter return (0); 52319304Speter 52419304Speter /* 52519304Speter * !!! 52619304Speter * Backward searches starting at column 0, and forward searches ending 52719304Speter * at column 0 are corrected to the last column of the previous line. 52819304Speter * Otherwise, adjust the starting/ending point to the character before 52919304Speter * the current one (this is safe because we know the search had to move 53019304Speter * to succeed). 53119304Speter * 53219304Speter * Searches become line mode operations if they start at the first 53319304Speter * nonblank and end at column 0 of another line. 53419304Speter */ 53519304Speter if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { 53619304Speter if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) 53719304Speter return (1); 53819304Speter vp->m_stop.cno = len ? len - 1 : 0; 53919304Speter len = 0; 54019304Speter if (nonblank(sp, vp->m_start.lno, &len)) 54119304Speter return (1); 54219304Speter if (vp->m_start.cno <= len) 54319304Speter F_SET(vp, VM_LMODE); 54419304Speter } else 54519304Speter --vp->m_stop.cno; 54619304Speter 54719304Speter return (0); 54819304Speter} 549