search.c revision 47558
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 1121308Sache the Free Software Foundation; either version 1, 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, 2221308Sache 675 Mass Ave, Cambridge, MA 02139, 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 4626497Sache#ifdef abs 4726497Sache# undef abs 4826497Sache#endif 4926497Sache#define abs(x) (((x) >= 0) ? (x) : -(x)) 5021308Sache 5121308Sacheextern char *xmalloc (), *xrealloc (); 5221308Sache 5321308Sache/* Variables imported from readline.c */ 5421308Sacheextern int rl_point, rl_end, rl_line_buffer_len; 5521308Sacheextern int rl_editing_mode; 5621308Sacheextern char *rl_prompt; 5721308Sacheextern char *rl_line_buffer; 5821308Sacheextern HIST_ENTRY *saved_line_for_history; 5921308Sacheextern Function *rl_last_func; 6021308Sache 6121308Sache/* Functions imported from the rest of the library. */ 6221308Sacheextern int _rl_free_history_entry (); 6321308Sacheextern char *_rl_make_prompt_for_search (); 6421308Sacheextern void rl_extend_line_buffer (); 6521308Sache 6621308Sachestatic char *noninc_search_string = (char *) NULL; 6721308Sachestatic int noninc_history_pos; 6821308Sachestatic char *prev_line_found = (char *) NULL; 6921308Sache 7021308Sache/* Search the history list for STRING starting at absolute history position 7121308Sache POS. If STRING begins with `^', the search must match STRING at the 7221308Sache beginning of a history line, otherwise a full substring match is performed 7321308Sache for STRING. DIR < 0 means to search backwards through the history list, 7421308Sache DIR >= 0 means to search forward. */ 7521308Sachestatic int 7621308Sachenoninc_search_from_pos (string, pos, dir) 7721308Sache char *string; 7821308Sache int pos, dir; 7921308Sache{ 8021308Sache int ret, old; 8121308Sache 8221308Sache old = where_history (); 8321308Sache history_set_pos (pos); 8421308Sache 8521308Sache if (*string == '^') 8621308Sache ret = history_search_prefix (string + 1, dir); 8721308Sache else 8821308Sache ret = history_search (string, dir); 8921308Sache 9021308Sache if (ret != -1) 9121308Sache ret = where_history (); 9221308Sache 9321308Sache history_set_pos (old); 9421308Sache return (ret); 9521308Sache} 9621308Sache 9721308Sache/* Search for a line in the history containing STRING. If DIR is < 0, the 9821308Sache search is backwards through previous entries, else through subsequent 9921308Sache entries. */ 10021308Sachestatic void 10121308Sachenoninc_dosearch (string, dir) 10221308Sache char *string; 10321308Sache int dir; 10421308Sache{ 10521308Sache int oldpos, pos, line_len; 10621308Sache HIST_ENTRY *entry; 10721308Sache 10821308Sache if (string == 0 || *string == '\0' || noninc_history_pos < 0) 10921308Sache { 11021308Sache ding (); 11121308Sache return; 11221308Sache } 11321308Sache 11421308Sache pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 11521308Sache if (pos == -1) 11621308Sache { 11721308Sache /* Search failed, current history position unchanged. */ 11821308Sache maybe_unsave_line (); 11921308Sache rl_clear_message (); 12021308Sache rl_point = 0; 12121308Sache ding (); 12221308Sache return; 12321308Sache } 12421308Sache 12521308Sache noninc_history_pos = pos; 12621308Sache 12721308Sache oldpos = where_history (); 12821308Sache history_set_pos (noninc_history_pos); 12921308Sache entry = current_history (); 13021308Sache#if defined (VI_MODE) 13121308Sache if (rl_editing_mode != vi_mode) 13221308Sache#endif 13321308Sache history_set_pos (oldpos); 13421308Sache 13521308Sache line_len = strlen (entry->line); 13621308Sache if (line_len >= rl_line_buffer_len) 13721308Sache rl_extend_line_buffer (line_len); 13821308Sache strcpy (rl_line_buffer, entry->line); 13921308Sache 14021308Sache rl_undo_list = (UNDO_LIST *)entry->data; 14121308Sache rl_end = strlen (rl_line_buffer); 14221308Sache rl_point = 0; 14321308Sache rl_clear_message (); 14421308Sache 14521308Sache if (saved_line_for_history) 14621308Sache _rl_free_history_entry (saved_line_for_history); 14721308Sache saved_line_for_history = (HIST_ENTRY *)NULL; 14821308Sache} 14921308Sache 15021308Sache/* Search non-interactively through the history list. DIR < 0 means to 15121308Sache search backwards through the history of previous commands; otherwise 15221308Sache the search is for commands subsequent to the current position in the 15321308Sache history list. PCHAR is the character to use for prompting when reading 15421308Sache the search string; if not specified (0), it defaults to `:'. */ 15521308Sachestatic void 15621308Sachenoninc_search (dir, pchar) 15721308Sache int dir; 15821308Sache int pchar; 15921308Sache{ 16021308Sache int saved_point, c; 16121308Sache char *p; 16221308Sache 16321308Sache maybe_save_line (); 16421308Sache saved_point = rl_point; 16521308Sache 16621308Sache /* Use the line buffer to read the search string. */ 16721308Sache rl_line_buffer[0] = 0; 16821308Sache rl_end = rl_point = 0; 16921308Sache 17021308Sache p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 17121308Sache rl_message (p, 0, 0); 17221308Sache free (p); 17321308Sache 17447558Sache#define SEARCH_RETURN rl_restore_prompt (); return 17521308Sache 17621308Sache /* Read the search string. */ 17721308Sache while (c = rl_read_key ()) 17821308Sache { 17921308Sache switch (c) 18021308Sache { 18121308Sache case CTRL('H'): 18221308Sache case RUBOUT: 18321308Sache if (rl_point == 0) 18421308Sache { 18521308Sache maybe_unsave_line (); 18621308Sache rl_clear_message (); 18721308Sache rl_point = saved_point; 18821308Sache SEARCH_RETURN; 18921308Sache } 19021308Sache rl_rubout (1, c); 19121308Sache break; 19221308Sache 19321308Sache case CTRL('W'): 19421308Sache rl_unix_word_rubout (1, c); 19521308Sache break; 19621308Sache 19721308Sache case CTRL('U'): 19821308Sache rl_unix_line_discard (1, c); 19921308Sache break; 20021308Sache 20121308Sache case RETURN: 20221308Sache case NEWLINE: 20321308Sache goto dosearch; 20421308Sache /* NOTREACHED */ 20521308Sache break; 20621308Sache 20721308Sache case CTRL('C'): 20821308Sache case CTRL('G'): 20921308Sache maybe_unsave_line (); 21021308Sache rl_clear_message (); 21121308Sache rl_point = saved_point; 21221308Sache ding (); 21321308Sache SEARCH_RETURN; 21421308Sache 21521308Sache default: 21621308Sache rl_insert (1, c); 21721308Sache break; 21821308Sache } 21921308Sache (*rl_redisplay_function) (); 22021308Sache } 22121308Sache 22221308Sache dosearch: 22321308Sache /* If rl_point == 0, we want to re-use the previous search string and 22421308Sache start from the saved history position. If there's no previous search 22521308Sache string, punt. */ 22621308Sache if (rl_point == 0) 22721308Sache { 22821308Sache if (!noninc_search_string) 22921308Sache { 23021308Sache ding (); 23121308Sache SEARCH_RETURN; 23221308Sache } 23321308Sache } 23421308Sache else 23521308Sache { 23621308Sache /* We want to start the search from the current history position. */ 23721308Sache noninc_history_pos = where_history (); 23821308Sache if (noninc_search_string) 23921308Sache free (noninc_search_string); 24021308Sache noninc_search_string = savestring (rl_line_buffer); 24121308Sache } 24221308Sache 24347558Sache rl_restore_prompt (); 24421308Sache noninc_dosearch (noninc_search_string, dir); 24521308Sache} 24621308Sache 24721308Sache/* Search forward through the history list for a string. If the vi-mode 24821308Sache code calls this, KEY will be `?'. */ 24921308Sacheint 25021308Sacherl_noninc_forward_search (count, key) 25121308Sache int count, key; 25221308Sache{ 25321308Sache noninc_search (1, (key == '?') ? '?' : 0); 25421308Sache return 0; 25521308Sache} 25621308Sache 25721308Sache/* Reverse search the history list for a string. If the vi-mode code 25821308Sache calls this, KEY will be `/'. */ 25921308Sacheint 26021308Sacherl_noninc_reverse_search (count, key) 26121308Sache int count, key; 26221308Sache{ 26321308Sache noninc_search (-1, (key == '/') ? '/' : 0); 26421308Sache return 0; 26521308Sache} 26621308Sache 26721308Sache/* Search forward through the history list for the last string searched 26821308Sache for. If there is no saved search string, abort. */ 26921308Sacheint 27021308Sacherl_noninc_forward_search_again (count, key) 27121308Sache int count, key; 27221308Sache{ 27321308Sache if (!noninc_search_string) 27421308Sache { 27521308Sache ding (); 27621308Sache return (-1); 27721308Sache } 27821308Sache noninc_dosearch (noninc_search_string, 1); 27921308Sache return 0; 28021308Sache} 28121308Sache 28221308Sache/* Reverse search in the history list for the last string searched 28321308Sache for. If there is no saved search string, abort. */ 28421308Sacheint 28521308Sacherl_noninc_reverse_search_again (count, key) 28621308Sache int count, key; 28721308Sache{ 28821308Sache if (!noninc_search_string) 28921308Sache { 29021308Sache ding (); 29121308Sache return (-1); 29221308Sache } 29321308Sache noninc_dosearch (noninc_search_string, -1); 29421308Sache return 0; 29521308Sache} 29621308Sache 29721308Sachestatic int 29821308Sacherl_history_search_internal (count, direction) 29921308Sache int count, direction; 30021308Sache{ 30121308Sache HIST_ENTRY *temp, *old_temp; 30221308Sache int line_len; 30321308Sache 30421308Sache maybe_save_line (); 30521308Sache 30621308Sache temp = old_temp = (HIST_ENTRY *)NULL; 30721308Sache while (count) 30821308Sache { 30921308Sache temp = (direction < 0) ? previous_history () : next_history (); 31021308Sache if (temp == 0) 31121308Sache break; 31221308Sache /* On an empty prefix, make this the same as previous-history. */ 31321308Sache if (rl_point == 0) 31421308Sache { 31521308Sache count--; 31621308Sache continue; 31721308Sache } 31821308Sache if (STREQN (rl_line_buffer, temp->line, rl_point)) 31921308Sache { 32021308Sache /* Don't find multiple instances of the same line. */ 32121308Sache if (prev_line_found && STREQ (prev_line_found, temp->line)) 32221308Sache continue; 32321308Sache if (direction < 0) 32421308Sache old_temp = temp; 32521308Sache prev_line_found = temp->line; 32621308Sache count--; 32721308Sache } 32821308Sache } 32921308Sache 33021308Sache if (temp == 0) 33121308Sache { 33221308Sache if (direction < 0 && old_temp) 33321308Sache temp = old_temp; 33421308Sache else 33521308Sache { 33621308Sache maybe_unsave_line (); 33721308Sache ding (); 33821308Sache return 1; 33921308Sache } 34021308Sache } 34121308Sache 34221308Sache line_len = strlen (temp->line); 34321308Sache if (line_len >= rl_line_buffer_len) 34421308Sache rl_extend_line_buffer (line_len); 34521308Sache strcpy (rl_line_buffer, temp->line); 34621308Sache rl_undo_list = (UNDO_LIST *)temp->data; 34721308Sache rl_end = line_len; 34821308Sache return 0; 34921308Sache} 35021308Sache 35121308Sache/* Search forward in the history for the string of characters 35221308Sache from the start of the line to rl_point. This is a non-incremental 35321308Sache search. */ 35421308Sacheint 35521308Sacherl_history_search_forward (count, ignore) 35621308Sache int count, ignore; 35721308Sache{ 35821308Sache if (count == 0) 35921308Sache return (0); 36021308Sache if (rl_last_func != rl_history_search_forward) 36121308Sache prev_line_found = (char *)NULL; 36221308Sache return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 36321308Sache} 36421308Sache 36521308Sache/* Search backward through the history for the string of characters 36621308Sache from the start of the line to rl_point. This is a non-incremental 36721308Sache search. */ 36821308Sacheint 36921308Sacherl_history_search_backward (count, ignore) 37021308Sache int count, ignore; 37121308Sache{ 37221308Sache if (count == 0) 37321308Sache return (0); 37421308Sache if (rl_last_func != rl_history_search_backward) 37521308Sache prev_line_found = (char *)NULL; 37621308Sache return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 37721308Sache} 378