search.c revision 75406
121308Sache/* search.c - code for non-incremental searching in emacs and vi modes. */ 221308Sache 321308Sache/* Copyright (C) 1992 Free Software Foundation, Inc. 421308Sache 521308Sache This file is part of the Readline Library (the Library), a set of 621308Sache routines for providing Emacs style line input to programs that ask 721308Sache for it. 821308Sache 921308Sache The Library is free software; you can redistribute it and/or modify 1021308Sache it under the terms of the GNU General Public License as published by 1158310Sache the Free Software Foundation; either version 2, or (at your option) 1221308Sache any later version. 1321308Sache 1421308Sache The Library is distributed in the hope that it will be useful, but 1521308Sache WITHOUT ANY WARRANTY; without even the implied warranty of 1621308Sache MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1721308Sache General Public License for more details. 1821308Sache 1921308Sache The GNU General Public License is often shipped with GNU software, and 2021308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2121308Sache have a copy of the license, write to the Free Software Foundation, 2258310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2321308Sache#define READLINE_LIBRARY 2421308Sache 2521308Sache#if defined (HAVE_CONFIG_H) 2621308Sache# include <config.h> 2721308Sache#endif 2821308Sache 2921308Sache#include <sys/types.h> 3021308Sache#include <stdio.h> 3121308Sache 3221308Sache#if defined (HAVE_UNISTD_H) 3321308Sache# include <unistd.h> 3421308Sache#endif 3521308Sache 3626497Sache#if defined (HAVE_STDLIB_H) 3726497Sache# include <stdlib.h> 3826497Sache#else 3926497Sache# include "ansi_stdlib.h" 4026497Sache#endif 4126497Sache 4221308Sache#include "rldefs.h" 4321308Sache#include "readline.h" 4421308Sache#include "history.h" 4521308Sache 4658310Sache#include "rlprivate.h" 4758310Sache#include "xmalloc.h" 4858310Sache 4926497Sache#ifdef abs 5026497Sache# undef abs 5126497Sache#endif 5226497Sache#define abs(x) (((x) >= 0) ? (x) : -(x)) 5321308Sache 5475406Sacheextern HIST_ENTRY *_rl_saved_line_for_history; 5521308Sache 5621308Sache/* Functions imported from the rest of the library. */ 5758310Sacheextern int _rl_free_history_entry __P((HIST_ENTRY *)); 5821308Sache 5921308Sachestatic char *noninc_search_string = (char *) NULL; 6021308Sachestatic int noninc_history_pos; 6158310Sache 6221308Sachestatic char *prev_line_found = (char *) NULL; 6321308Sache 6458310Sachestatic int rl_history_search_len; 6558310Sachestatic int rl_history_search_pos; 6658310Sachestatic char *history_search_string; 6758310Sachestatic int history_string_size; 6858310Sache 6958310Sache/* Make the data from the history entry ENTRY be the contents of the 7058310Sache current line. This doesn't do anything with rl_point; the caller 7158310Sache must set it. */ 7258310Sachestatic void 7358310Sachemake_history_line_current (entry) 7458310Sache HIST_ENTRY *entry; 7558310Sache{ 7658310Sache int line_len; 7758310Sache 7858310Sache line_len = strlen (entry->line); 7958310Sache if (line_len >= rl_line_buffer_len) 8058310Sache rl_extend_line_buffer (line_len); 8158310Sache strcpy (rl_line_buffer, entry->line); 8258310Sache 8358310Sache rl_undo_list = (UNDO_LIST *)entry->data; 8458310Sache rl_end = line_len; 8558310Sache 8675406Sache if (_rl_saved_line_for_history) 8775406Sache _rl_free_history_entry (_rl_saved_line_for_history); 8875406Sache _rl_saved_line_for_history = (HIST_ENTRY *)NULL; 8958310Sache} 9058310Sache 9121308Sache/* Search the history list for STRING starting at absolute history position 9221308Sache POS. If STRING begins with `^', the search must match STRING at the 9321308Sache beginning of a history line, otherwise a full substring match is performed 9421308Sache for STRING. DIR < 0 means to search backwards through the history list, 9521308Sache DIR >= 0 means to search forward. */ 9621308Sachestatic int 9721308Sachenoninc_search_from_pos (string, pos, dir) 9821308Sache char *string; 9921308Sache int pos, dir; 10021308Sache{ 10121308Sache int ret, old; 10221308Sache 10375406Sache if (pos < 0) 10475406Sache return -1; 10575406Sache 10621308Sache old = where_history (); 10775406Sache if (history_set_pos (pos) == 0) 10875406Sache return -1; 10921308Sache 11075406Sache RL_SETSTATE(RL_STATE_SEARCH); 11121308Sache if (*string == '^') 11221308Sache ret = history_search_prefix (string + 1, dir); 11321308Sache else 11421308Sache ret = history_search (string, dir); 11575406Sache RL_UNSETSTATE(RL_STATE_SEARCH); 11621308Sache 11721308Sache if (ret != -1) 11821308Sache ret = where_history (); 11921308Sache 12021308Sache history_set_pos (old); 12121308Sache return (ret); 12221308Sache} 12321308Sache 12421308Sache/* Search for a line in the history containing STRING. If DIR is < 0, the 12521308Sache search is backwards through previous entries, else through subsequent 12621308Sache entries. */ 12721308Sachestatic void 12821308Sachenoninc_dosearch (string, dir) 12921308Sache char *string; 13021308Sache int dir; 13121308Sache{ 13258310Sache int oldpos, pos; 13321308Sache HIST_ENTRY *entry; 13421308Sache 13521308Sache if (string == 0 || *string == '\0' || noninc_history_pos < 0) 13621308Sache { 13775406Sache rl_ding (); 13821308Sache return; 13921308Sache } 14021308Sache 14121308Sache pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 14221308Sache if (pos == -1) 14321308Sache { 14421308Sache /* Search failed, current history position unchanged. */ 14575406Sache rl_maybe_unsave_line (); 14621308Sache rl_clear_message (); 14721308Sache rl_point = 0; 14875406Sache rl_ding (); 14921308Sache return; 15021308Sache } 15121308Sache 15221308Sache noninc_history_pos = pos; 15321308Sache 15421308Sache oldpos = where_history (); 15521308Sache history_set_pos (noninc_history_pos); 15621308Sache entry = current_history (); 15721308Sache#if defined (VI_MODE) 15821308Sache if (rl_editing_mode != vi_mode) 15921308Sache#endif 16021308Sache history_set_pos (oldpos); 16121308Sache 16258310Sache make_history_line_current (entry); 16321308Sache 16421308Sache rl_point = 0; 16521308Sache rl_clear_message (); 16621308Sache} 16721308Sache 16821308Sache/* Search non-interactively through the history list. DIR < 0 means to 16921308Sache search backwards through the history of previous commands; otherwise 17021308Sache the search is for commands subsequent to the current position in the 17121308Sache history list. PCHAR is the character to use for prompting when reading 17221308Sache the search string; if not specified (0), it defaults to `:'. */ 17321308Sachestatic void 17421308Sachenoninc_search (dir, pchar) 17521308Sache int dir; 17621308Sache int pchar; 17721308Sache{ 17821308Sache int saved_point, c; 17921308Sache char *p; 18021308Sache 18175406Sache rl_maybe_save_line (); 18221308Sache saved_point = rl_point; 18321308Sache 18421308Sache /* Use the line buffer to read the search string. */ 18521308Sache rl_line_buffer[0] = 0; 18621308Sache rl_end = rl_point = 0; 18721308Sache 18821308Sache p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 18921308Sache rl_message (p, 0, 0); 19021308Sache free (p); 19121308Sache 19275406Sache#define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return 19321308Sache 19475406Sache RL_SETSTATE(RL_STATE_NSEARCH); 19521308Sache /* Read the search string. */ 19675406Sache while (1) 19721308Sache { 19875406Sache RL_SETSTATE(RL_STATE_MOREINPUT); 19975406Sache c = rl_read_key (); 20075406Sache RL_UNSETSTATE(RL_STATE_MOREINPUT); 20175406Sache 20275406Sache if (c == 0) 20375406Sache break; 20475406Sache 20521308Sache switch (c) 20621308Sache { 20721308Sache case CTRL('H'): 20821308Sache case RUBOUT: 20921308Sache if (rl_point == 0) 21021308Sache { 21175406Sache rl_maybe_unsave_line (); 21221308Sache rl_clear_message (); 21321308Sache rl_point = saved_point; 21421308Sache SEARCH_RETURN; 21521308Sache } 21621308Sache rl_rubout (1, c); 21721308Sache break; 21821308Sache 21921308Sache case CTRL('W'): 22021308Sache rl_unix_word_rubout (1, c); 22121308Sache break; 22221308Sache 22321308Sache case CTRL('U'): 22421308Sache rl_unix_line_discard (1, c); 22521308Sache break; 22621308Sache 22721308Sache case RETURN: 22821308Sache case NEWLINE: 22921308Sache goto dosearch; 23021308Sache /* NOTREACHED */ 23121308Sache break; 23221308Sache 23321308Sache case CTRL('C'): 23421308Sache case CTRL('G'): 23575406Sache rl_maybe_unsave_line (); 23621308Sache rl_clear_message (); 23721308Sache rl_point = saved_point; 23875406Sache rl_ding (); 23921308Sache SEARCH_RETURN; 24021308Sache 24121308Sache default: 24221308Sache rl_insert (1, c); 24321308Sache break; 24421308Sache } 24521308Sache (*rl_redisplay_function) (); 24621308Sache } 24721308Sache 24821308Sache dosearch: 24921308Sache /* If rl_point == 0, we want to re-use the previous search string and 25021308Sache start from the saved history position. If there's no previous search 25121308Sache string, punt. */ 25221308Sache if (rl_point == 0) 25321308Sache { 25421308Sache if (!noninc_search_string) 25521308Sache { 25675406Sache rl_ding (); 25721308Sache SEARCH_RETURN; 25821308Sache } 25921308Sache } 26021308Sache else 26121308Sache { 26221308Sache /* We want to start the search from the current history position. */ 26321308Sache noninc_history_pos = where_history (); 26458310Sache FREE (noninc_search_string); 26521308Sache noninc_search_string = savestring (rl_line_buffer); 26621308Sache } 26721308Sache 26847558Sache rl_restore_prompt (); 26921308Sache noninc_dosearch (noninc_search_string, dir); 27075406Sache RL_UNSETSTATE(RL_STATE_NSEARCH); 27121308Sache} 27221308Sache 27321308Sache/* Search forward through the history list for a string. If the vi-mode 27421308Sache code calls this, KEY will be `?'. */ 27521308Sacheint 27621308Sacherl_noninc_forward_search (count, key) 27721308Sache int count, key; 27821308Sache{ 27921308Sache noninc_search (1, (key == '?') ? '?' : 0); 28021308Sache return 0; 28121308Sache} 28221308Sache 28321308Sache/* Reverse search the history list for a string. If the vi-mode code 28421308Sache calls this, KEY will be `/'. */ 28521308Sacheint 28621308Sacherl_noninc_reverse_search (count, key) 28721308Sache int count, key; 28821308Sache{ 28921308Sache noninc_search (-1, (key == '/') ? '/' : 0); 29021308Sache return 0; 29121308Sache} 29221308Sache 29321308Sache/* Search forward through the history list for the last string searched 29421308Sache for. If there is no saved search string, abort. */ 29521308Sacheint 29621308Sacherl_noninc_forward_search_again (count, key) 29721308Sache int count, key; 29821308Sache{ 29921308Sache if (!noninc_search_string) 30021308Sache { 30175406Sache rl_ding (); 30221308Sache return (-1); 30321308Sache } 30421308Sache noninc_dosearch (noninc_search_string, 1); 30521308Sache return 0; 30621308Sache} 30721308Sache 30821308Sache/* Reverse search in the history list for the last string searched 30921308Sache for. If there is no saved search string, abort. */ 31021308Sacheint 31121308Sacherl_noninc_reverse_search_again (count, key) 31221308Sache int count, key; 31321308Sache{ 31421308Sache if (!noninc_search_string) 31521308Sache { 31675406Sache rl_ding (); 31721308Sache return (-1); 31821308Sache } 31921308Sache noninc_dosearch (noninc_search_string, -1); 32021308Sache return 0; 32121308Sache} 32221308Sache 32321308Sachestatic int 32458310Sacherl_history_search_internal (count, dir) 32558310Sache int count, dir; 32621308Sache{ 32758310Sache HIST_ENTRY *temp; 32858310Sache int ret, oldpos; 32921308Sache 33075406Sache rl_maybe_save_line (); 33158310Sache temp = (HIST_ENTRY *)NULL; 33221308Sache 33358310Sache /* Search COUNT times through the history for a line whose prefix 33458310Sache matches history_search_string. When this loop finishes, TEMP, 33558310Sache if non-null, is the history line to copy into the line buffer. */ 33621308Sache while (count) 33721308Sache { 33858310Sache ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir); 33958310Sache if (ret == -1) 34058310Sache break; 34158310Sache 34258310Sache /* Get the history entry we found. */ 34358310Sache rl_history_search_pos = ret; 34458310Sache oldpos = where_history (); 34558310Sache history_set_pos (rl_history_search_pos); 34658310Sache temp = current_history (); 34758310Sache history_set_pos (oldpos); 34858310Sache 34958310Sache /* Don't find multiple instances of the same line. */ 35058310Sache if (prev_line_found && STREQ (prev_line_found, temp->line)) 35158310Sache continue; 35258310Sache prev_line_found = temp->line; 35358310Sache count--; 35421308Sache } 35521308Sache 35658310Sache /* If we didn't find anything at all, return. */ 35721308Sache if (temp == 0) 35821308Sache { 35975406Sache rl_maybe_unsave_line (); 36075406Sache rl_ding (); 36158310Sache /* If you don't want the saved history line (last match) to show up 36258310Sache in the line buffer after the search fails, change the #if 0 to 36358310Sache #if 1 */ 36458310Sache#if 0 36558310Sache if (rl_point > rl_history_search_len) 36658310Sache { 36758310Sache rl_point = rl_end = rl_history_search_len; 36858310Sache rl_line_buffer[rl_end] = '\0'; 36958310Sache } 37058310Sache#else 37175406Sache rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ 37258310Sache#endif 37358310Sache return 1; 37421308Sache } 37521308Sache 37658310Sache /* Copy the line we found into the current line buffer. */ 37758310Sache make_history_line_current (temp); 37858310Sache 37958310Sache rl_point = rl_history_search_len; 38021308Sache return 0; 38121308Sache} 38221308Sache 38358310Sachestatic void 38458310Sacherl_history_search_reinit () 38558310Sache{ 38658310Sache rl_history_search_pos = where_history (); 38758310Sache rl_history_search_len = rl_point; 38858310Sache prev_line_found = (char *)NULL; 38958310Sache if (rl_point) 39058310Sache { 39158310Sache if (rl_history_search_len >= history_string_size - 2) 39258310Sache { 39358310Sache history_string_size = rl_history_search_len + 2; 39458310Sache history_search_string = xrealloc (history_search_string, history_string_size); 39558310Sache } 39658310Sache history_search_string[0] = '^'; 39758310Sache strncpy (history_search_string + 1, rl_line_buffer, rl_point); 39858310Sache history_search_string[rl_point + 1] = '\0'; 39958310Sache } 40075406Sache _rl_free_saved_history_line (); 40158310Sache} 40258310Sache 40321308Sache/* Search forward in the history for the string of characters 40421308Sache from the start of the line to rl_point. This is a non-incremental 40521308Sache search. */ 40621308Sacheint 40721308Sacherl_history_search_forward (count, ignore) 40821308Sache int count, ignore; 40921308Sache{ 41021308Sache if (count == 0) 41121308Sache return (0); 41258310Sache 41358310Sache if (rl_last_func != rl_history_search_forward && 41458310Sache rl_last_func != rl_history_search_backward) 41558310Sache rl_history_search_reinit (); 41658310Sache 41758310Sache if (rl_history_search_len == 0) 41858310Sache return (rl_get_next_history (count, ignore)); 41921308Sache return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 42021308Sache} 42121308Sache 42221308Sache/* Search backward through the history for the string of characters 42321308Sache from the start of the line to rl_point. This is a non-incremental 42421308Sache search. */ 42521308Sacheint 42621308Sacherl_history_search_backward (count, ignore) 42721308Sache int count, ignore; 42821308Sache{ 42921308Sache if (count == 0) 43021308Sache return (0); 43158310Sache 43258310Sache if (rl_last_func != rl_history_search_forward && 43358310Sache rl_last_func != rl_history_search_backward) 43458310Sache rl_history_search_reinit (); 43558310Sache 43658310Sache if (rl_history_search_len == 0) 43758310Sache return (rl_get_previous_history (count, ignore)); 43821308Sache return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 43921308Sache} 440