isearch.c revision 75406
121308Sache/* **************************************************************** */ 221308Sache/* */ 321308Sache/* I-Search and Searching */ 421308Sache/* */ 521308Sache/* **************************************************************** */ 621308Sache 721308Sache/* Copyright (C) 1987,1989 Free Software Foundation, Inc. 821308Sache 921308Sache This file contains the Readline Library (the Library), a set of 1021308Sache routines for providing Emacs style line input to programs that ask 1121308Sache for it. 1221308Sache 1321308Sache The Library is free software; you can redistribute it and/or modify 1421308Sache it under the terms of the GNU General Public License as published by 1558310Sache the Free Software Foundation; either version 2, or (at your option) 1621308Sache any later version. 1721308Sache 1821308Sache The Library is distributed in the hope that it will be useful, but 1921308Sache WITHOUT ANY WARRANTY; without even the implied warranty of 2021308Sache MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2121308Sache General Public License for more details. 2221308Sache 2321308Sache The GNU General Public License is often shipped with GNU software, and 2421308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2521308Sache have a copy of the license, write to the Free Software Foundation, 2658310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2721308Sache#define READLINE_LIBRARY 2821308Sache 2921308Sache#if defined (HAVE_CONFIG_H) 3021308Sache# include <config.h> 3121308Sache#endif 3221308Sache 3326497Sache#include <sys/types.h> 3426497Sache 3521308Sache#include <stdio.h> 3621308Sache 3721308Sache#if defined (HAVE_UNISTD_H) 3821308Sache# include <unistd.h> 3921308Sache#endif 4021308Sache 4126497Sache#if defined (HAVE_STDLIB_H) 4226497Sache# include <stdlib.h> 4326497Sache#else 4426497Sache# include "ansi_stdlib.h" 4526497Sache#endif 4621308Sache 4721308Sache#include "rldefs.h" 4821308Sache#include "readline.h" 4921308Sache#include "history.h" 5021308Sache 5158310Sache#include "rlprivate.h" 5258310Sache#include "xmalloc.h" 5358310Sache 5447558Sache/* Variables exported to other files in the readline library. */ 5547558Sacheunsigned char *_rl_isearch_terminators = (unsigned char *)NULL; 5647558Sache 5721308Sache/* Variables imported from other files in the readline library. */ 5875406Sacheextern HIST_ENTRY *_rl_saved_line_for_history; 5921308Sache 6058310Sache/* Forward declarations */ 6158310Sachestatic int rl_search_history __P((int, int)); 6221308Sache 6321308Sache/* Last line found by the current incremental search, so we don't `find' 6421308Sache identical lines many times in a row. */ 6521308Sachestatic char *prev_line_found; 6621308Sache 6775406Sachestatic unsigned char *default_isearch_terminators = "\033\012"; 6875406Sache 6921308Sache/* Search backwards through the history looking for a string which is typed 7021308Sache interactively. Start with the current line. */ 7121308Sacheint 7221308Sacherl_reverse_search_history (sign, key) 7321308Sache int sign, key; 7421308Sache{ 7521308Sache return (rl_search_history (-sign, key)); 7621308Sache} 7721308Sache 7821308Sache/* Search forwards through the history looking for a string which is typed 7921308Sache interactively. Start with the current line. */ 8021308Sacheint 8121308Sacherl_forward_search_history (sign, key) 8221308Sache int sign, key; 8321308Sache{ 8421308Sache return (rl_search_history (sign, key)); 8521308Sache} 8621308Sache 8721308Sache/* Display the current state of the search in the echo-area. 8821308Sache SEARCH_STRING contains the string that is being searched for, 8921308Sache DIRECTION is zero for forward, or 1 for reverse, 9021308Sache WHERE is the history list number of the current line. If it is 9121308Sache -1, then this line is the starting one. */ 9221308Sachestatic void 9321308Sacherl_display_search (search_string, reverse_p, where) 9421308Sache char *search_string; 9521308Sache int reverse_p, where; 9621308Sache{ 9721308Sache char *message; 9821308Sache int msglen, searchlen; 9921308Sache 10021308Sache searchlen = (search_string && *search_string) ? strlen (search_string) : 0; 10121308Sache 10221308Sache message = xmalloc (searchlen + 33); 10321308Sache msglen = 0; 10421308Sache 10521308Sache#if defined (NOTDEF) 10621308Sache if (where != -1) 10721308Sache { 10821308Sache sprintf (message, "[%d]", where + history_base); 10921308Sache msglen = strlen (message); 11021308Sache } 11121308Sache#endif /* NOTDEF */ 11221308Sache 11321308Sache message[msglen++] = '('; 11421308Sache 11521308Sache if (reverse_p) 11621308Sache { 11721308Sache strcpy (message + msglen, "reverse-"); 11821308Sache msglen += 8; 11921308Sache } 12021308Sache 12121308Sache strcpy (message + msglen, "i-search)`"); 12221308Sache msglen += 10; 12321308Sache 12421308Sache if (search_string) 12521308Sache { 12621308Sache strcpy (message + msglen, search_string); 12721308Sache msglen += searchlen; 12821308Sache } 12921308Sache 13021308Sache strcpy (message + msglen, "': "); 13121308Sache 13221308Sache rl_message ("%s", message, 0); 13321308Sache free (message); 13421308Sache (*rl_redisplay_function) (); 13521308Sache} 13621308Sache 13721308Sache/* Search through the history looking for an interactively typed string. 13821308Sache This is analogous to i-search. We start the search in the current line. 13921308Sache DIRECTION is which direction to search; >= 0 means forward, < 0 means 14021308Sache backwards. */ 14121308Sachestatic int 14221308Sacherl_search_history (direction, invoking_key) 14321308Sache int direction, invoking_key; 14421308Sache{ 14521308Sache /* The string that the user types in to search for. */ 14621308Sache char *search_string; 14721308Sache 14821308Sache /* The current length of SEARCH_STRING. */ 14921308Sache int search_string_index; 15021308Sache 15121308Sache /* The amount of space that SEARCH_STRING has allocated to it. */ 15221308Sache int search_string_size; 15321308Sache 15421308Sache /* The list of lines to search through. */ 15521308Sache char **lines, *allocated_line; 15621308Sache 15721308Sache /* The length of LINES. */ 15821308Sache int hlen; 15921308Sache 16021308Sache /* Where we get LINES from. */ 16121308Sache HIST_ENTRY **hlist; 16221308Sache 16321308Sache register int i; 16421308Sache int orig_point, orig_line, last_found_line; 16521308Sache int c, found, failed, sline_len; 16621308Sache 16721308Sache /* The line currently being searched. */ 16821308Sache char *sline; 16921308Sache 17021308Sache /* Offset in that line. */ 17121308Sache int line_index; 17221308Sache 17321308Sache /* Non-zero if we are doing a reverse search. */ 17421308Sache int reverse; 17521308Sache 17647558Sache /* The list of characters which terminate the search, but are not 17747558Sache subsequently executed. If the variable isearch-terminators has 17847558Sache been set, we use that value, otherwise we use ESC and C-J. */ 17947558Sache unsigned char *isearch_terminators; 18047558Sache 18175406Sache RL_SETSTATE(RL_STATE_ISEARCH); 18221308Sache orig_point = rl_point; 18321308Sache last_found_line = orig_line = where_history (); 18421308Sache reverse = direction < 0; 18521308Sache hlist = history_list (); 18621308Sache allocated_line = (char *)NULL; 18721308Sache 18847558Sache isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators 18975406Sache : default_isearch_terminators; 19047558Sache 19121308Sache /* Create an arrary of pointers to the lines that we want to search. */ 19275406Sache rl_maybe_replace_line (); 19321308Sache i = 0; 19421308Sache if (hlist) 19521308Sache for (i = 0; hlist[i]; i++); 19621308Sache 19721308Sache /* Allocate space for this many lines, +1 for the current input line, 19821308Sache and remember those lines. */ 19921308Sache lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); 20021308Sache for (i = 0; i < hlen; i++) 20121308Sache lines[i] = hlist[i]->line; 20221308Sache 20375406Sache if (_rl_saved_line_for_history) 20475406Sache lines[i] = _rl_saved_line_for_history->line; 20521308Sache else 20621308Sache { 20721308Sache /* Keep track of this so we can free it. */ 20821308Sache allocated_line = xmalloc (1 + strlen (rl_line_buffer)); 20921308Sache strcpy (allocated_line, &rl_line_buffer[0]); 21021308Sache lines[i] = allocated_line; 21121308Sache } 21221308Sache 21321308Sache hlen++; 21421308Sache 21521308Sache /* The line where we start the search. */ 21621308Sache i = orig_line; 21721308Sache 21847558Sache rl_save_prompt (); 21921308Sache 22021308Sache /* Initialize search parameters. */ 22121308Sache search_string = xmalloc (search_string_size = 128); 22221308Sache *search_string = '\0'; 22321308Sache search_string_index = 0; 22421308Sache prev_line_found = (char *)0; /* XXX */ 22521308Sache 22621308Sache /* Normalize DIRECTION into 1 or -1. */ 22721308Sache direction = (direction >= 0) ? 1 : -1; 22821308Sache 22921308Sache rl_display_search (search_string, reverse, -1); 23021308Sache 23121308Sache sline = rl_line_buffer; 23221308Sache sline_len = strlen (sline); 23321308Sache line_index = rl_point; 23421308Sache 23521308Sache found = failed = 0; 23621308Sache for (;;) 23721308Sache { 23875406Sache rl_command_func_t *f = (rl_command_func_t *)NULL; 23921308Sache 24021308Sache /* Read a key and decide how to proceed. */ 24175406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 24221308Sache c = rl_read_key (); 24375406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 24421308Sache 24521308Sache if (_rl_keymap[c].type == ISFUNC) 24621308Sache { 24721308Sache f = _rl_keymap[c].function; 24821308Sache 24921308Sache if (f == rl_reverse_search_history) 25021308Sache c = reverse ? -1 : -2; 25121308Sache else if (f == rl_forward_search_history) 25221308Sache c = !reverse ? -1 : -2; 25321308Sache } 25421308Sache 25547558Sache#if 0 25621308Sache /* Let NEWLINE (^J) terminate the search for people who don't like 25721308Sache using ESC. ^M can still be used to terminate the search and 25821308Sache immediately execute the command. */ 25921308Sache if (c == ESC || c == NEWLINE) 26047558Sache#else 26147558Sache /* The characters in isearch_terminators (set from the user-settable 26247558Sache variable isearch-terminators) are used to terminate the search but 26347558Sache not subsequently execute the character as a command. The default 26447558Sache value is "\033\012" (ESC and C-J). */ 26547558Sache if (strchr (isearch_terminators, c)) 26647558Sache#endif 26721308Sache { 26821308Sache /* ESC still terminates the search, but if there is pending 26921308Sache input or if input arrives within 0.1 seconds (on systems 27021308Sache with select(2)) it is used as a prefix character 27121308Sache with rl_execute_next. WATCH OUT FOR THIS! This is intended 27221308Sache to allow the arrow keys to be used like ^F and ^B are used 27321308Sache to terminate the search and execute the movement command. */ 27421308Sache if (c == ESC && _rl_input_available ()) /* XXX */ 27521308Sache rl_execute_next (ESC); 27621308Sache break; 27721308Sache } 27821308Sache 27935486Sache if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G')) 28021308Sache { 28175406Sache /* This sets rl_pending_input to c; it will be picked up the next 28275406Sache time rl_read_key is called. */ 28321308Sache rl_execute_next (c); 28421308Sache break; 28521308Sache } 28621308Sache 28721308Sache switch (c) 28821308Sache { 28921308Sache case -1: 29021308Sache if (search_string_index == 0) 29121308Sache continue; 29221308Sache else if (reverse) 29321308Sache --line_index; 29421308Sache else if (line_index != sline_len) 29521308Sache ++line_index; 29621308Sache else 29775406Sache rl_ding (); 29821308Sache break; 29921308Sache 30021308Sache /* switch directions */ 30121308Sache case -2: 30221308Sache direction = -direction; 30321308Sache reverse = direction < 0; 30421308Sache break; 30521308Sache 30621308Sache case CTRL ('G'): 30721308Sache strcpy (rl_line_buffer, lines[orig_line]); 30821308Sache rl_point = orig_point; 30921308Sache rl_end = strlen (rl_line_buffer); 31047558Sache rl_restore_prompt(); 31121308Sache rl_clear_message (); 31226497Sache if (allocated_line) 31326497Sache free (allocated_line); 31421308Sache free (lines); 31575406Sache RL_UNSETSTATE(RL_STATE_ISEARCH); 31621308Sache return 0; 31721308Sache 31835486Sache#if 0 31935486Sache /* delete character from search string. */ 32035486Sache case -3: 32135486Sache if (search_string_index == 0) 32275406Sache rl_ding (); 32335486Sache else 32435486Sache { 32535486Sache search_string[--search_string_index] = '\0'; 32635486Sache /* This is tricky. To do this right, we need to keep a 32735486Sache stack of search positions for the current search, with 32835486Sache sentinels marking the beginning and end. */ 32935486Sache } 33035486Sache break; 33135486Sache#endif 33235486Sache 33321308Sache default: 33421308Sache /* Add character to search string and continue search. */ 33521308Sache if (search_string_index + 2 >= search_string_size) 33621308Sache { 33721308Sache search_string_size += 128; 33821308Sache search_string = xrealloc (search_string, search_string_size); 33921308Sache } 34021308Sache search_string[search_string_index++] = c; 34121308Sache search_string[search_string_index] = '\0'; 34221308Sache break; 34321308Sache } 34421308Sache 34521308Sache for (found = failed = 0;;) 34621308Sache { 34721308Sache int limit = sline_len - search_string_index + 1; 34821308Sache 34921308Sache /* Search the current line. */ 35021308Sache while (reverse ? (line_index >= 0) : (line_index < limit)) 35121308Sache { 35221308Sache if (STREQN (search_string, sline + line_index, search_string_index)) 35321308Sache { 35421308Sache found++; 35521308Sache break; 35621308Sache } 35721308Sache else 35821308Sache line_index += direction; 35921308Sache } 36021308Sache if (found) 36121308Sache break; 36221308Sache 36321308Sache /* Move to the next line, but skip new copies of the line 36421308Sache we just found and lines shorter than the string we're 36521308Sache searching for. */ 36621308Sache do 36721308Sache { 36821308Sache /* Move to the next line. */ 36921308Sache i += direction; 37021308Sache 37121308Sache /* At limit for direction? */ 37221308Sache if (reverse ? (i < 0) : (i == hlen)) 37321308Sache { 37421308Sache failed++; 37521308Sache break; 37621308Sache } 37721308Sache 37821308Sache /* We will need these later. */ 37921308Sache sline = lines[i]; 38021308Sache sline_len = strlen (sline); 38121308Sache } 38221308Sache while ((prev_line_found && STREQ (prev_line_found, lines[i])) || 38321308Sache (search_string_index > sline_len)); 38421308Sache 38521308Sache if (failed) 38621308Sache break; 38721308Sache 38821308Sache /* Now set up the line for searching... */ 38921308Sache line_index = reverse ? sline_len - search_string_index : 0; 39021308Sache } 39121308Sache 39221308Sache if (failed) 39321308Sache { 39421308Sache /* We cannot find the search string. Ding the bell. */ 39575406Sache rl_ding (); 39621308Sache i = last_found_line; 39721308Sache continue; /* XXX - was break */ 39821308Sache } 39921308Sache 40021308Sache /* We have found the search string. Just display it. But don't 40121308Sache actually move there in the history list until the user accepts 40221308Sache the location. */ 40321308Sache if (found) 40421308Sache { 40521308Sache int line_len; 40621308Sache 40721308Sache prev_line_found = lines[i]; 40821308Sache line_len = strlen (lines[i]); 40921308Sache 41021308Sache if (line_len >= rl_line_buffer_len) 41121308Sache rl_extend_line_buffer (line_len); 41221308Sache 41321308Sache strcpy (rl_line_buffer, lines[i]); 41421308Sache rl_point = line_index; 41521308Sache rl_end = line_len; 41621308Sache last_found_line = i; 41721308Sache rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); 41821308Sache } 41921308Sache } 42021308Sache 42121308Sache /* The searching is over. The user may have found the string that she 42221308Sache was looking for, or else she may have exited a failing search. If 42321308Sache LINE_INDEX is -1, then that shows that the string searched for was 42421308Sache not found. We use this to determine where to place rl_point. */ 42521308Sache 42621308Sache /* First put back the original state. */ 42721308Sache strcpy (rl_line_buffer, lines[orig_line]); 42821308Sache 42947558Sache rl_restore_prompt (); 43021308Sache 43121308Sache /* Free the search string. */ 43221308Sache free (search_string); 43321308Sache 43421308Sache if (last_found_line < orig_line) 43547558Sache rl_get_previous_history (orig_line - last_found_line, 0); 43621308Sache else 43747558Sache rl_get_next_history (last_found_line - orig_line, 0); 43821308Sache 43921308Sache /* If the string was not found, put point at the end of the line. */ 44021308Sache if (line_index < 0) 44121308Sache line_index = strlen (rl_line_buffer); 44221308Sache rl_point = line_index; 44321308Sache rl_clear_message (); 44421308Sache 44526497Sache if (allocated_line) 44626497Sache free (allocated_line); 44721308Sache free (lines); 44821308Sache 44975406Sache RL_UNSETSTATE(RL_STATE_ISEARCH); 45075406Sache 45121308Sache return 0; 45221308Sache} 453