1/* search.c - code for non-incremental searching in emacs and vi modes. */ 2 3/* Copyright (C) 1992-2005 Free Software Foundation, Inc. 4 5 This file is part of the Readline Library (the Library), a set of 6 routines for providing Emacs style line input to programs that ask 7 for it. 8 9 The Library is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 The Library is distributed in the hope that it will be useful, but 15 WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 General Public License for more details. 18 19 The GNU General Public License is often shipped with GNU software, and 20 is generally kept in a file called COPYING or LICENSE. If you do not 21 have a copy of the license, write to the Free Software Foundation, 22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 23#define READLINE_LIBRARY 24 25#if defined (HAVE_CONFIG_H) 26# include <config.h> 27#endif 28 29#include <sys/types.h> 30#include <stdio.h> 31 32#if defined (HAVE_UNISTD_H) 33# include <unistd.h> 34#endif 35 36#if defined (HAVE_STDLIB_H) 37# include <stdlib.h> 38#else 39# include "ansi_stdlib.h" 40#endif 41 42#include "rldefs.h" 43#include "rlmbutil.h" 44 45#include "readline.h" 46#include "history.h" 47 48#include "rlprivate.h" 49#include "xmalloc.h" 50 51#ifdef abs 52# undef abs 53#endif 54#define abs(x) (((x) >= 0) ? (x) : -(x)) 55 56_rl_search_cxt *_rl_nscxt = 0; 57 58extern HIST_ENTRY *_rl_saved_line_for_history; 59 60/* Functions imported from the rest of the library. */ 61extern int _rl_free_history_entry PARAMS((HIST_ENTRY *)); 62 63static char *noninc_search_string = (char *) NULL; 64static int noninc_history_pos; 65 66static char *prev_line_found = (char *) NULL; 67 68static int rl_history_search_len; 69static int rl_history_search_pos; 70static char *history_search_string; 71static int history_string_size; 72 73static UNDO_LIST *noninc_saved_undo_list; 74static void make_history_line_current PARAMS((HIST_ENTRY *)); 75static int noninc_search_from_pos PARAMS((char *, int, int)); 76static int noninc_dosearch PARAMS((char *, int)); 77static int noninc_search PARAMS((int, int)); 78static int rl_history_search_internal PARAMS((int, int)); 79static void rl_history_search_reinit PARAMS((void)); 80 81static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int)); 82static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int)); 83static void _rl_nsearch_abort PARAMS((_rl_search_cxt *)); 84static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int)); 85 86/* Make the data from the history entry ENTRY be the contents of the 87 current line. This doesn't do anything with rl_point; the caller 88 must set it. */ 89static void 90make_history_line_current (entry) 91 HIST_ENTRY *entry; 92{ 93 _rl_replace_text (entry->line, 0, rl_end); 94 _rl_fix_point (1); 95#if defined (VI_MODE) 96 if (rl_editing_mode == vi_mode) 97 /* POSIX.2 says that the `U' command doesn't affect the copy of any 98 command lines to the edit line. We're going to implement that by 99 making the undo list start after the matching line is copied to the 100 current editing buffer. */ 101 rl_free_undo_list (); 102#endif 103 104 if (_rl_saved_line_for_history) 105 _rl_free_history_entry (_rl_saved_line_for_history); 106 _rl_saved_line_for_history = (HIST_ENTRY *)NULL; 107} 108 109/* Search the history list for STRING starting at absolute history position 110 POS. If STRING begins with `^', the search must match STRING at the 111 beginning of a history line, otherwise a full substring match is performed 112 for STRING. DIR < 0 means to search backwards through the history list, 113 DIR >= 0 means to search forward. */ 114static int 115noninc_search_from_pos (string, pos, dir) 116 char *string; 117 int pos, dir; 118{ 119 int ret, old; 120 121 if (pos < 0) 122 return -1; 123 124 old = where_history (); 125 if (history_set_pos (pos) == 0) 126 return -1; 127 128 RL_SETSTATE(RL_STATE_SEARCH); 129 if (*string == '^') 130 ret = history_search_prefix (string + 1, dir); 131 else 132 ret = history_search (string, dir); 133 RL_UNSETSTATE(RL_STATE_SEARCH); 134 135 if (ret != -1) 136 ret = where_history (); 137 138 history_set_pos (old); 139 return (ret); 140} 141 142/* Search for a line in the history containing STRING. If DIR is < 0, the 143 search is backwards through previous entries, else through subsequent 144 entries. Returns 1 if the search was successful, 0 otherwise. */ 145static int 146noninc_dosearch (string, dir) 147 char *string; 148 int dir; 149{ 150 int oldpos, pos; 151 HIST_ENTRY *entry; 152 153 if (string == 0 || *string == '\0' || noninc_history_pos < 0) 154 { 155 rl_ding (); 156 return 0; 157 } 158 159 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 160 if (pos == -1) 161 { 162 /* Search failed, current history position unchanged. */ 163 rl_maybe_unsave_line (); 164 rl_clear_message (); 165 rl_point = 0; 166 rl_ding (); 167 return 0; 168 } 169 170 noninc_history_pos = pos; 171 172 oldpos = where_history (); 173 history_set_pos (noninc_history_pos); 174 entry = current_history (); 175#if defined (VI_MODE) 176 if (rl_editing_mode != vi_mode) 177#endif 178 history_set_pos (oldpos); 179 180 make_history_line_current (entry); 181 182 rl_point = 0; 183 rl_mark = rl_end; 184 185 rl_clear_message (); 186 return 1; 187} 188 189static _rl_search_cxt * 190_rl_nsearch_init (dir, pchar) 191 int dir, pchar; 192{ 193 _rl_search_cxt *cxt; 194 char *p; 195 196 cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0); 197 if (dir < 0) 198 cxt->sflags |= SF_REVERSE; /* not strictly needed */ 199 200 cxt->direction = dir; 201 cxt->history_pos = cxt->save_line; 202 203 rl_maybe_save_line (); 204 205 /* Clear the undo list, since reading the search string should create its 206 own undo list, and the whole list will end up being freed when we 207 finish reading the search string. */ 208 rl_undo_list = 0; 209 210 /* Use the line buffer to read the search string. */ 211 rl_line_buffer[0] = 0; 212 rl_end = rl_point = 0; 213 214 p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 215 rl_message (p, 0, 0); 216 free (p); 217 218 RL_SETSTATE(RL_STATE_NSEARCH); 219 220 _rl_nscxt = cxt; 221 222 return cxt; 223} 224 225static int 226_rl_nsearch_cleanup (cxt, r) 227 _rl_search_cxt *cxt; 228 int r; 229{ 230 _rl_scxt_dispose (cxt, 0); 231 _rl_nscxt = 0; 232 233 RL_UNSETSTATE(RL_STATE_NSEARCH); 234 235 return (r != 1); 236} 237 238static void 239_rl_nsearch_abort (cxt) 240 _rl_search_cxt *cxt; 241{ 242 rl_maybe_unsave_line (); 243 rl_clear_message (); 244 rl_point = cxt->save_point; 245 rl_mark = cxt->save_mark; 246 rl_restore_prompt (); 247 248 RL_UNSETSTATE (RL_STATE_NSEARCH); 249} 250 251/* Process just-read character C according to search context CXT. Return -1 252 if the caller should abort the search, 0 if we should break out of the 253 loop, and 1 if we should continue to read characters. */ 254static int 255_rl_nsearch_dispatch (cxt, c) 256 _rl_search_cxt *cxt; 257 int c; 258{ 259 switch (c) 260 { 261 case CTRL('W'): 262 rl_unix_word_rubout (1, c); 263 break; 264 265 case CTRL('U'): 266 rl_unix_line_discard (1, c); 267 break; 268 269 case RETURN: 270 case NEWLINE: 271 return 0; 272 273 case CTRL('H'): 274 case RUBOUT: 275 if (rl_point == 0) 276 { 277 _rl_nsearch_abort (cxt); 278 return -1; 279 } 280 _rl_rubout_char (1, c); 281 break; 282 283 case CTRL('C'): 284 case CTRL('G'): 285 rl_ding (); 286 _rl_nsearch_abort (cxt); 287 return -1; 288 289 default: 290#if defined (HANDLE_MULTIBYTE) 291 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 292 rl_insert_text (cxt->mb); 293 else 294#endif 295 _rl_insert_char (1, c); 296 break; 297 } 298 299 (*rl_redisplay_function) (); 300 return 1; 301} 302 303/* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return 304 -1 if the search should be aborted, any other value means to clean up 305 using _rl_nsearch_cleanup (). Returns 1 if the search was successful, 306 0 otherwise. */ 307static int 308_rl_nsearch_dosearch (cxt) 309 _rl_search_cxt *cxt; 310{ 311 rl_mark = cxt->save_mark; 312 313 /* If rl_point == 0, we want to re-use the previous search string and 314 start from the saved history position. If there's no previous search 315 string, punt. */ 316 if (rl_point == 0) 317 { 318 if (noninc_search_string == 0) 319 { 320 rl_ding (); 321 rl_restore_prompt (); 322 RL_UNSETSTATE (RL_STATE_NSEARCH); 323 return -1; 324 } 325 } 326 else 327 { 328 /* We want to start the search from the current history position. */ 329 noninc_history_pos = cxt->save_line; 330 FREE (noninc_search_string); 331 noninc_search_string = savestring (rl_line_buffer); 332 333 /* If we don't want the subsequent undo list generated by the search 334 matching a history line to include the contents of the search string, 335 we need to clear rl_line_buffer here. For now, we just clear the 336 undo list generated by reading the search string. (If the search 337 fails, the old undo list will be restored by rl_maybe_unsave_line.) */ 338 rl_free_undo_list (); 339 } 340 341 rl_restore_prompt (); 342 return (noninc_dosearch (noninc_search_string, cxt->direction)); 343} 344 345/* Search non-interactively through the history list. DIR < 0 means to 346 search backwards through the history of previous commands; otherwise 347 the search is for commands subsequent to the current position in the 348 history list. PCHAR is the character to use for prompting when reading 349 the search string; if not specified (0), it defaults to `:'. */ 350static int 351noninc_search (dir, pchar) 352 int dir; 353 int pchar; 354{ 355 _rl_search_cxt *cxt; 356 int c, r; 357 358 cxt = _rl_nsearch_init (dir, pchar); 359 360 if (RL_ISSTATE (RL_STATE_CALLBACK)) 361 return (0); 362 363 /* Read the search string. */ 364 r = 0; 365 while (1) 366 { 367 c = _rl_search_getchar (cxt); 368 369 if (c == 0) 370 break; 371 372 r = _rl_nsearch_dispatch (cxt, c); 373 if (r < 0) 374 return 1; 375 else if (r == 0) 376 break; 377 } 378 379 r = _rl_nsearch_dosearch (cxt); 380 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 381} 382 383/* Search forward through the history list for a string. If the vi-mode 384 code calls this, KEY will be `?'. */ 385int 386rl_noninc_forward_search (count, key) 387 int count, key; 388{ 389 return noninc_search (1, (key == '?') ? '?' : 0); 390} 391 392/* Reverse search the history list for a string. If the vi-mode code 393 calls this, KEY will be `/'. */ 394int 395rl_noninc_reverse_search (count, key) 396 int count, key; 397{ 398 return noninc_search (-1, (key == '/') ? '/' : 0); 399} 400 401/* Search forward through the history list for the last string searched 402 for. If there is no saved search string, abort. */ 403int 404rl_noninc_forward_search_again (count, key) 405 int count, key; 406{ 407 int r; 408 409 if (!noninc_search_string) 410 { 411 rl_ding (); 412 return (-1); 413 } 414 r = noninc_dosearch (noninc_search_string, 1); 415 return (r != 1); 416} 417 418/* Reverse search in the history list for the last string searched 419 for. If there is no saved search string, abort. */ 420int 421rl_noninc_reverse_search_again (count, key) 422 int count, key; 423{ 424 int r; 425 426 if (!noninc_search_string) 427 { 428 rl_ding (); 429 return (-1); 430 } 431 r = noninc_dosearch (noninc_search_string, -1); 432 return (r != 1); 433} 434 435#if defined (READLINE_CALLBACKS) 436int 437_rl_nsearch_callback (cxt) 438 _rl_search_cxt *cxt; 439{ 440 int c, r; 441 442 c = _rl_search_getchar (cxt); 443 r = _rl_nsearch_dispatch (cxt, c); 444 if (r != 0) 445 return 1; 446 447 r = _rl_nsearch_dosearch (cxt); 448 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 449} 450#endif 451 452static int 453rl_history_search_internal (count, dir) 454 int count, dir; 455{ 456 HIST_ENTRY *temp; 457 int ret, oldpos; 458 459 rl_maybe_save_line (); 460 temp = (HIST_ENTRY *)NULL; 461 462 /* Search COUNT times through the history for a line whose prefix 463 matches history_search_string. When this loop finishes, TEMP, 464 if non-null, is the history line to copy into the line buffer. */ 465 while (count) 466 { 467 ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir); 468 if (ret == -1) 469 break; 470 471 /* Get the history entry we found. */ 472 rl_history_search_pos = ret; 473 oldpos = where_history (); 474 history_set_pos (rl_history_search_pos); 475 temp = current_history (); 476 history_set_pos (oldpos); 477 478 /* Don't find multiple instances of the same line. */ 479 if (prev_line_found && STREQ (prev_line_found, temp->line)) 480 continue; 481 prev_line_found = temp->line; 482 count--; 483 } 484 485 /* If we didn't find anything at all, return. */ 486 if (temp == 0) 487 { 488 rl_maybe_unsave_line (); 489 rl_ding (); 490 /* If you don't want the saved history line (last match) to show up 491 in the line buffer after the search fails, change the #if 0 to 492 #if 1 */ 493#if 0 494 if (rl_point > rl_history_search_len) 495 { 496 rl_point = rl_end = rl_history_search_len; 497 rl_line_buffer[rl_end] = '\0'; 498 rl_mark = 0; 499 } 500#else 501 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ 502 rl_mark = rl_end; 503#endif 504 return 1; 505 } 506 507 /* Copy the line we found into the current line buffer. */ 508 make_history_line_current (temp); 509 510 rl_point = rl_history_search_len; 511 rl_mark = rl_end; 512 513 return 0; 514} 515 516static void 517rl_history_search_reinit () 518{ 519 rl_history_search_pos = where_history (); 520 rl_history_search_len = rl_point; 521 prev_line_found = (char *)NULL; 522 if (rl_point) 523 { 524 if (rl_history_search_len >= history_string_size - 2) 525 { 526 history_string_size = rl_history_search_len + 2; 527 history_search_string = (char *)xrealloc (history_search_string, history_string_size); 528 } 529 history_search_string[0] = '^'; 530 strncpy (history_search_string + 1, rl_line_buffer, rl_point); 531 history_search_string[rl_point + 1] = '\0'; 532 } 533 _rl_free_saved_history_line (); 534} 535 536/* Search forward in the history for the string of characters 537 from the start of the line to rl_point. This is a non-incremental 538 search. */ 539int 540rl_history_search_forward (count, ignore) 541 int count, ignore; 542{ 543 if (count == 0) 544 return (0); 545 546 if (rl_last_func != rl_history_search_forward && 547 rl_last_func != rl_history_search_backward) 548 rl_history_search_reinit (); 549 550 if (rl_history_search_len == 0) 551 return (rl_get_next_history (count, ignore)); 552 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 553} 554 555/* Search backward through the history for the string of characters 556 from the start of the line to rl_point. This is a non-incremental 557 search. */ 558int 559rl_history_search_backward (count, ignore) 560 int count, ignore; 561{ 562 if (count == 0) 563 return (0); 564 565 if (rl_last_func != rl_history_search_forward && 566 rl_last_func != rl_history_search_backward) 567 rl_history_search_reinit (); 568 569 if (rl_history_search_len == 0) 570 return (rl_get_previous_history (count, ignore)); 571 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 572} 573