search.c revision 21308
1227825Stheraven/* search.c - code for non-incremental searching in emacs and vi modes. */ 2227825Stheraven 3227825Stheraven/* Copyright (C) 1992 Free Software Foundation, Inc. 4227825Stheraven 5227825Stheraven This file is part of the Readline Library (the Library), a set of 6227825Stheraven routines for providing Emacs style line input to programs that ask 7227825Stheraven for it. 8227825Stheraven 9227825Stheraven The Library is free software; you can redistribute it and/or modify 10227825Stheraven it under the terms of the GNU General Public License as published by 11227825Stheraven the Free Software Foundation; either version 1, or (at your option) 12227825Stheraven any later version. 13227825Stheraven 14227825Stheraven The Library is distributed in the hope that it will be useful, but 15227825Stheraven WITHOUT ANY WARRANTY; without even the implied warranty of 16227825Stheraven MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17227825Stheraven General Public License for more details. 18227825Stheraven 19227825Stheraven The GNU General Public License is often shipped with GNU software, and 20227825Stheraven is generally kept in a file called COPYING or LICENSE. If you do not 21227825Stheraven have a copy of the license, write to the Free Software Foundation, 22227825Stheraven 675 Mass Ave, Cambridge, MA 02139, USA. */ 23227825Stheraven#define READLINE_LIBRARY 24227825Stheraven 25227825Stheraven#if defined (HAVE_CONFIG_H) 26227825Stheraven# include <config.h> 27227825Stheraven#endif 28227825Stheraven 29227825Stheraven#include <sys/types.h> 30227825Stheraven#include <stdio.h> 31227825Stheraven 32227825Stheraven#if defined (HAVE_UNISTD_H) 33227825Stheraven# include <unistd.h> 34227825Stheraven#endif 35227825Stheraven 36227825Stheraven#include "rldefs.h" 37227825Stheraven#include "readline.h" 38227825Stheraven#include "history.h" 39227825Stheraven 40227825Stheraven#define abs(x) (((x) > 0) ? (x) : -(x)) 41227825Stheraven 42227825Stheravenextern char *xmalloc (), *xrealloc (); 43227825Stheraven 44227825Stheraven/* Variables imported from readline.c */ 45227825Stheravenextern int rl_point, rl_end, rl_line_buffer_len; 46227825Stheravenextern int rl_editing_mode; 47227825Stheravenextern char *rl_prompt; 48227825Stheravenextern char *rl_line_buffer; 49227825Stheravenextern HIST_ENTRY *saved_line_for_history; 50227825Stheravenextern Function *rl_last_func; 51227825Stheraven 52227825Stheraven/* Functions imported from the rest of the library. */ 53227825Stheravenextern int _rl_free_history_entry (); 54227825Stheravenextern char *_rl_make_prompt_for_search (); 55227825Stheravenextern void _rl_restore_prompt (); 56227825Stheravenextern void rl_extend_line_buffer (); 57227825Stheraven 58227825Stheravenstatic char *noninc_search_string = (char *) NULL; 59262801Sdimstatic int noninc_history_pos; 60227825Stheravenstatic char *prev_line_found = (char *) NULL; 61227825Stheraven 62227825Stheraven/* Search the history list for STRING starting at absolute history position 63227825Stheraven POS. If STRING begins with `^', the search must match STRING at the 64227825Stheraven beginning of a history line, otherwise a full substring match is performed 65227825Stheraven for STRING. DIR < 0 means to search backwards through the history list, 66227825Stheraven DIR >= 0 means to search forward. */ 67227825Stheravenstatic int 68227825Stheravennoninc_search_from_pos (string, pos, dir) 69227825Stheraven char *string; 70227825Stheraven int pos, dir; 71262801Sdim{ 72227825Stheraven int ret, old; 73227825Stheraven 74227825Stheraven old = where_history (); 75227825Stheraven history_set_pos (pos); 76227825Stheraven 77262801Sdim if (*string == '^') 78227825Stheraven ret = history_search_prefix (string + 1, dir); 79227825Stheraven else 80227825Stheraven ret = history_search (string, dir); 81227825Stheraven 82227825Stheraven if (ret != -1) 83262801Sdim ret = where_history (); 84227825Stheraven 85227825Stheraven history_set_pos (old); 86227825Stheraven return (ret); 87227825Stheraven} 88227825Stheraven 89262801Sdim/* Search for a line in the history containing STRING. If DIR is < 0, the 90227825Stheraven search is backwards through previous entries, else through subsequent 91227825Stheraven entries. */ 92227825Stheravenstatic void 93227825Stheravennoninc_dosearch (string, dir) 94227825Stheraven char *string; 95262801Sdim int dir; 96227825Stheraven{ 97227825Stheraven int oldpos, pos, line_len; 98227825Stheraven HIST_ENTRY *entry; 99227825Stheraven 100227825Stheraven if (string == 0 || *string == '\0' || noninc_history_pos < 0) 101262801Sdim { 102227825Stheraven ding (); 103227825Stheraven return; 104227825Stheraven } 105227825Stheraven 106227825Stheraven pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 107262801Sdim if (pos == -1) 108227825Stheraven { 109227825Stheraven /* Search failed, current history position unchanged. */ 110227825Stheraven maybe_unsave_line (); 111227825Stheraven rl_clear_message (); 112227825Stheraven rl_point = 0; 113262801Sdim ding (); 114227825Stheraven return; 115227825Stheraven } 116227825Stheraven 117227825Stheraven noninc_history_pos = pos; 118227825Stheraven 119262801Sdim oldpos = where_history (); 120227825Stheraven history_set_pos (noninc_history_pos); 121227825Stheraven entry = current_history (); 122227825Stheraven#if defined (VI_MODE) 123227825Stheraven if (rl_editing_mode != vi_mode) 124227825Stheraven#endif 125262801Sdim history_set_pos (oldpos); 126227825Stheraven 127227825Stheraven line_len = strlen (entry->line); 128227825Stheraven if (line_len >= rl_line_buffer_len) 129227825Stheraven rl_extend_line_buffer (line_len); 130227825Stheraven strcpy (rl_line_buffer, entry->line); 131262801Sdim 132227825Stheraven rl_undo_list = (UNDO_LIST *)entry->data; 133227825Stheraven rl_end = strlen (rl_line_buffer); 134227825Stheraven rl_point = 0; 135227825Stheraven rl_clear_message (); 136227825Stheraven 137262801Sdim if (saved_line_for_history) 138227825Stheraven _rl_free_history_entry (saved_line_for_history); 139227825Stheraven saved_line_for_history = (HIST_ENTRY *)NULL; 140227825Stheraven} 141227825Stheraven 142227825Stheraven/* Search non-interactively through the history list. DIR < 0 means to 143262801Sdim search backwards through the history of previous commands; otherwise 144227825Stheraven the search is for commands subsequent to the current position in the 145227825Stheraven history list. PCHAR is the character to use for prompting when reading 146227825Stheraven the search string; if not specified (0), it defaults to `:'. */ 147227825Stheravenstatic void 148227825Stheravennoninc_search (dir, pchar) 149262801Sdim int dir; 150227825Stheraven int pchar; 151227825Stheraven{ 152227825Stheraven int saved_point, c; 153227825Stheraven char *p; 154227825Stheraven 155262801Sdim maybe_save_line (); 156227825Stheraven saved_point = rl_point; 157227825Stheraven 158227825Stheraven /* Use the line buffer to read the search string. */ 159227825Stheraven rl_line_buffer[0] = 0; 160227825Stheraven rl_end = rl_point = 0; 161262801Sdim 162262801Sdim p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 163262801Sdim rl_message (p, 0, 0); 164262801Sdim free (p); 165262801Sdim 166262801Sdim#define SEARCH_RETURN _rl_restore_prompt (); return 167262801Sdim 168262801Sdim /* Read the search string. */ 169262801Sdim while (c = rl_read_key ()) 170262801Sdim { 171262801Sdim switch (c) 172262801Sdim { 173262801Sdim case CTRL('H'): 174262801Sdim case RUBOUT: 175262801Sdim if (rl_point == 0) 176262801Sdim { 177262801Sdim maybe_unsave_line (); 178262801Sdim rl_clear_message (); 179262801Sdim rl_point = saved_point; 180262801Sdim SEARCH_RETURN; 181262801Sdim } 182262801Sdim rl_rubout (1, c); 183262801Sdim break; 184262801Sdim 185227825Stheraven case CTRL('W'): 186227825Stheraven rl_unix_word_rubout (1, c); 187227825Stheraven break; 188227825Stheraven 189227825Stheraven case CTRL('U'): 190227825Stheraven rl_unix_line_discard (1, c); 191227825Stheraven break; 192227825Stheraven 193227825Stheraven case RETURN: 194227825Stheraven case NEWLINE: 195227825Stheraven goto dosearch; 196227825Stheraven /* NOTREACHED */ 197227825Stheraven break; 198227825Stheraven 199227825Stheraven case CTRL('C'): 200227825Stheraven case CTRL('G'): 201227825Stheraven maybe_unsave_line (); 202227825Stheraven rl_clear_message (); 203227825Stheraven rl_point = saved_point; 204227825Stheraven ding (); 205227825Stheraven SEARCH_RETURN; 206227825Stheraven 207227825Stheraven default: 208227825Stheraven rl_insert (1, c); 209227825Stheraven break; 210227825Stheraven } 211227825Stheraven (*rl_redisplay_function) (); 212227825Stheraven } 213227825Stheraven 214227825Stheraven dosearch: 215227825Stheraven /* If rl_point == 0, we want to re-use the previous search string and 216227825Stheraven start from the saved history position. If there's no previous search 217227825Stheraven string, punt. */ 218227825Stheraven if (rl_point == 0) 219227825Stheraven { 220227825Stheraven if (!noninc_search_string) 221227825Stheraven { 222227825Stheraven ding (); 223227825Stheraven SEARCH_RETURN; 224227825Stheraven } 225232950Stheraven } 226227825Stheraven else 227227825Stheraven { 228227825Stheraven /* We want to start the search from the current history position. */ 229227825Stheraven noninc_history_pos = where_history (); 230227825Stheraven if (noninc_search_string) 231227825Stheraven free (noninc_search_string); 232227825Stheraven noninc_search_string = savestring (rl_line_buffer); 233227825Stheraven } 234227825Stheraven 235227825Stheraven _rl_restore_prompt (); 236227825Stheraven noninc_dosearch (noninc_search_string, dir); 237227825Stheraven} 238227825Stheraven 239227825Stheraven/* Search forward through the history list for a string. If the vi-mode 240227825Stheraven code calls this, KEY will be `?'. */ 241227825Stheravenint 242227825Stheravenrl_noninc_forward_search (count, key) 243227825Stheraven int count, key; 244227825Stheraven{ 245227825Stheraven noninc_search (1, (key == '?') ? '?' : 0); 246227825Stheraven return 0; 247227825Stheraven} 248227825Stheraven 249227825Stheraven/* Reverse search the history list for a string. If the vi-mode code 250227825Stheraven calls this, KEY will be `/'. */ 251227825Stheravenint 252227825Stheravenrl_noninc_reverse_search (count, key) 253227825Stheraven int count, key; 254227825Stheraven{ 255227825Stheraven noninc_search (-1, (key == '/') ? '/' : 0); 256227825Stheraven return 0; 257227825Stheraven} 258227825Stheraven 259227825Stheraven/* Search forward through the history list for the last string searched 260227825Stheraven for. If there is no saved search string, abort. */ 261227825Stheravenint 262227825Stheravenrl_noninc_forward_search_again (count, key) 263227825Stheraven int count, key; 264227825Stheraven{ 265227825Stheraven if (!noninc_search_string) 266227825Stheraven { 267227825Stheraven ding (); 268227825Stheraven return (-1); 269227825Stheraven } 270227825Stheraven noninc_dosearch (noninc_search_string, 1); 271227825Stheraven return 0; 272227825Stheraven} 273227825Stheraven 274227825Stheraven/* Reverse search in the history list for the last string searched 275227825Stheraven for. If there is no saved search string, abort. */ 276227825Stheravenint 277227825Stheravenrl_noninc_reverse_search_again (count, key) 278227825Stheraven int count, key; 279227825Stheraven{ 280227825Stheraven if (!noninc_search_string) 281227825Stheraven { 282227825Stheraven ding (); 283227825Stheraven return (-1); 284227825Stheraven } 285227825Stheraven noninc_dosearch (noninc_search_string, -1); 286227825Stheraven return 0; 287227825Stheraven} 288227825Stheraven 289227825Stheravenstatic int 290227825Stheravenrl_history_search_internal (count, direction) 291227825Stheraven int count, direction; 292227825Stheraven{ 293227825Stheraven HIST_ENTRY *temp, *old_temp; 294227825Stheraven int line_len; 295227825Stheraven 296227825Stheraven maybe_save_line (); 297227825Stheraven 298227825Stheraven temp = old_temp = (HIST_ENTRY *)NULL; 299227825Stheraven while (count) 300227825Stheraven { 301227825Stheraven temp = (direction < 0) ? previous_history () : next_history (); 302227825Stheraven if (temp == 0) 303227825Stheraven break; 304227825Stheraven /* On an empty prefix, make this the same as previous-history. */ 305227825Stheraven if (rl_point == 0) 306227825Stheraven { 307227825Stheraven count--; 308227825Stheraven continue; 309227825Stheraven } 310227825Stheraven if (STREQN (rl_line_buffer, temp->line, rl_point)) 311227825Stheraven { 312227825Stheraven /* Don't find multiple instances of the same line. */ 313227825Stheraven if (prev_line_found && STREQ (prev_line_found, temp->line)) 314227825Stheraven continue; 315227825Stheraven if (direction < 0) 316227825Stheraven old_temp = temp; 317227825Stheraven prev_line_found = temp->line; 318227825Stheraven count--; 319227825Stheraven } 320227825Stheraven } 321227825Stheraven 322227825Stheraven if (temp == 0) 323227825Stheraven { 324227825Stheraven if (direction < 0 && old_temp) 325227825Stheraven temp = old_temp; 326227825Stheraven else 327227825Stheraven { 328227825Stheraven maybe_unsave_line (); 329227825Stheraven ding (); 330227825Stheraven return 1; 331227825Stheraven } 332227825Stheraven } 333227825Stheraven 334227825Stheraven line_len = strlen (temp->line); 335227825Stheraven if (line_len >= rl_line_buffer_len) 336227825Stheraven rl_extend_line_buffer (line_len); 337227825Stheraven strcpy (rl_line_buffer, temp->line); 338227825Stheraven rl_undo_list = (UNDO_LIST *)temp->data; 339227825Stheraven rl_end = line_len; 340227825Stheraven return 0; 341227825Stheraven} 342227825Stheraven 343227825Stheraven/* Search forward in the history for the string of characters 344227825Stheraven from the start of the line to rl_point. This is a non-incremental 345227825Stheraven search. */ 346227825Stheravenint 347227825Stheravenrl_history_search_forward (count, ignore) 348227825Stheraven int count, ignore; 349227825Stheraven{ 350227825Stheraven if (count == 0) 351227825Stheraven return (0); 352227825Stheraven if (rl_last_func != rl_history_search_forward) 353227825Stheraven prev_line_found = (char *)NULL; 354227825Stheraven return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 355227825Stheraven} 356227825Stheraven 357227825Stheraven/* Search backward through the history for the string of characters 358227825Stheraven from the start of the line to rl_point. This is a non-incremental 359227825Stheraven search. */ 360227825Stheravenint 361227825Stheravenrl_history_search_backward (count, ignore) 362227825Stheraven int count, ignore; 363227825Stheraven{ 364227825Stheraven if (count == 0) 365227825Stheraven return (0); 366227825Stheraven if (rl_last_func != rl_history_search_backward) 367227825Stheraven prev_line_found = (char *)NULL; 368227825Stheraven return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 369227825Stheraven} 370227825Stheraven