isearch.c revision 173404
1210284Sjmallett/* **************************************************************** */ 2215990Sjmallett/* */ 3215990Sjmallett/* I-Search and Searching */ 4210284Sjmallett/* */ 5210284Sjmallett/* **************************************************************** */ 6215990Sjmallett 7215990Sjmallett/* Copyright (C) 1987-2005 Free Software Foundation, Inc. 8215990Sjmallett 9210284Sjmallett This file contains the Readline Library (the Library), a set of 10215990Sjmallett routines for providing Emacs style line input to programs that ask 11215990Sjmallett for it. 12210284Sjmallett 13215990Sjmallett The Library is free software; you can redistribute it and/or modify 14215990Sjmallett it under the terms of the GNU General Public License as published by 15215990Sjmallett the Free Software Foundation; either version 2, or (at your option) 16215990Sjmallett any later version. 17210284Sjmallett 18215990Sjmallett The Library is distributed in the hope that it will be useful, but 19215990Sjmallett WITHOUT ANY WARRANTY; without even the implied warranty of 20215990Sjmallett MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21215990Sjmallett General Public License for more details. 22210284Sjmallett 23215990Sjmallett The GNU General Public License is often shipped with GNU software, and 24215990Sjmallett is generally kept in a file called COPYING or LICENSE. If you do not 25215990Sjmallett have a copy of the license, write to the Free Software Foundation, 26215990Sjmallett 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 27210284Sjmallett#define READLINE_LIBRARY 28215990Sjmallett 29215990Sjmallett#if defined (HAVE_CONFIG_H) 30215990Sjmallett# include <config.h> 31215990Sjmallett#endif 32215990Sjmallett 33215990Sjmallett#include <sys/types.h> 34215990Sjmallett 35215990Sjmallett#include <stdio.h> 36215990Sjmallett 37215990Sjmallett#if defined (HAVE_UNISTD_H) 38215990Sjmallett# include <unistd.h> 39210284Sjmallett#endif 40210284Sjmallett 41210284Sjmallett#if defined (HAVE_STDLIB_H) 42210284Sjmallett# include <stdlib.h> 43210284Sjmallett#else 44210284Sjmallett# include "ansi_stdlib.h" 45210284Sjmallett#endif 46210284Sjmallett 47210284Sjmallett#include "rldefs.h" 48210284Sjmallett#include "rlmbutil.h" 49210284Sjmallett 50210284Sjmallett#include "readline.h" 51210284Sjmallett#include "history.h" 52210284Sjmallett 53210284Sjmallett#include "rlprivate.h" 54210284Sjmallett#include "xmalloc.h" 55210284Sjmallett 56210284Sjmallett/* Variables exported to other files in the readline library. */ 57210284Sjmallettchar *_rl_isearch_terminators = (char *)NULL; 58210284Sjmallett 59210284Sjmallett_rl_search_cxt *_rl_iscxt = 0; 60210284Sjmallett 61210284Sjmallett/* Variables imported from other files in the readline library. */ 62210284Sjmallettextern HIST_ENTRY *_rl_saved_line_for_history; 63210284Sjmallett 64215990Sjmallettstatic int rl_search_history PARAMS((int, int)); 65210284Sjmallett 66210284Sjmallettstatic _rl_search_cxt *_rl_isearch_init PARAMS((int)); 67210284Sjmallettstatic void _rl_isearch_fini PARAMS((_rl_search_cxt *)); 68210284Sjmallettstatic int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int)); 69210284Sjmallett 70210284Sjmallett/* Last line found by the current incremental search, so we don't `find' 71210284Sjmallett identical lines many times in a row. Now part of isearch context. */ 72215990Sjmallett/* static char *prev_line_found; */ 73215990Sjmallett 74210284Sjmallett/* Last search string and its length. */ 75215990Sjmallettstatic char *last_isearch_string; 76210284Sjmallettstatic int last_isearch_string_len; 77210284Sjmallett 78210284Sjmallettstatic char *default_isearch_terminators = "\033\012"; 79210284Sjmallett 80210284Sjmallett_rl_search_cxt * 81210284Sjmallett_rl_scxt_alloc (type, flags) 82210284Sjmallett int type, flags; 83210284Sjmallett{ 84210284Sjmallett _rl_search_cxt *cxt; 85210284Sjmallett 86210284Sjmallett cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt)); 87210284Sjmallett 88210284Sjmallett cxt->type = type; 89210284Sjmallett cxt->sflags = flags; 90210284Sjmallett 91210284Sjmallett cxt->search_string = 0; 92210284Sjmallett cxt->search_string_size = cxt->search_string_index = 0; 93210284Sjmallett 94210284Sjmallett cxt->lines = 0; 95210284Sjmallett cxt->allocated_line = 0; 96210284Sjmallett cxt->hlen = cxt->hindex = 0; 97210284Sjmallett 98210284Sjmallett cxt->save_point = rl_point; 99210284Sjmallett cxt->save_mark = rl_mark; 100210284Sjmallett cxt->save_line = where_history (); 101210284Sjmallett cxt->last_found_line = cxt->save_line; 102210284Sjmallett cxt->prev_line_found = 0; 103210284Sjmallett 104210284Sjmallett cxt->save_undo_list = 0; 105210284Sjmallett 106210284Sjmallett cxt->history_pos = 0; 107210284Sjmallett cxt->direction = 0; 108210284Sjmallett 109210284Sjmallett cxt->lastc = 0; 110210284Sjmallett 111210284Sjmallett cxt->sline = 0; 112210284Sjmallett cxt->sline_len = cxt->sline_index = 0; 113210284Sjmallett 114210284Sjmallett cxt->search_terminators = 0; 115210284Sjmallett 116210284Sjmallett return cxt; 117210284Sjmallett} 118210284Sjmallett 119210284Sjmallettvoid 120210284Sjmallett_rl_scxt_dispose (cxt, flags) 121210284Sjmallett _rl_search_cxt *cxt; 122210284Sjmallett int flags; 123210284Sjmallett{ 124210284Sjmallett FREE (cxt->search_string); 125210284Sjmallett FREE (cxt->allocated_line); 126210284Sjmallett FREE (cxt->lines); 127210284Sjmallett 128210284Sjmallett free (cxt); 129210284Sjmallett} 130210284Sjmallett 131210284Sjmallett/* Search backwards through the history looking for a string which is typed 132210284Sjmallett interactively. Start with the current line. */ 133210284Sjmallettint 134210284Sjmallettrl_reverse_search_history (sign, key) 135210284Sjmallett int sign, key; 136210284Sjmallett{ 137210284Sjmallett return (rl_search_history (-sign, key)); 138210284Sjmallett} 139210284Sjmallett 140210284Sjmallett/* Search forwards through the history looking for a string which is typed 141210284Sjmallett interactively. Start with the current line. */ 142210284Sjmallettint 143210284Sjmallettrl_forward_search_history (sign, key) 144210284Sjmallett int sign, key; 145210284Sjmallett{ 146210284Sjmallett return (rl_search_history (sign, key)); 147210284Sjmallett} 148210284Sjmallett 149210284Sjmallett/* Display the current state of the search in the echo-area. 150210284Sjmallett SEARCH_STRING contains the string that is being searched for, 151210284Sjmallett DIRECTION is zero for forward, or non-zero for reverse, 152210284Sjmallett WHERE is the history list number of the current line. If it is 153210284Sjmallett -1, then this line is the starting one. */ 154210284Sjmallettstatic void 155210284Sjmallettrl_display_search (search_string, reverse_p, where) 156210284Sjmallett char *search_string; 157210284Sjmallett int reverse_p, where; 158210284Sjmallett{ 159210284Sjmallett char *message; 160210284Sjmallett int msglen, searchlen; 161210284Sjmallett 162210284Sjmallett searchlen = (search_string && *search_string) ? strlen (search_string) : 0; 163210284Sjmallett 164210284Sjmallett message = (char *)xmalloc (searchlen + 33); 165210284Sjmallett msglen = 0; 166210284Sjmallett 167210284Sjmallett#if defined (NOTDEF) 168210284Sjmallett if (where != -1) 169210284Sjmallett { 170210284Sjmallett sprintf (message, "[%d]", where + history_base); 171210284Sjmallett msglen = strlen (message); 172210284Sjmallett } 173210284Sjmallett#endif /* NOTDEF */ 174210284Sjmallett 175210284Sjmallett message[msglen++] = '('; 176210284Sjmallett 177210284Sjmallett if (reverse_p) 178210284Sjmallett { 179210284Sjmallett strcpy (message + msglen, "reverse-"); 180210284Sjmallett msglen += 8; 181210284Sjmallett } 182210284Sjmallett 183210284Sjmallett strcpy (message + msglen, "i-search)`"); 184210284Sjmallett msglen += 10; 185210284Sjmallett 186210284Sjmallett if (search_string) 187210284Sjmallett { 188210284Sjmallett strcpy (message + msglen, search_string); 189210284Sjmallett msglen += searchlen; 190210284Sjmallett } 191210284Sjmallett 192210284Sjmallett strcpy (message + msglen, "': "); 193210284Sjmallett 194210284Sjmallett rl_message ("%s", message); 195210284Sjmallett free (message); 196210284Sjmallett (*rl_redisplay_function) (); 197210284Sjmallett} 198210284Sjmallett 199210284Sjmallettstatic _rl_search_cxt * 200210284Sjmallett_rl_isearch_init (direction) 201210284Sjmallett int direction; 202210284Sjmallett{ 203210284Sjmallett _rl_search_cxt *cxt; 204210284Sjmallett register int i; 205210284Sjmallett HIST_ENTRY **hlist; 206210284Sjmallett 207210284Sjmallett cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0); 208210284Sjmallett if (direction < 0) 209210284Sjmallett cxt->sflags |= SF_REVERSE; 210210284Sjmallett 211210284Sjmallett cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators 212210284Sjmallett : default_isearch_terminators; 213210284Sjmallett 214210284Sjmallett /* Create an arrary of pointers to the lines that we want to search. */ 215210284Sjmallett hlist = history_list (); 216210284Sjmallett rl_maybe_replace_line (); 217210284Sjmallett i = 0; 218210284Sjmallett if (hlist) 219210284Sjmallett for (i = 0; hlist[i]; i++); 220210284Sjmallett 221210284Sjmallett /* Allocate space for this many lines, +1 for the current input line, 222210284Sjmallett and remember those lines. */ 223210284Sjmallett cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *)); 224210284Sjmallett for (i = 0; i < cxt->hlen; i++) 225210284Sjmallett cxt->lines[i] = hlist[i]->line; 226210284Sjmallett 227210284Sjmallett if (_rl_saved_line_for_history) 228210284Sjmallett cxt->lines[i] = _rl_saved_line_for_history->line; 229210284Sjmallett else 230210284Sjmallett { 231210284Sjmallett /* Keep track of this so we can free it. */ 232210284Sjmallett cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer)); 233210284Sjmallett strcpy (cxt->allocated_line, &rl_line_buffer[0]); 234210284Sjmallett cxt->lines[i] = cxt->allocated_line; 235210284Sjmallett } 236210284Sjmallett 237210284Sjmallett cxt->hlen++; 238210284Sjmallett 239210284Sjmallett /* The line where we start the search. */ 240210284Sjmallett cxt->history_pos = cxt->save_line; 241210284Sjmallett 242210284Sjmallett rl_save_prompt (); 243210284Sjmallett 244210284Sjmallett /* Initialize search parameters. */ 245210284Sjmallett cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128); 246210284Sjmallett cxt->search_string[cxt->search_string_index = 0] = '\0'; 247210284Sjmallett 248210284Sjmallett /* Normalize DIRECTION into 1 or -1. */ 249210284Sjmallett cxt->direction = (direction >= 0) ? 1 : -1; 250210284Sjmallett 251210284Sjmallett cxt->sline = rl_line_buffer; 252210284Sjmallett cxt->sline_len = strlen (cxt->sline); 253210284Sjmallett cxt->sline_index = rl_point; 254210284Sjmallett 255210284Sjmallett _rl_iscxt = cxt; /* save globally */ 256210284Sjmallett 257210284Sjmallett return cxt; 258210284Sjmallett} 259210284Sjmallett 260210284Sjmallettstatic void 261210284Sjmallett_rl_isearch_fini (cxt) 262210284Sjmallett _rl_search_cxt *cxt; 263210284Sjmallett{ 264210284Sjmallett /* First put back the original state. */ 265210284Sjmallett strcpy (rl_line_buffer, cxt->lines[cxt->save_line]); 266210284Sjmallett 267210284Sjmallett rl_restore_prompt (); 268210284Sjmallett 269210284Sjmallett /* Save the search string for possible later use. */ 270210284Sjmallett FREE (last_isearch_string); 271210284Sjmallett last_isearch_string = cxt->search_string; 272210284Sjmallett last_isearch_string_len = cxt->search_string_index; 273210284Sjmallett cxt->search_string = 0; 274210284Sjmallett 275210284Sjmallett if (cxt->last_found_line < cxt->save_line) 276210284Sjmallett rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0); 277210284Sjmallett else 278210284Sjmallett rl_get_next_history (cxt->last_found_line - cxt->save_line, 0); 279210284Sjmallett 280210284Sjmallett /* If the string was not found, put point at the end of the last matching 281210284Sjmallett line. If last_found_line == orig_line, we didn't find any matching 282210284Sjmallett history lines at all, so put point back in its original position. */ 283210284Sjmallett if (cxt->sline_index < 0) 284210284Sjmallett { 285210284Sjmallett if (cxt->last_found_line == cxt->save_line) 286210284Sjmallett cxt->sline_index = cxt->save_point; 287210284Sjmallett else 288210284Sjmallett cxt->sline_index = strlen (rl_line_buffer); 289210284Sjmallett rl_mark = cxt->save_mark; 290210284Sjmallett } 291210284Sjmallett 292210284Sjmallett rl_point = cxt->sline_index; 293210284Sjmallett /* Don't worry about where to put the mark here; rl_get_previous_history 294210284Sjmallett and rl_get_next_history take care of it. */ 295210284Sjmallett 296210284Sjmallett rl_clear_message (); 297210284Sjmallett} 298210284Sjmallett 299210284Sjmallettint 300210284Sjmallett_rl_search_getchar (cxt) 301210284Sjmallett _rl_search_cxt *cxt; 302210284Sjmallett{ 303210284Sjmallett int c; 304210284Sjmallett 305210284Sjmallett /* Read a key and decide how to proceed. */ 306210284Sjmallett RL_SETSTATE(RL_STATE_MOREINPUT); 307210284Sjmallett c = cxt->lastc = rl_read_key (); 308210284Sjmallett RL_UNSETSTATE(RL_STATE_MOREINPUT); 309210284Sjmallett 310210284Sjmallett#if defined (HANDLE_MULTIBYTE) 311210284Sjmallett if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 312210284Sjmallett c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX); 313210284Sjmallett#endif 314210284Sjmallett 315210284Sjmallett return c; 316210284Sjmallett} 317210284Sjmallett 318210284Sjmallett/* Process just-read character C according to isearch context CXT. Return 319210284Sjmallett -1 if the caller should just free the context and return, 0 if we should 320210284Sjmallett break out of the loop, and 1 if we should continue to read characters. */ 321210284Sjmallettint 322210284Sjmallett_rl_isearch_dispatch (cxt, c) 323210284Sjmallett _rl_search_cxt *cxt; 324210284Sjmallett int c; 325210284Sjmallett{ 326210284Sjmallett int n, wstart, wlen, limit, cval; 327210284Sjmallett rl_command_func_t *f; 328210284Sjmallett 329210284Sjmallett f = (rl_command_func_t *)NULL; 330210284Sjmallett 331210284Sjmallett if (c < 0) 332210284Sjmallett { 333210284Sjmallett cxt->sflags |= SF_FAILED; 334210284Sjmallett cxt->history_pos = cxt->last_found_line; 335210284Sjmallett return -1; 336210284Sjmallett } 337210284Sjmallett 338210284Sjmallett /* Translate the keys we do something with to opcodes. */ 339210284Sjmallett if (c >= 0 && _rl_keymap[c].type == ISFUNC) 340210284Sjmallett { 341210284Sjmallett f = _rl_keymap[c].function; 342210284Sjmallett 343210284Sjmallett if (f == rl_reverse_search_history) 344210284Sjmallett cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2; 345210284Sjmallett else if (f == rl_forward_search_history) 346210284Sjmallett cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1; 347210284Sjmallett else if (f == rl_rubout) 348210284Sjmallett cxt->lastc = -3; 349210284Sjmallett else if (c == CTRL ('G')) 350210284Sjmallett cxt->lastc = -4; 351210284Sjmallett else if (c == CTRL ('W')) /* XXX */ 352210284Sjmallett cxt->lastc = -5; 353210284Sjmallett else if (c == CTRL ('Y')) /* XXX */ 354210284Sjmallett cxt->lastc = -6; 355210284Sjmallett } 356210284Sjmallett 357210284Sjmallett /* The characters in isearch_terminators (set from the user-settable 358210284Sjmallett variable isearch-terminators) are used to terminate the search but 359210284Sjmallett not subsequently execute the character as a command. The default 360210284Sjmallett value is "\033\012" (ESC and C-J). */ 361210284Sjmallett if (strchr (cxt->search_terminators, cxt->lastc)) 362210284Sjmallett { 363210284Sjmallett /* ESC still terminates the search, but if there is pending 364210284Sjmallett input or if input arrives within 0.1 seconds (on systems 365210284Sjmallett with select(2)) it is used as a prefix character 366210284Sjmallett with rl_execute_next. WATCH OUT FOR THIS! This is intended 367210284Sjmallett to allow the arrow keys to be used like ^F and ^B are used 368210284Sjmallett to terminate the search and execute the movement command. 369210284Sjmallett XXX - since _rl_input_available depends on the application- 370210284Sjmallett settable keyboard timeout value, this could alternatively 371210284Sjmallett use _rl_input_queued(100000) */ 372210284Sjmallett if (cxt->lastc == ESC && _rl_input_available ()) 373210284Sjmallett rl_execute_next (ESC); 374210284Sjmallett return (0); 375210284Sjmallett } 376210284Sjmallett 377210284Sjmallett#define ENDSRCH_CHAR(c) \ 378210284Sjmallett ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) 379210284Sjmallett 380210284Sjmallett#if defined (HANDLE_MULTIBYTE) 381210284Sjmallett if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 382210284Sjmallett { 383210284Sjmallett if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc)) 384210284Sjmallett { 385210284Sjmallett /* This sets rl_pending_input to c; it will be picked up the next 386210284Sjmallett time rl_read_key is called. */ 387210284Sjmallett rl_execute_next (cxt->lastc); 388210284Sjmallett return (0); 389210284Sjmallett } 390210284Sjmallett } 391210284Sjmallett else 392210284Sjmallett#endif 393210284Sjmallett if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc)) 394210284Sjmallett { 395210284Sjmallett /* This sets rl_pending_input to LASTC; it will be picked up the next 396210284Sjmallett time rl_read_key is called. */ 397210284Sjmallett rl_execute_next (cxt->lastc); 398210284Sjmallett return (0); 399210284Sjmallett } 400210284Sjmallett 401210284Sjmallett /* Now dispatch on the character. `Opcodes' affect the search string or 402210284Sjmallett state. Other characters are added to the string. */ 403210284Sjmallett switch (cxt->lastc) 404210284Sjmallett { 405210284Sjmallett /* search again */ 406210284Sjmallett case -1: 407210284Sjmallett if (cxt->search_string_index == 0) 408210284Sjmallett { 409210284Sjmallett if (last_isearch_string) 410210284Sjmallett { 411210284Sjmallett cxt->search_string_size = 64 + last_isearch_string_len; 412210284Sjmallett cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); 413210284Sjmallett strcpy (cxt->search_string, last_isearch_string); 414210284Sjmallett cxt->search_string_index = last_isearch_string_len; 415210284Sjmallett rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1); 416210284Sjmallett break; 417210284Sjmallett } 418210284Sjmallett return (1); 419210284Sjmallett } 420210284Sjmallett else if (cxt->sflags & SF_REVERSE) 421210284Sjmallett cxt->sline_index--; 422210284Sjmallett else if (cxt->sline_index != cxt->sline_len) 423210284Sjmallett cxt->sline_index++; 424210284Sjmallett else 425210284Sjmallett rl_ding (); 426210284Sjmallett break; 427210284Sjmallett 428210284Sjmallett /* switch directions */ 429210284Sjmallett case -2: 430210284Sjmallett cxt->direction = -cxt->direction; 431210284Sjmallett if (cxt->direction < 0) 432210284Sjmallett cxt->sflags |= SF_REVERSE; 433210284Sjmallett else 434210284Sjmallett cxt->sflags &= ~SF_REVERSE; 435210284Sjmallett break; 436210284Sjmallett 437210284Sjmallett /* delete character from search string. */ 438210284Sjmallett case -3: /* C-H, DEL */ 439210284Sjmallett /* This is tricky. To do this right, we need to keep a 440210284Sjmallett stack of search positions for the current search, with 441210284Sjmallett sentinels marking the beginning and end. But this will 442210284Sjmallett do until we have a real isearch-undo. */ 443210284Sjmallett if (cxt->search_string_index == 0) 444210284Sjmallett rl_ding (); 445210284Sjmallett else 446210284Sjmallett cxt->search_string[--cxt->search_string_index] = '\0'; 447210284Sjmallett break; 448210284Sjmallett 449210284Sjmallett case -4: /* C-G, abort */ 450210284Sjmallett rl_replace_line (cxt->lines[cxt->save_line], 0); 451210284Sjmallett rl_point = cxt->save_point; 452210284Sjmallett rl_mark = cxt->save_mark; 453210284Sjmallett rl_restore_prompt(); 454210284Sjmallett rl_clear_message (); 455210284Sjmallett 456210284Sjmallett return -1; 457210284Sjmallett 458210284Sjmallett case -5: /* C-W */ 459210284Sjmallett /* skip over portion of line we already matched and yank word */ 460210284Sjmallett wstart = rl_point + cxt->search_string_index; 461210284Sjmallett if (wstart >= rl_end) 462210284Sjmallett { 463210284Sjmallett rl_ding (); 464210284Sjmallett break; 465210284Sjmallett } 466210284Sjmallett 467210284Sjmallett /* if not in a word, move to one. */ 468210284Sjmallett cval = _rl_char_value (rl_line_buffer, wstart); 469210284Sjmallett if (_rl_walphabetic (cval) == 0) 470210284Sjmallett { 471210284Sjmallett rl_ding (); 472210284Sjmallett break; 473210284Sjmallett } 474210284Sjmallett n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);; 475210284Sjmallett while (n < rl_end) 476210284Sjmallett { 477210284Sjmallett cval = _rl_char_value (rl_line_buffer, n); 478210284Sjmallett if (_rl_walphabetic (cval) == 0) 479210284Sjmallett break; 480210284Sjmallett n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);; 481210284Sjmallett } 482210284Sjmallett wlen = n - wstart + 1; 483210284Sjmallett if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size) 484210284Sjmallett { 485210284Sjmallett cxt->search_string_size += wlen + 1; 486210284Sjmallett cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); 487210284Sjmallett } 488210284Sjmallett for (; wstart < n; wstart++) 489210284Sjmallett cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart]; 490210284Sjmallett cxt->search_string[cxt->search_string_index] = '\0'; 491210284Sjmallett break; 492210284Sjmallett 493210284Sjmallett case -6: /* C-Y */ 494210284Sjmallett /* skip over portion of line we already matched and yank rest */ 495210284Sjmallett wstart = rl_point + cxt->search_string_index; 496210284Sjmallett if (wstart >= rl_end) 497210284Sjmallett { 498210284Sjmallett rl_ding (); 499210284Sjmallett break; 500210284Sjmallett } 501210284Sjmallett n = rl_end - wstart + 1; 502210284Sjmallett if (cxt->search_string_index + n + 1 >= cxt->search_string_size) 503210284Sjmallett { 504210284Sjmallett cxt->search_string_size += n + 1; 505210284Sjmallett cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); 506210284Sjmallett } 507210284Sjmallett for (n = wstart; n < rl_end; n++) 508210284Sjmallett cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n]; 509210284Sjmallett cxt->search_string[cxt->search_string_index] = '\0'; 510210284Sjmallett break; 511210284Sjmallett 512210284Sjmallett /* Add character to search string and continue search. */ 513210284Sjmallett default: 514210284Sjmallett if (cxt->search_string_index + 2 >= cxt->search_string_size) 515210284Sjmallett { 516210284Sjmallett cxt->search_string_size += 128; 517210284Sjmallett cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); 518210284Sjmallett } 519210284Sjmallett#if defined (HANDLE_MULTIBYTE) 520210284Sjmallett if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 521210284Sjmallett { 522210284Sjmallett int j, l; 523210284Sjmallett for (j = 0, l = strlen (cxt->mb); j < l; ) 524210284Sjmallett cxt->search_string[cxt->search_string_index++] = cxt->mb[j++]; 525210284Sjmallett } 526210284Sjmallett else 527210284Sjmallett#endif 528210284Sjmallett cxt->search_string[cxt->search_string_index++] = c; 529210284Sjmallett cxt->search_string[cxt->search_string_index] = '\0'; 530210284Sjmallett break; 531210284Sjmallett } 532210284Sjmallett 533210284Sjmallett for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; ) 534210284Sjmallett { 535210284Sjmallett limit = cxt->sline_len - cxt->search_string_index + 1; 536210284Sjmallett 537210284Sjmallett /* Search the current line. */ 538210284Sjmallett while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit)) 539210284Sjmallett { 540210284Sjmallett if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index)) 541210284Sjmallett { 542210284Sjmallett cxt->sflags |= SF_FOUND; 543210284Sjmallett break; 544210284Sjmallett } 545210284Sjmallett else 546210284Sjmallett cxt->sline_index += cxt->direction; 547210284Sjmallett } 548210284Sjmallett if (cxt->sflags & SF_FOUND) 549210284Sjmallett break; 550210284Sjmallett 551210284Sjmallett /* Move to the next line, but skip new copies of the line 552210284Sjmallett we just found and lines shorter than the string we're 553210284Sjmallett searching for. */ 554210284Sjmallett do 555210284Sjmallett { 556210284Sjmallett /* Move to the next line. */ 557210284Sjmallett cxt->history_pos += cxt->direction; 558210284Sjmallett 559210284Sjmallett /* At limit for direction? */ 560210284Sjmallett if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen)) 561210284Sjmallett { 562210284Sjmallett cxt->sflags |= SF_FAILED; 563210284Sjmallett break; 564210284Sjmallett } 565210284Sjmallett 566210284Sjmallett /* We will need these later. */ 567210284Sjmallett cxt->sline = cxt->lines[cxt->history_pos]; 568210284Sjmallett cxt->sline_len = strlen (cxt->sline); 569210284Sjmallett } 570210284Sjmallett while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) || 571210284Sjmallett (cxt->search_string_index > cxt->sline_len)); 572210284Sjmallett 573210284Sjmallett if (cxt->sflags & SF_FAILED) 574210284Sjmallett break; 575210284Sjmallett 576210284Sjmallett /* Now set up the line for searching... */ 577210284Sjmallett cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0; 578210284Sjmallett } 579210284Sjmallett 580210284Sjmallett if (cxt->sflags & SF_FAILED) 581210284Sjmallett { 582210284Sjmallett /* We cannot find the search string. Ding the bell. */ 583210284Sjmallett rl_ding (); 584210284Sjmallett cxt->history_pos = cxt->last_found_line; 585210284Sjmallett return 1; 586210284Sjmallett } 587210284Sjmallett 588210284Sjmallett /* We have found the search string. Just display it. But don't 589210284Sjmallett actually move there in the history list until the user accepts 590210284Sjmallett the location. */ 591210284Sjmallett if (cxt->sflags & SF_FOUND) 592210284Sjmallett { 593210284Sjmallett cxt->prev_line_found = cxt->lines[cxt->history_pos]; 594210284Sjmallett rl_replace_line (cxt->lines[cxt->history_pos], 0); 595210284Sjmallett rl_point = cxt->sline_index; 596210284Sjmallett cxt->last_found_line = cxt->history_pos; 597210284Sjmallett rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos); 598210284Sjmallett } 599210284Sjmallett 600210284Sjmallett return 1; 601210284Sjmallett} 602210284Sjmallett 603210284Sjmallettstatic int 604210284Sjmallett_rl_isearch_cleanup (cxt, r) 605210284Sjmallett _rl_search_cxt *cxt; 606210284Sjmallett int r; 607210284Sjmallett{ 608210284Sjmallett if (r >= 0) 609210284Sjmallett _rl_isearch_fini (cxt); 610210284Sjmallett _rl_scxt_dispose (cxt, 0); 611210284Sjmallett _rl_iscxt = 0; 612210284Sjmallett 613210284Sjmallett RL_UNSETSTATE(RL_STATE_ISEARCH); 614210284Sjmallett 615210284Sjmallett return (r != 0); 616210284Sjmallett} 617210284Sjmallett 618210284Sjmallett/* Search through the history looking for an interactively typed string. 619210284Sjmallett This is analogous to i-search. We start the search in the current line. 620210284Sjmallett DIRECTION is which direction to search; >= 0 means forward, < 0 means 621210284Sjmallett backwards. */ 622210284Sjmallettstatic int 623210284Sjmallettrl_search_history (direction, invoking_key) 624210284Sjmallett int direction, invoking_key; 625210284Sjmallett{ 626210284Sjmallett _rl_search_cxt *cxt; /* local for now, but saved globally */ 627210284Sjmallett int c, r; 628210284Sjmallett 629210284Sjmallett RL_SETSTATE(RL_STATE_ISEARCH); 630210284Sjmallett cxt = _rl_isearch_init (direction); 631210284Sjmallett 632210284Sjmallett rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1); 633210284Sjmallett 634210284Sjmallett /* If we are using the callback interface, all we do is set up here and 635210284Sjmallett return. The key is that we leave RL_STATE_ISEARCH set. */ 636210284Sjmallett if (RL_ISSTATE (RL_STATE_CALLBACK)) 637210284Sjmallett return (0); 638210284Sjmallett 639210284Sjmallett r = -1; 640210284Sjmallett for (;;) 641210284Sjmallett { 642210284Sjmallett c = _rl_search_getchar (cxt); 643210284Sjmallett /* We might want to handle EOF here (c == 0) */ 644210284Sjmallett r = _rl_isearch_dispatch (cxt, cxt->lastc); 645210284Sjmallett if (r <= 0) 646210284Sjmallett break; 647210284Sjmallett } 648210284Sjmallett 649210284Sjmallett /* The searching is over. The user may have found the string that she 650210284Sjmallett was looking for, or else she may have exited a failing search. If 651210284Sjmallett LINE_INDEX is -1, then that shows that the string searched for was 652210284Sjmallett not found. We use this to determine where to place rl_point. */ 653210284Sjmallett return (_rl_isearch_cleanup (cxt, r)); 654210284Sjmallett} 655210284Sjmallett 656210284Sjmallett#if defined (READLINE_CALLBACKS) 657210284Sjmallett/* Called from the callback functions when we are ready to read a key. The 658210284Sjmallett callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH). 659210284Sjmallett If _rl_isearch_dispatch finishes searching, this function is responsible 660210284Sjmallett for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */ 661210284Sjmallettint 662210284Sjmallett_rl_isearch_callback (cxt) 663210284Sjmallett _rl_search_cxt *cxt; 664210284Sjmallett{ 665210284Sjmallett int c, r; 666210284Sjmallett 667210284Sjmallett c = _rl_search_getchar (cxt); 668210284Sjmallett /* We might want to handle EOF here */ 669210284Sjmallett r = _rl_isearch_dispatch (cxt, cxt->lastc); 670210284Sjmallett 671210284Sjmallett return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0; 672210284Sjmallett} 673210284Sjmallett#endif 674210284Sjmallett