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