1/* search.c - code for non-incremental searching in emacs and vi modes. */ 2 3/* Copyright (C) 1992-2020 Free Software Foundation, Inc. 4 5 This file is part of the GNU Readline Library (Readline), a library 6 for reading lines of text with interactive input and history editing. 7 8 Readline is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 Readline is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Readline. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#define READLINE_LIBRARY 23 24#if defined (HAVE_CONFIG_H) 25# include <config.h> 26#endif 27 28#include <sys/types.h> 29#include <stdio.h> 30 31#if defined (HAVE_UNISTD_H) 32# include <unistd.h> 33#endif 34 35#if defined (HAVE_STDLIB_H) 36# include <stdlib.h> 37#else 38# include "ansi_stdlib.h" 39#endif 40 41#include "rldefs.h" 42#include "rlmbutil.h" 43 44#include "readline.h" 45#include "history.h" 46#include "histlib.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 void _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 int rl_history_search_flags; 71 72static char *history_search_string; 73static int history_string_size; 74 75static void make_history_line_current PARAMS((HIST_ENTRY *)); 76static int noninc_search_from_pos PARAMS((char *, int, int, int, int *)); 77static int noninc_dosearch PARAMS((char *, int, int)); 78static int noninc_search PARAMS((int, int)); 79static int rl_history_search_internal PARAMS((int, int)); 80static void rl_history_search_reinit PARAMS((int)); 81 82static _rl_search_cxt *_rl_nsearch_init PARAMS((int, 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 (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 (char *string, int pos, int dir, int flags, int *ncp) 115{ 116 int ret, old, sflags; 117 char *s; 118 119 if (pos < 0) 120 return -1; 121 122 old = where_history (); 123 if (history_set_pos (pos) == 0) 124 return -1; 125 126 RL_SETSTATE(RL_STATE_SEARCH); 127 /* These functions return the match offset in the line; history_offset gives 128 the matching line in the history list */ 129 if (flags & SF_PATTERN) 130 { 131 s = string; 132 sflags = 0; /* Non-anchored search */ 133 if (*s == '^') 134 { 135 sflags |= ANCHORED_SEARCH; 136 s++; 137 } 138 ret = _hs_history_patsearch (s, dir, sflags); 139 } 140 else if (*string == '^') 141 ret = history_search_prefix (string + 1, dir); 142 else 143 ret = history_search (string, dir); 144 RL_UNSETSTATE(RL_STATE_SEARCH); 145 146 if (ncp) 147 *ncp = ret; /* caller will catch -1 to indicate no-op */ 148 149 if (ret != -1) 150 ret = where_history (); 151 152 history_set_pos (old); 153 return (ret); 154} 155 156/* Search for a line in the history containing STRING. If DIR is < 0, the 157 search is backwards through previous entries, else through subsequent 158 entries. Returns 1 if the search was successful, 0 otherwise. */ 159static int 160noninc_dosearch (char *string, int dir, int flags) 161{ 162 int oldpos, pos, ind; 163 HIST_ENTRY *entry; 164 165 if (string == 0 || *string == '\0' || noninc_history_pos < 0) 166 { 167 rl_ding (); 168 return 0; 169 } 170 171 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir, flags, &ind); 172 if (pos == -1) 173 { 174 /* Search failed, current history position unchanged. */ 175 rl_maybe_unsave_line (); 176 rl_clear_message (); 177 rl_point = 0; 178 rl_ding (); 179 return 0; 180 } 181 182 noninc_history_pos = pos; 183 184 oldpos = where_history (); 185 history_set_pos (noninc_history_pos); 186 entry = current_history (); /* will never be NULL after successful search */ 187 188#if defined (VI_MODE) 189 if (rl_editing_mode != vi_mode) 190#endif 191 history_set_pos (oldpos); 192 193 make_history_line_current (entry); 194 195 if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind > 0 && ind < rl_end) 196 { 197 rl_point = ind; 198 rl_mark = ind + strlen (string); 199 if (rl_mark > rl_end) 200 rl_mark = rl_end; /* can't happen? */ 201 rl_activate_mark (); 202 } 203 else 204 { 205 rl_point = 0; 206 rl_mark = rl_end; 207 } 208 209 rl_clear_message (); 210 return 1; 211} 212 213static _rl_search_cxt * 214_rl_nsearch_init (int dir, int pchar) 215{ 216 _rl_search_cxt *cxt; 217 char *p; 218 219 cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0); 220 if (dir < 0) 221 cxt->sflags |= SF_REVERSE; /* not strictly needed */ 222#if defined (VI_MODE) 223 if (VI_COMMAND_MODE() && (pchar == '?' || pchar == '/')) 224 cxt->sflags |= SF_PATTERN; 225#endif 226 227 cxt->direction = dir; 228 cxt->history_pos = cxt->save_line; 229 230 rl_maybe_save_line (); 231 232 /* Clear the undo list, since reading the search string should create its 233 own undo list, and the whole list will end up being freed when we 234 finish reading the search string. */ 235 rl_undo_list = 0; 236 237 /* Use the line buffer to read the search string. */ 238 rl_line_buffer[0] = 0; 239 rl_end = rl_point = 0; 240 241 p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 242 rl_message ("%s", p); 243 xfree (p); 244 245 RL_SETSTATE(RL_STATE_NSEARCH); 246 247 _rl_nscxt = cxt; 248 249 return cxt; 250} 251 252int 253_rl_nsearch_cleanup (_rl_search_cxt *cxt, int r) 254{ 255 _rl_scxt_dispose (cxt, 0); 256 _rl_nscxt = 0; 257 258 RL_UNSETSTATE(RL_STATE_NSEARCH); 259 260 return (r != 1); 261} 262 263static void 264_rl_nsearch_abort (_rl_search_cxt *cxt) 265{ 266 rl_maybe_unsave_line (); 267 rl_clear_message (); 268 rl_point = cxt->save_point; 269 rl_mark = cxt->save_mark; 270 _rl_fix_point (1); 271 rl_restore_prompt (); 272 273 RL_UNSETSTATE (RL_STATE_NSEARCH); 274} 275 276/* Process just-read character C according to search context CXT. Return -1 277 if the caller should abort the search, 0 if we should break out of the 278 loop, and 1 if we should continue to read characters. */ 279static int 280_rl_nsearch_dispatch (_rl_search_cxt *cxt, int c) 281{ 282 int n; 283 284 if (c < 0) 285 c = CTRL ('C'); 286 287 switch (c) 288 { 289 case CTRL('W'): 290 rl_unix_word_rubout (1, c); 291 break; 292 293 case CTRL('U'): 294 rl_unix_line_discard (1, c); 295 break; 296 297 case RETURN: 298 case NEWLINE: 299 return 0; 300 301 case CTRL('H'): 302 case RUBOUT: 303 if (rl_point == 0) 304 { 305 _rl_nsearch_abort (cxt); 306 return -1; 307 } 308 _rl_rubout_char (1, c); 309 break; 310 311 case CTRL('C'): 312 case CTRL('G'): 313 rl_ding (); 314 _rl_nsearch_abort (cxt); 315 return -1; 316 317 case ESC: 318 /* XXX - experimental code to allow users to bracketed-paste into the 319 search string. Similar code is in isearch.c:_rl_isearch_dispatch(). 320 The difference here is that the bracketed paste sometimes doesn't 321 paste everything, so checking for the prefix and the suffix in the 322 input queue doesn't work well. We just have to check to see if the 323 number of chars in the input queue is enough for the bracketed paste 324 prefix and hope for the best. */ 325 if (_rl_enable_bracketed_paste && ((n = _rl_nchars_available ()) >= (BRACK_PASTE_SLEN-1))) 326 { 327 if (_rl_read_bracketed_paste_prefix (c) == 1) 328 rl_bracketed_paste_begin (1, c); 329 else 330 { 331 c = rl_read_key (); /* get the ESC that got pushed back */ 332 _rl_insert_char (1, c); 333 } 334 } 335 else 336 _rl_insert_char (1, c); 337 break; 338 339 default: 340#if defined (HANDLE_MULTIBYTE) 341 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 342 rl_insert_text (cxt->mb); 343 else 344#endif 345 _rl_insert_char (1, c); 346 break; 347 } 348 349 (*rl_redisplay_function) (); 350 rl_deactivate_mark (); 351 return 1; 352} 353 354/* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return 355 -1 if the search should be aborted, any other value means to clean up 356 using _rl_nsearch_cleanup (). Returns 1 if the search was successful, 357 0 otherwise. */ 358static int 359_rl_nsearch_dosearch (_rl_search_cxt *cxt) 360{ 361 rl_mark = cxt->save_mark; 362 363 /* If rl_point == 0, we want to re-use the previous search string and 364 start from the saved history position. If there's no previous search 365 string, punt. */ 366 if (rl_point == 0) 367 { 368 if (noninc_search_string == 0) 369 { 370 rl_ding (); 371 rl_restore_prompt (); 372 RL_UNSETSTATE (RL_STATE_NSEARCH); 373 return -1; 374 } 375 } 376 else 377 { 378 /* We want to start the search from the current history position. */ 379 noninc_history_pos = cxt->save_line; 380 FREE (noninc_search_string); 381 noninc_search_string = savestring (rl_line_buffer); 382 383 /* If we don't want the subsequent undo list generated by the search 384 matching a history line to include the contents of the search string, 385 we need to clear rl_line_buffer here. For now, we just clear the 386 undo list generated by reading the search string. (If the search 387 fails, the old undo list will be restored by rl_maybe_unsave_line.) */ 388 rl_free_undo_list (); 389 } 390 391 rl_restore_prompt (); 392 return (noninc_dosearch (noninc_search_string, cxt->direction, cxt->sflags&SF_PATTERN)); 393} 394 395/* Search non-interactively through the history list. DIR < 0 means to 396 search backwards through the history of previous commands; otherwise 397 the search is for commands subsequent to the current position in the 398 history list. PCHAR is the character to use for prompting when reading 399 the search string; if not specified (0), it defaults to `:'. */ 400static int 401noninc_search (int dir, int pchar) 402{ 403 _rl_search_cxt *cxt; 404 int c, r; 405 406 cxt = _rl_nsearch_init (dir, pchar); 407 408 if (RL_ISSTATE (RL_STATE_CALLBACK)) 409 return (0); 410 411 /* Read the search string. */ 412 r = 0; 413 while (1) 414 { 415 c = _rl_search_getchar (cxt); 416 417 if (c < 0) 418 { 419 _rl_nsearch_abort (cxt); 420 return 1; 421 } 422 423 if (c == 0) 424 break; 425 426 r = _rl_nsearch_dispatch (cxt, c); 427 if (r < 0) 428 return 1; 429 else if (r == 0) 430 break; 431 } 432 433 r = _rl_nsearch_dosearch (cxt); 434 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 435} 436 437/* Search forward through the history list for a string. If the vi-mode 438 code calls this, KEY will be `?'. */ 439int 440rl_noninc_forward_search (int count, int key) 441{ 442 return noninc_search (1, (key == '?') ? '?' : 0); 443} 444 445/* Reverse search the history list for a string. If the vi-mode code 446 calls this, KEY will be `/'. */ 447int 448rl_noninc_reverse_search (int count, int key) 449{ 450 return noninc_search (-1, (key == '/') ? '/' : 0); 451} 452 453/* Search forward through the history list for the last string searched 454 for. If there is no saved search string, abort. If the vi-mode code 455 calls this, KEY will be `N'. */ 456int 457rl_noninc_forward_search_again (int count, int key) 458{ 459 int r; 460 461 if (!noninc_search_string) 462 { 463 rl_ding (); 464 return (1); 465 } 466#if defined (VI_MODE) 467 if (VI_COMMAND_MODE() && key == 'N') 468 r = noninc_dosearch (noninc_search_string, 1, SF_PATTERN); 469 else 470#endif 471 r = noninc_dosearch (noninc_search_string, 1, 0); 472 return (r != 1); 473} 474 475/* Reverse search in the history list for the last string searched 476 for. If there is no saved search string, abort. If the vi-mode code 477 calls this, KEY will be `n'. */ 478int 479rl_noninc_reverse_search_again (int count, int key) 480{ 481 int r; 482 483 if (!noninc_search_string) 484 { 485 rl_ding (); 486 return (1); 487 } 488#if defined (VI_MODE) 489 if (VI_COMMAND_MODE() && key == 'n') 490 r = noninc_dosearch (noninc_search_string, -1, SF_PATTERN); 491 else 492#endif 493 r = noninc_dosearch (noninc_search_string, -1, 0); 494 return (r != 1); 495} 496 497#if defined (READLINE_CALLBACKS) 498int 499_rl_nsearch_callback (_rl_search_cxt *cxt) 500{ 501 int c, r; 502 503 c = _rl_search_getchar (cxt); 504 if (c <= 0) 505 { 506 if (c < 0) 507 _rl_nsearch_abort (cxt); 508 return 1; 509 } 510 r = _rl_nsearch_dispatch (cxt, c); 511 if (r != 0) 512 return 1; 513 514 r = _rl_nsearch_dosearch (cxt); 515 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 516} 517#endif 518 519static int 520rl_history_search_internal (int count, int dir) 521{ 522 HIST_ENTRY *temp; 523 int ret, oldpos, newcol; 524 char *t; 525 526 rl_maybe_save_line (); 527 temp = (HIST_ENTRY *)NULL; 528 529 /* Search COUNT times through the history for a line matching 530 history_search_string. If history_search_string[0] == '^', the 531 line must match from the start; otherwise any substring can match. 532 When this loop finishes, TEMP, if non-null, is the history line to 533 copy into the line buffer. */ 534 while (count) 535 { 536 RL_CHECK_SIGNALS (); 537 ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir, 0, &newcol); 538 if (ret == -1) 539 break; 540 541 /* Get the history entry we found. */ 542 rl_history_search_pos = ret; 543 oldpos = where_history (); 544 history_set_pos (rl_history_search_pos); 545 temp = current_history (); /* will never be NULL after successful search */ 546 history_set_pos (oldpos); 547 548 /* Don't find multiple instances of the same line. */ 549 if (prev_line_found && STREQ (prev_line_found, temp->line)) 550 continue; 551 prev_line_found = temp->line; 552 count--; 553 } 554 555 /* If we didn't find anything at all, return. */ 556 if (temp == 0) 557 { 558 rl_maybe_unsave_line (); 559 rl_ding (); 560 /* If you don't want the saved history line (last match) to show up 561 in the line buffer after the search fails, change the #if 0 to 562 #if 1 */ 563#if 0 564 if (rl_point > rl_history_search_len) 565 { 566 rl_point = rl_end = rl_history_search_len; 567 rl_line_buffer[rl_end] = '\0'; 568 rl_mark = 0; 569 } 570#else 571 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ 572 rl_mark = rl_end; 573#endif 574 return 1; 575 } 576 577 /* Copy the line we found into the current line buffer. */ 578 make_history_line_current (temp); 579 580 /* decide where to put rl_point -- need to change this for pattern search */ 581 if (rl_history_search_flags & ANCHORED_SEARCH) 582 rl_point = rl_history_search_len; /* easy case */ 583 else 584 { 585#if 0 586 t = strstr (rl_line_buffer, history_search_string); /* XXX */ 587 rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end; 588#else 589 rl_point = (newcol >= 0) ? newcol : rl_end; 590#endif 591 } 592 rl_mark = rl_end; 593 594 return 0; 595} 596 597static void 598rl_history_search_reinit (int flags) 599{ 600 int sind; 601 602 rl_history_search_pos = where_history (); 603 rl_history_search_len = rl_point; 604 rl_history_search_flags = flags; 605 606 prev_line_found = (char *)NULL; 607 if (rl_point) 608 { 609 /* Allocate enough space for anchored and non-anchored searches */ 610 if (rl_history_search_len >= history_string_size - 2) 611 { 612 history_string_size = rl_history_search_len + 2; 613 history_search_string = (char *)xrealloc (history_search_string, history_string_size); 614 } 615 sind = 0; 616 if (flags & ANCHORED_SEARCH) 617 history_search_string[sind++] = '^'; 618 strncpy (history_search_string + sind, rl_line_buffer, rl_point); 619 history_search_string[rl_point + sind] = '\0'; 620 } 621 _rl_free_saved_history_line (); 622} 623 624/* Search forward in the history for the string of characters 625 from the start of the line to rl_point. This is a non-incremental 626 search. The search is anchored to the beginning of the history line. */ 627int 628rl_history_search_forward (int count, int ignore) 629{ 630 if (count == 0) 631 return (0); 632 633 if (rl_last_func != rl_history_search_forward && 634 rl_last_func != rl_history_search_backward) 635 rl_history_search_reinit (ANCHORED_SEARCH); 636 637 if (rl_history_search_len == 0) 638 return (rl_get_next_history (count, ignore)); 639 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 640} 641 642/* Search backward through the history for the string of characters 643 from the start of the line to rl_point. This is a non-incremental 644 search. */ 645int 646rl_history_search_backward (int count, int ignore) 647{ 648 if (count == 0) 649 return (0); 650 651 if (rl_last_func != rl_history_search_forward && 652 rl_last_func != rl_history_search_backward) 653 rl_history_search_reinit (ANCHORED_SEARCH); 654 655 if (rl_history_search_len == 0) 656 return (rl_get_previous_history (count, ignore)); 657 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 658} 659 660/* Search forward in the history for the string of characters 661 from the start of the line to rl_point. This is a non-incremental 662 search. The search succeeds if the search string is present anywhere 663 in the history line. */ 664int 665rl_history_substr_search_forward (int count, int ignore) 666{ 667 if (count == 0) 668 return (0); 669 670 if (rl_last_func != rl_history_substr_search_forward && 671 rl_last_func != rl_history_substr_search_backward) 672 rl_history_search_reinit (NON_ANCHORED_SEARCH); 673 674 if (rl_history_search_len == 0) 675 return (rl_get_next_history (count, ignore)); 676 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 677} 678 679/* Search backward through the history for the string of characters 680 from the start of the line to rl_point. This is a non-incremental 681 search. */ 682int 683rl_history_substr_search_backward (int count, int ignore) 684{ 685 if (count == 0) 686 return (0); 687 688 if (rl_last_func != rl_history_substr_search_forward && 689 rl_last_func != rl_history_substr_search_backward) 690 rl_history_search_reinit (NON_ANCHORED_SEARCH); 691 692 if (rl_history_search_len == 0) 693 return (rl_get_previous_history (count, ignore)); 694 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 695} 696