isearch.c revision 35486
1109864Sjeff/* **************************************************************** */ 2113357Sjeff/* */ 3109864Sjeff/* I-Search and Searching */ 4109864Sjeff/* */ 5109864Sjeff/* **************************************************************** */ 6109864Sjeff 7109864Sjeff/* Copyright (C) 1987,1989 Free Software Foundation, Inc. 8109864Sjeff 9109864Sjeff This file contains the Readline Library (the Library), a set of 10109864Sjeff routines for providing Emacs style line input to programs that ask 11109864Sjeff for it. 12109864Sjeff 13109864Sjeff The Library is free software; you can redistribute it and/or modify 14109864Sjeff it under the terms of the GNU General Public License as published by 15109864Sjeff the Free Software Foundation; either version 1, or (at your option) 16109864Sjeff any later version. 17109864Sjeff 18109864Sjeff The Library is distributed in the hope that it will be useful, but 19109864Sjeff WITHOUT ANY WARRANTY; without even the implied warranty of 20109864Sjeff MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21109864Sjeff General Public License for more details. 22109864Sjeff 23109864Sjeff The GNU General Public License is often shipped with GNU software, and 24109864Sjeff is generally kept in a file called COPYING or LICENSE. If you do not 25109864Sjeff have a copy of the license, write to the Free Software Foundation, 26109864Sjeff 675 Mass Ave, Cambridge, MA 02139, USA. */ 27116182Sobrien#define READLINE_LIBRARY 28116182Sobrien 29116182Sobrien#if defined (HAVE_CONFIG_H) 30109864Sjeff# include <config.h> 31109864Sjeff#endif 32109864Sjeff 33109864Sjeff#include <sys/types.h> 34109864Sjeff 35109864Sjeff#include <stdio.h> 36109864Sjeff 37112966Sjeff#if defined (HAVE_UNISTD_H) 38122038Sjeff# include <unistd.h> 39109864Sjeff#endif 40109864Sjeff 41109864Sjeff#if defined (HAVE_STDLIB_H) 42109864Sjeff# include <stdlib.h> 43109864Sjeff#else 44109864Sjeff# include "ansi_stdlib.h" 45109864Sjeff#endif 46109864Sjeff 47109864Sjeff#include "rldefs.h" 48109864Sjeff#include "readline.h" 49109864Sjeff#include "history.h" 50109864Sjeff 51109864Sjeff/* Variables imported from other files in the readline library. */ 52109864Sjeffextern Keymap _rl_keymap; 53109864Sjeffextern HIST_ENTRY *saved_line_for_history; 54121790Sjeffextern int rl_line_buffer_len; 55109864Sjeffextern int rl_point, rl_end; 56113357Sjeffextern char *rl_line_buffer; 57113357Sjeff 58109864Sjeffextern void _rl_save_prompt (); 59109864Sjeffextern void _rl_restore_prompt (); 60109864Sjeff 61109864Sjeffextern int rl_execute_next (); 62109864Sjeffextern void rl_extend_line_buffer (); 63109864Sjeff 64109864Sjeffextern int _rl_input_available (); 65109864Sjeff 66113357Sjeffextern char *xmalloc (), *xrealloc (); 67113357Sjeff 68113357Sjeffstatic int rl_search_history (); 69113357Sjeff 70113357Sjeff/* Last line found by the current incremental search, so we don't `find' 71116365Sjeff identical lines many times in a row. */ 72113357Sjeffstatic char *prev_line_found; 73113357Sjeff 74111857Sjeff/* Search backwards through the history looking for a string which is typed 75113357Sjeff interactively. Start with the current line. */ 76111857Sjeffint 77116069Sjeffrl_reverse_search_history (sign, key) 78123487Sjeff int sign, key; 79116069Sjeff{ 80123487Sjeff return (rl_search_history (-sign, key)); 81116069Sjeff} 82116069Sjeff 83109864Sjeff/* Search forwards through the history looking for a string which is typed 84109864Sjeff interactively. Start with the current line. */ 85109864Sjeffint 86109864Sjeffrl_forward_search_history (sign, key) 87109864Sjeff int sign, key; 88109864Sjeff{ 89109864Sjeff return (rl_search_history (sign, key)); 90109864Sjeff} 91109864Sjeff 92109864Sjeff/* Display the current state of the search in the echo-area. 93109864Sjeff SEARCH_STRING contains the string that is being searched for, 94109864Sjeff DIRECTION is zero for forward, or 1 for reverse, 95113357Sjeff WHERE is the history list number of the current line. If it is 96110260Sjeff -1, then this line is the starting one. */ 97109864Sjeffstatic void 98109864Sjeffrl_display_search (search_string, reverse_p, where) 99109864Sjeff char *search_string; 100109864Sjeff int reverse_p, where; 101109864Sjeff{ 102109864Sjeff char *message; 103110260Sjeff int msglen, searchlen; 104121790Sjeff 105109864Sjeff searchlen = (search_string && *search_string) ? strlen (search_string) : 0; 106121790Sjeff 107122158Sjeff message = xmalloc (searchlen + 33); 108121790Sjeff msglen = 0; 109109864Sjeff 110110645Sjeff#if defined (NOTDEF) 111110645Sjeff if (where != -1) 112109864Sjeff { 113109864Sjeff sprintf (message, "[%d]", where + history_base); 114110645Sjeff msglen = strlen (message); 115109864Sjeff } 116109864Sjeff#endif /* NOTDEF */ 117109864Sjeff 118109864Sjeff message[msglen++] = '('; 119109864Sjeff 120109864Sjeff if (reverse_p) 121110267Sjeff { 122109864Sjeff strcpy (message + msglen, "reverse-"); 123109864Sjeff msglen += 8; 124109864Sjeff } 125109864Sjeff 126109864Sjeff strcpy (message + msglen, "i-search)`"); 127109864Sjeff msglen += 10; 128109864Sjeff 129109864Sjeff if (search_string) 130109864Sjeff { 131116642Sjeff strcpy (message + msglen, search_string); 132116642Sjeff msglen += searchlen; 133116642Sjeff } 134116642Sjeff 135111857Sjeff strcpy (message + msglen, "': "); 136111857Sjeff 137116642Sjeff rl_message ("%s", message, 0); 138111857Sjeff free (message); 139109864Sjeff (*rl_redisplay_function) (); 140111857Sjeff} 141121869Sjeff 142121869Sjeff/* Search through the history looking for an interactively typed string. 143116642Sjeff This is analogous to i-search. We start the search in the current line. 144113357Sjeff DIRECTION is which direction to search; >= 0 means forward, < 0 means 145116642Sjeff backwards. */ 146109864Sjeffstatic int 147109864Sjeffrl_search_history (direction, invoking_key) 148111857Sjeff int direction, invoking_key; 149109864Sjeff{ 150110645Sjeff /* The string that the user types in to search for. */ 151110645Sjeff char *search_string; 152121868Sjeff 153116365Sjeff /* The current length of SEARCH_STRING. */ 154111857Sjeff int search_string_index; 155109864Sjeff 156121126Sjeff /* The amount of space that SEARCH_STRING has allocated to it. */ 157121868Sjeff int search_string_size; 158116365Sjeff 159116365Sjeff /* The list of lines to search through. */ 160121126Sjeff char **lines, *allocated_line; 161111857Sjeff 162109864Sjeff /* The length of LINES. */ 163109864Sjeff int hlen; 164109864Sjeff 165109864Sjeff /* Where we get LINES from. */ 166109864Sjeff HIST_ENTRY **hlist; 167109864Sjeff 168109864Sjeff register int i; 169112966Sjeff int orig_point, orig_line, last_found_line; 170112966Sjeff int c, found, failed, sline_len; 171121871Sjeff 172109864Sjeff /* The line currently being searched. */ 173113357Sjeff char *sline; 174113357Sjeff 175125299Sjeff /* Offset in that line. */ 176121871Sjeff int line_index; 177111857Sjeff 178109864Sjeff /* Non-zero if we are doing a reverse search. */ 179112966Sjeff int reverse; 180121871Sjeff 181109864Sjeff orig_point = rl_point; 182109864Sjeff last_found_line = orig_line = where_history (); 183109864Sjeff reverse = direction < 0; 184109864Sjeff hlist = history_list (); 185109864Sjeff allocated_line = (char *)NULL; 186113357Sjeff 187113357Sjeff /* Create an arrary of pointers to the lines that we want to search. */ 188113417Sjeff maybe_replace_line (); 189127278Sobrien i = 0; 190121107Sjeff if (hlist) 191109864Sjeff for (i = 0; hlist[i]; i++); 192109864Sjeff 193109864Sjeff /* Allocate space for this many lines, +1 for the current input line, 194109864Sjeff and remember those lines. */ 195109864Sjeff lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); 196109864Sjeff for (i = 0; i < hlen; i++) 197109864Sjeff lines[i] = hlist[i]->line; 198109864Sjeff 199112971Sjeff if (saved_line_for_history) 200109864Sjeff lines[i] = saved_line_for_history->line; 201109864Sjeff else 202109864Sjeff { 203113357Sjeff /* Keep track of this so we can free it. */ 204109864Sjeff allocated_line = xmalloc (1 + strlen (rl_line_buffer)); 205109864Sjeff strcpy (allocated_line, &rl_line_buffer[0]); 206113357Sjeff lines[i] = allocated_line; 207113357Sjeff } 208113357Sjeff 209113357Sjeff hlen++; 210121896Sjeff 211113357Sjeff /* The line where we start the search. */ 212121869Sjeff i = orig_line; 213113357Sjeff 214110267Sjeff _rl_save_prompt (); 215123433Sjeff 216123433Sjeff /* Initialize search parameters. */ 217123433Sjeff search_string = xmalloc (search_string_size = 128); 218123433Sjeff *search_string = '\0'; 219125289Sjeff search_string_index = 0; 220125289Sjeff prev_line_found = (char *)0; /* XXX */ 221110267Sjeff 222109864Sjeff /* Normalize DIRECTION into 1 or -1. */ 223109864Sjeff direction = (direction >= 0) ? 1 : -1; 224123433Sjeff 225109864Sjeff rl_display_search (search_string, reverse, -1); 226123433Sjeff 227123433Sjeff sline = rl_line_buffer; 228123433Sjeff sline_len = strlen (sline); 229123433Sjeff line_index = rl_point; 230123433Sjeff 231123433Sjeff found = failed = 0; 232123433Sjeff for (;;) 233123433Sjeff { 234123433Sjeff Function *f = (Function *)NULL; 235127498Smarcel 236127498Smarcel /* Read a key and decide how to proceed. */ 237127498Smarcel c = rl_read_key (); 238123487Sjeff 239123433Sjeff if (_rl_keymap[c].type == ISFUNC) 240123433Sjeff { 241123433Sjeff f = _rl_keymap[c].function; 242123433Sjeff 243123433Sjeff if (f == rl_reverse_search_history) 244123433Sjeff c = reverse ? -1 : -2; 245109864Sjeff else if (f == rl_forward_search_history) 246109864Sjeff c = !reverse ? -1 : -2; 247110028Sjeff } 248127498Smarcel 249123487Sjeff /* Let NEWLINE (^J) terminate the search for people who don't like 250121790Sjeff using ESC. ^M can still be used to terminate the search and 251123433Sjeff immediately execute the command. */ 252123433Sjeff if (c == ESC || c == NEWLINE) 253123433Sjeff { 254123487Sjeff /* ESC still terminates the search, but if there is pending 255123487Sjeff input or if input arrives within 0.1 seconds (on systems 256123433Sjeff with select(2)) it is used as a prefix character 257121790Sjeff with rl_execute_next. WATCH OUT FOR THIS! This is intended 258110028Sjeff to allow the arrow keys to be used like ^F and ^B are used 259110028Sjeff to terminate the search and execute the movement command. */ 260110028Sjeff if (c == ESC && _rl_input_available ()) /* XXX */ 261109864Sjeff rl_execute_next (ESC); 262112966Sjeff break; 263113357Sjeff } 264111857Sjeff 265116463Sjeff if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G')) 266121868Sjeff { 267121790Sjeff rl_execute_next (c); 268109864Sjeff break; 269110267Sjeff } 270121790Sjeff 271110028Sjeff switch (c) 272122744Sjeff { 273122744Sjeff case -1: 274122744Sjeff if (search_string_index == 0) 275122744Sjeff continue; 276113357Sjeff else if (reverse) 277113357Sjeff --line_index; 278113660Sjeff else if (line_index != sline_len) 279110267Sjeff ++line_index; 280123433Sjeff else 281121790Sjeff ding (); 282122744Sjeff break; 283123487Sjeff 284123487Sjeff /* switch directions */ 285121790Sjeff case -2: 286123433Sjeff direction = -direction; 287121790Sjeff reverse = direction < 0; 288121790Sjeff break; 289123433Sjeff 290123693Sjeff case CTRL ('G'): 291123693Sjeff strcpy (rl_line_buffer, lines[orig_line]); 292123693Sjeff rl_point = orig_point; 293123693Sjeff rl_end = strlen (rl_line_buffer); 294123693Sjeff _rl_restore_prompt(); 295123693Sjeff rl_clear_message (); 296122038Sjeff if (allocated_line) 297123693Sjeff free (allocated_line); 298123693Sjeff free (lines); 299123693Sjeff return 0; 300122158Sjeff 301122165Sjeff#if 0 302123693Sjeff /* delete character from search string. */ 303121790Sjeff case -3: 304110028Sjeff if (search_string_index == 0) 305113357Sjeff ding (); 306113660Sjeff else 307110267Sjeff { 308113660Sjeff search_string[--search_string_index] = '\0'; 309113357Sjeff /* This is tricky. To do this right, we need to keep a 310112994Sjeff stack of search positions for the current search, with 311113660Sjeff sentinels marking the beginning and end. */ 312112994Sjeff } 313113357Sjeff break; 314113357Sjeff#endif 315122744Sjeff 316121896Sjeff default: 317123433Sjeff /* Add character to search string and continue search. */ 318121896Sjeff if (search_string_index + 2 >= search_string_size) 319113357Sjeff { 320113357Sjeff search_string_size += 128; 321121869Sjeff search_string = xrealloc (search_string, search_string_size); 322113357Sjeff } 323113357Sjeff search_string[search_string_index++] = c; 324113357Sjeff search_string[search_string_index] = '\0'; 325113357Sjeff break; 326112994Sjeff } 327122744Sjeff 328122744Sjeff for (found = failed = 0;;) 329122744Sjeff { 330122744Sjeff int limit = sline_len - search_string_index + 1; 331123433Sjeff 332123433Sjeff /* Search the current line. */ 333123433Sjeff while (reverse ? (line_index >= 0) : (line_index < limit)) 334123433Sjeff { 335122744Sjeff if (STREQN (search_string, sline + line_index, search_string_index)) 336122744Sjeff { 337122744Sjeff found++; 338122744Sjeff break; 339122744Sjeff } 340122744Sjeff else 341122744Sjeff line_index += direction; 342122744Sjeff } 343123433Sjeff if (found) 344123433Sjeff break; 345123433Sjeff 346123433Sjeff /* Move to the next line, but skip new copies of the line 347122744Sjeff we just found and lines shorter than the string we're 348122744Sjeff searching for. */ 349122744Sjeff do 350122744Sjeff { 351113357Sjeff /* Move to the next line. */ 352122744Sjeff i += direction; 353113357Sjeff 354121896Sjeff /* At limit for direction? */ 355115998Sjeff if (reverse ? (i < 0) : (i == hlen)) 356121896Sjeff { 357121896Sjeff failed++; 358121896Sjeff break; 359113357Sjeff } 360125289Sjeff 361123487Sjeff /* We will need these later. */ 362123487Sjeff sline = lines[i]; 363125289Sjeff sline_len = strlen (sline); 364125289Sjeff } 365123487Sjeff while ((prev_line_found && STREQ (prev_line_found, lines[i])) || 366113357Sjeff (search_string_index > sline_len)); 367122744Sjeff 368122744Sjeff if (failed) 369122744Sjeff break; 370122744Sjeff 371113357Sjeff /* Now set up the line for searching... */ 372113357Sjeff line_index = reverse ? sline_len - search_string_index : 0; 373110267Sjeff } 374113357Sjeff 375112994Sjeff if (failed) 376122744Sjeff { 377110267Sjeff /* We cannot find the search string. Ding the bell. */ 378121896Sjeff ding (); 379115998Sjeff i = last_found_line; 380121896Sjeff continue; /* XXX - was break */ 381121896Sjeff } 382121896Sjeff 383125289Sjeff /* We have found the search string. Just display it. But don't 384123487Sjeff actually move there in the history list until the user accepts 385123487Sjeff the location. */ 386125289Sjeff if (found) 387125289Sjeff { 388123487Sjeff int line_len; 389113357Sjeff 390113357Sjeff prev_line_found = lines[i]; 391113357Sjeff line_len = strlen (lines[i]); 392113357Sjeff 393110267Sjeff if (line_len >= rl_line_buffer_len) 394110267Sjeff rl_extend_line_buffer (line_len); 395113357Sjeff 396113357Sjeff strcpy (rl_line_buffer, lines[i]); 397110267Sjeff rl_point = line_index; 398115998Sjeff rl_end = line_len; 399113357Sjeff last_found_line = i; 400113357Sjeff rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); 401121896Sjeff } 402113357Sjeff } 403110267Sjeff 404110267Sjeff /* The searching is over. The user may have found the string that she 405113357Sjeff was looking for, or else she may have exited a failing search. If 406113357Sjeff LINE_INDEX is -1, then that shows that the string searched for was 407110267Sjeff not found. We use this to determine where to place rl_point. */ 408113357Sjeff 409113357Sjeff /* First put back the original state. */ 410115998Sjeff strcpy (rl_line_buffer, lines[orig_line]); 411113357Sjeff 412113357Sjeff _rl_restore_prompt (); 413113357Sjeff 414113357Sjeff /* Free the search string. */ 415113357Sjeff free (search_string); 416113357Sjeff 417113357Sjeff if (last_found_line < orig_line) 418113357Sjeff rl_get_previous_history (orig_line - last_found_line); 419113357Sjeff else 420113357Sjeff rl_get_next_history (last_found_line - orig_line); 421113357Sjeff 422113357Sjeff /* If the string was not found, put point at the end of the line. */ 423121896Sjeff if (line_index < 0) 424113357Sjeff line_index = strlen (rl_line_buffer); 425113357Sjeff rl_point = line_index; 426121869Sjeff rl_clear_message (); 427113357Sjeff 428113357Sjeff if (allocated_line) 429113357Sjeff free (allocated_line); 430113357Sjeff free (lines); 431110267Sjeff 432110267Sjeff return 0; 433113357Sjeff} 434116069Sjeff