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