121308Sache/* search.c - code for non-incremental searching in emacs and vi modes. */ 221308Sache 3157184Sache/* Copyright (C) 1992-2005 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" 43119610Sache#include "rlmbutil.h" 44119610Sache 4521308Sache#include "readline.h" 4621308Sache#include "history.h" 4721308Sache 4858310Sache#include "rlprivate.h" 4958310Sache#include "xmalloc.h" 5058310Sache 5126497Sache#ifdef abs 5226497Sache# undef abs 5326497Sache#endif 5426497Sache#define abs(x) (((x) >= 0) ? (x) : -(x)) 5521308Sache 56157184Sache_rl_search_cxt *_rl_nscxt = 0; 57157184Sache 5875406Sacheextern HIST_ENTRY *_rl_saved_line_for_history; 5921308Sache 6021308Sache/* Functions imported from the rest of the library. */ 61119610Sacheextern int _rl_free_history_entry PARAMS((HIST_ENTRY *)); 6221308Sache 6321308Sachestatic char *noninc_search_string = (char *) NULL; 6421308Sachestatic int noninc_history_pos; 6558310Sache 6621308Sachestatic char *prev_line_found = (char *) NULL; 6721308Sache 6858310Sachestatic int rl_history_search_len; 6958310Sachestatic int rl_history_search_pos; 7058310Sachestatic char *history_search_string; 7158310Sachestatic int history_string_size; 7258310Sache 73119610Sachestatic void make_history_line_current PARAMS((HIST_ENTRY *)); 74119610Sachestatic int noninc_search_from_pos PARAMS((char *, int, int)); 75157184Sachestatic int noninc_dosearch PARAMS((char *, int)); 76157184Sachestatic int noninc_search PARAMS((int, int)); 77119610Sachestatic int rl_history_search_internal PARAMS((int, int)); 78119610Sachestatic void rl_history_search_reinit PARAMS((void)); 79119610Sache 80157184Sachestatic _rl_search_cxt *_rl_nsearch_init PARAMS((int, int)); 81157184Sachestatic int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int)); 82157184Sachestatic void _rl_nsearch_abort PARAMS((_rl_search_cxt *)); 83157184Sachestatic int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int)); 84157184Sache 8558310Sache/* Make the data from the history entry ENTRY be the contents of the 8658310Sache current line. This doesn't do anything with rl_point; the caller 8758310Sache must set it. */ 8858310Sachestatic void 8958310Sachemake_history_line_current (entry) 9058310Sache HIST_ENTRY *entry; 9158310Sache{ 92136644Sache _rl_replace_text (entry->line, 0, rl_end); 93136644Sache _rl_fix_point (1); 94157184Sache#if defined (VI_MODE) 95157184Sache if (rl_editing_mode == vi_mode) 96157184Sache /* POSIX.2 says that the `U' command doesn't affect the copy of any 97157184Sache command lines to the edit line. We're going to implement that by 98157184Sache making the undo list start after the matching line is copied to the 99157184Sache current editing buffer. */ 100157184Sache rl_free_undo_list (); 101136644Sache#endif 10258310Sache 10375406Sache if (_rl_saved_line_for_history) 10475406Sache _rl_free_history_entry (_rl_saved_line_for_history); 10575406Sache _rl_saved_line_for_history = (HIST_ENTRY *)NULL; 10658310Sache} 10758310Sache 10821308Sache/* Search the history list for STRING starting at absolute history position 10921308Sache POS. If STRING begins with `^', the search must match STRING at the 11021308Sache beginning of a history line, otherwise a full substring match is performed 11121308Sache for STRING. DIR < 0 means to search backwards through the history list, 11221308Sache DIR >= 0 means to search forward. */ 11321308Sachestatic int 11421308Sachenoninc_search_from_pos (string, pos, dir) 11521308Sache char *string; 11621308Sache int pos, dir; 11721308Sache{ 11821308Sache int ret, old; 11921308Sache 12075406Sache if (pos < 0) 12175406Sache return -1; 12275406Sache 12321308Sache old = where_history (); 12475406Sache if (history_set_pos (pos) == 0) 12575406Sache return -1; 12621308Sache 12775406Sache RL_SETSTATE(RL_STATE_SEARCH); 12821308Sache if (*string == '^') 12921308Sache ret = history_search_prefix (string + 1, dir); 13021308Sache else 13121308Sache ret = history_search (string, dir); 13275406Sache RL_UNSETSTATE(RL_STATE_SEARCH); 13321308Sache 13421308Sache if (ret != -1) 13521308Sache ret = where_history (); 13621308Sache 13721308Sache history_set_pos (old); 13821308Sache return (ret); 13921308Sache} 14021308Sache 14121308Sache/* Search for a line in the history containing STRING. If DIR is < 0, the 14221308Sache search is backwards through previous entries, else through subsequent 143157184Sache entries. Returns 1 if the search was successful, 0 otherwise. */ 144157184Sachestatic int 14521308Sachenoninc_dosearch (string, dir) 14621308Sache char *string; 14721308Sache int dir; 14821308Sache{ 14958310Sache int oldpos, pos; 15021308Sache HIST_ENTRY *entry; 15121308Sache 15221308Sache if (string == 0 || *string == '\0' || noninc_history_pos < 0) 15321308Sache { 15475406Sache rl_ding (); 155157184Sache return 0; 15621308Sache } 15721308Sache 15821308Sache pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 15921308Sache if (pos == -1) 16021308Sache { 16121308Sache /* Search failed, current history position unchanged. */ 16275406Sache rl_maybe_unsave_line (); 16321308Sache rl_clear_message (); 16421308Sache rl_point = 0; 16575406Sache rl_ding (); 166157184Sache return 0; 16721308Sache } 16821308Sache 16921308Sache noninc_history_pos = pos; 17021308Sache 17121308Sache oldpos = where_history (); 17221308Sache history_set_pos (noninc_history_pos); 17321308Sache entry = current_history (); 17421308Sache#if defined (VI_MODE) 17521308Sache if (rl_editing_mode != vi_mode) 17621308Sache#endif 177157184Sache history_set_pos (oldpos); 17821308Sache 17958310Sache make_history_line_current (entry); 18021308Sache 18121308Sache rl_point = 0; 182119610Sache rl_mark = rl_end; 183119610Sache 18421308Sache rl_clear_message (); 185157184Sache return 1; 18621308Sache} 18721308Sache 188157184Sachestatic _rl_search_cxt * 189157184Sache_rl_nsearch_init (dir, pchar) 190157184Sache int dir, pchar; 19121308Sache{ 192157184Sache _rl_search_cxt *cxt; 19321308Sache char *p; 19421308Sache 195157184Sache cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0); 196157184Sache if (dir < 0) 197157184Sache cxt->sflags |= SF_REVERSE; /* not strictly needed */ 198157184Sache 199157184Sache cxt->direction = dir; 200157184Sache cxt->history_pos = cxt->save_line; 201157184Sache 20275406Sache rl_maybe_save_line (); 20321308Sache 204136644Sache /* Clear the undo list, since reading the search string should create its 205136644Sache own undo list, and the whole list will end up being freed when we 206136644Sache finish reading the search string. */ 207136644Sache rl_undo_list = 0; 208136644Sache 20921308Sache /* Use the line buffer to read the search string. */ 21021308Sache rl_line_buffer[0] = 0; 21121308Sache rl_end = rl_point = 0; 21221308Sache 21321308Sache p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 214165670Sache rl_message ("%s", p, 0); 21521308Sache free (p); 21621308Sache 21775406Sache RL_SETSTATE(RL_STATE_NSEARCH); 21875406Sache 219157184Sache _rl_nscxt = cxt; 220119610Sache 221157184Sache return cxt; 222157184Sache} 22375406Sache 224157184Sachestatic int 225157184Sache_rl_nsearch_cleanup (cxt, r) 226157184Sache _rl_search_cxt *cxt; 227157184Sache int r; 228157184Sache{ 229157184Sache _rl_scxt_dispose (cxt, 0); 230157184Sache _rl_nscxt = 0; 23121308Sache 232157184Sache RL_UNSETSTATE(RL_STATE_NSEARCH); 23321308Sache 234157184Sache return (r != 1); 235157184Sache} 23621308Sache 237157184Sachestatic void 238157184Sache_rl_nsearch_abort (cxt) 239157184Sache _rl_search_cxt *cxt; 240157184Sache{ 241157184Sache rl_maybe_unsave_line (); 242157184Sache rl_clear_message (); 243157184Sache rl_point = cxt->save_point; 244157184Sache rl_mark = cxt->save_mark; 245157184Sache rl_restore_prompt (); 24621308Sache 247157184Sache RL_UNSETSTATE (RL_STATE_NSEARCH); 248157184Sache} 24921308Sache 250157184Sache/* Process just-read character C according to search context CXT. Return -1 251157184Sache if the caller should abort the search, 0 if we should break out of the 252157184Sache loop, and 1 if we should continue to read characters. */ 253157184Sachestatic int 254157184Sache_rl_nsearch_dispatch (cxt, c) 255157184Sache _rl_search_cxt *cxt; 256157184Sache int c; 257157184Sache{ 258157184Sache switch (c) 259157184Sache { 260157184Sache case CTRL('W'): 261157184Sache rl_unix_word_rubout (1, c); 262157184Sache break; 263157184Sache 264157184Sache case CTRL('U'): 265157184Sache rl_unix_line_discard (1, c); 266157184Sache break; 267157184Sache 268157184Sache case RETURN: 269157184Sache case NEWLINE: 270157184Sache return 0; 271157184Sache 272157184Sache case CTRL('H'): 273157184Sache case RUBOUT: 274157184Sache if (rl_point == 0) 275157184Sache { 276157184Sache _rl_nsearch_abort (cxt); 277157184Sache return -1; 278157184Sache } 279157184Sache _rl_rubout_char (1, c); 280157184Sache break; 281157184Sache 282157184Sache case CTRL('C'): 283157184Sache case CTRL('G'): 284157184Sache rl_ding (); 285157184Sache _rl_nsearch_abort (cxt); 286157184Sache return -1; 287157184Sache 288157184Sache default: 289119610Sache#if defined (HANDLE_MULTIBYTE) 290157184Sache if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 291157184Sache rl_insert_text (cxt->mb); 292157184Sache else 293119610Sache#endif 294157184Sache _rl_insert_char (1, c); 295157184Sache break; 29621308Sache } 29721308Sache 298157184Sache (*rl_redisplay_function) (); 299157184Sache return 1; 300157184Sache} 301119610Sache 302157184Sache/* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return 303157184Sache -1 if the search should be aborted, any other value means to clean up 304157184Sache using _rl_nsearch_cleanup (). Returns 1 if the search was successful, 305157184Sache 0 otherwise. */ 306157184Sachestatic int 307157184Sache_rl_nsearch_dosearch (cxt) 308157184Sache _rl_search_cxt *cxt; 309157184Sache{ 310157184Sache rl_mark = cxt->save_mark; 311157184Sache 31221308Sache /* If rl_point == 0, we want to re-use the previous search string and 31321308Sache start from the saved history position. If there's no previous search 31421308Sache string, punt. */ 31521308Sache if (rl_point == 0) 31621308Sache { 317157184Sache if (noninc_search_string == 0) 31821308Sache { 31975406Sache rl_ding (); 320157184Sache rl_restore_prompt (); 321157184Sache RL_UNSETSTATE (RL_STATE_NSEARCH); 322157184Sache return -1; 32321308Sache } 32421308Sache } 32521308Sache else 32621308Sache { 32721308Sache /* We want to start the search from the current history position. */ 328157184Sache noninc_history_pos = cxt->save_line; 32958310Sache FREE (noninc_search_string); 33021308Sache noninc_search_string = savestring (rl_line_buffer); 331157184Sache 332157184Sache /* If we don't want the subsequent undo list generated by the search 333157184Sache matching a history line to include the contents of the search string, 334157184Sache we need to clear rl_line_buffer here. For now, we just clear the 335157184Sache undo list generated by reading the search string. (If the search 336157184Sache fails, the old undo list will be restored by rl_maybe_unsave_line.) */ 337157184Sache rl_free_undo_list (); 33821308Sache } 33921308Sache 34047558Sache rl_restore_prompt (); 341157184Sache return (noninc_dosearch (noninc_search_string, cxt->direction)); 34221308Sache} 34321308Sache 344157184Sache/* Search non-interactively through the history list. DIR < 0 means to 345157184Sache search backwards through the history of previous commands; otherwise 346157184Sache the search is for commands subsequent to the current position in the 347157184Sache history list. PCHAR is the character to use for prompting when reading 348157184Sache the search string; if not specified (0), it defaults to `:'. */ 349157184Sachestatic int 350157184Sachenoninc_search (dir, pchar) 351157184Sache int dir; 352157184Sache int pchar; 353157184Sache{ 354157184Sache _rl_search_cxt *cxt; 355157184Sache int c, r; 356157184Sache 357157184Sache cxt = _rl_nsearch_init (dir, pchar); 358157184Sache 359157184Sache if (RL_ISSTATE (RL_STATE_CALLBACK)) 360157184Sache return (0); 361157184Sache 362157184Sache /* Read the search string. */ 363157184Sache r = 0; 364157184Sache while (1) 365157184Sache { 366157184Sache c = _rl_search_getchar (cxt); 367157184Sache 368157184Sache if (c == 0) 369157184Sache break; 370157184Sache 371157184Sache r = _rl_nsearch_dispatch (cxt, c); 372157184Sache if (r < 0) 373157184Sache return 1; 374157184Sache else if (r == 0) 375157184Sache break; 376157184Sache } 377157184Sache 378157184Sache r = _rl_nsearch_dosearch (cxt); 379157184Sache return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 380157184Sache} 381157184Sache 38221308Sache/* Search forward through the history list for a string. If the vi-mode 38321308Sache code calls this, KEY will be `?'. */ 38421308Sacheint 38521308Sacherl_noninc_forward_search (count, key) 38621308Sache int count, key; 38721308Sache{ 388157184Sache return noninc_search (1, (key == '?') ? '?' : 0); 38921308Sache} 39021308Sache 39121308Sache/* Reverse search the history list for a string. If the vi-mode code 39221308Sache calls this, KEY will be `/'. */ 39321308Sacheint 39421308Sacherl_noninc_reverse_search (count, key) 39521308Sache int count, key; 39621308Sache{ 397157184Sache return noninc_search (-1, (key == '/') ? '/' : 0); 39821308Sache} 39921308Sache 40021308Sache/* Search forward through the history list for the last string searched 40121308Sache for. If there is no saved search string, abort. */ 40221308Sacheint 40321308Sacherl_noninc_forward_search_again (count, key) 40421308Sache int count, key; 40521308Sache{ 406157184Sache int r; 407157184Sache 40821308Sache if (!noninc_search_string) 40921308Sache { 41075406Sache rl_ding (); 41121308Sache return (-1); 41221308Sache } 413157184Sache r = noninc_dosearch (noninc_search_string, 1); 414157184Sache return (r != 1); 41521308Sache} 41621308Sache 41721308Sache/* Reverse search in the history list for the last string searched 41821308Sache for. If there is no saved search string, abort. */ 41921308Sacheint 42021308Sacherl_noninc_reverse_search_again (count, key) 42121308Sache int count, key; 42221308Sache{ 423157184Sache int r; 424157184Sache 42521308Sache if (!noninc_search_string) 42621308Sache { 42775406Sache rl_ding (); 42821308Sache return (-1); 42921308Sache } 430157184Sache r = noninc_dosearch (noninc_search_string, -1); 431157184Sache return (r != 1); 43221308Sache} 43321308Sache 434157184Sache#if defined (READLINE_CALLBACKS) 435157184Sacheint 436157184Sache_rl_nsearch_callback (cxt) 437157184Sache _rl_search_cxt *cxt; 438157184Sache{ 439157184Sache int c, r; 440157184Sache 441157184Sache c = _rl_search_getchar (cxt); 442157184Sache r = _rl_nsearch_dispatch (cxt, c); 443157184Sache if (r != 0) 444157184Sache return 1; 445157184Sache 446157184Sache r = _rl_nsearch_dosearch (cxt); 447157184Sache return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1)); 448157184Sache} 449157184Sache#endif 450157184Sache 45121308Sachestatic int 45258310Sacherl_history_search_internal (count, dir) 45358310Sache int count, dir; 45421308Sache{ 45558310Sache HIST_ENTRY *temp; 45658310Sache int ret, oldpos; 45721308Sache 45875406Sache rl_maybe_save_line (); 45958310Sache temp = (HIST_ENTRY *)NULL; 46021308Sache 46158310Sache /* Search COUNT times through the history for a line whose prefix 46258310Sache matches history_search_string. When this loop finishes, TEMP, 46358310Sache if non-null, is the history line to copy into the line buffer. */ 46421308Sache while (count) 46521308Sache { 46658310Sache ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir); 46758310Sache if (ret == -1) 46858310Sache break; 46958310Sache 47058310Sache /* Get the history entry we found. */ 47158310Sache rl_history_search_pos = ret; 47258310Sache oldpos = where_history (); 47358310Sache history_set_pos (rl_history_search_pos); 47458310Sache temp = current_history (); 47558310Sache history_set_pos (oldpos); 47658310Sache 47758310Sache /* Don't find multiple instances of the same line. */ 47858310Sache if (prev_line_found && STREQ (prev_line_found, temp->line)) 47958310Sache continue; 48058310Sache prev_line_found = temp->line; 48158310Sache count--; 48221308Sache } 48321308Sache 48458310Sache /* If we didn't find anything at all, return. */ 48521308Sache if (temp == 0) 48621308Sache { 48775406Sache rl_maybe_unsave_line (); 48875406Sache rl_ding (); 48958310Sache /* If you don't want the saved history line (last match) to show up 49058310Sache in the line buffer after the search fails, change the #if 0 to 49158310Sache #if 1 */ 49258310Sache#if 0 49358310Sache if (rl_point > rl_history_search_len) 49458310Sache { 49558310Sache rl_point = rl_end = rl_history_search_len; 49658310Sache rl_line_buffer[rl_end] = '\0'; 497119610Sache rl_mark = 0; 49858310Sache } 49958310Sache#else 50075406Sache rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ 501119610Sache rl_mark = rl_end; 50258310Sache#endif 50358310Sache return 1; 50421308Sache } 50521308Sache 50658310Sache /* Copy the line we found into the current line buffer. */ 50758310Sache make_history_line_current (temp); 50858310Sache 50958310Sache rl_point = rl_history_search_len; 510119610Sache rl_mark = rl_end; 511119610Sache 51221308Sache return 0; 51321308Sache} 51421308Sache 51558310Sachestatic void 51658310Sacherl_history_search_reinit () 51758310Sache{ 51858310Sache rl_history_search_pos = where_history (); 51958310Sache rl_history_search_len = rl_point; 52058310Sache prev_line_found = (char *)NULL; 52158310Sache if (rl_point) 52258310Sache { 52358310Sache if (rl_history_search_len >= history_string_size - 2) 52458310Sache { 52558310Sache history_string_size = rl_history_search_len + 2; 526119610Sache history_search_string = (char *)xrealloc (history_search_string, history_string_size); 52758310Sache } 52858310Sache history_search_string[0] = '^'; 52958310Sache strncpy (history_search_string + 1, rl_line_buffer, rl_point); 53058310Sache history_search_string[rl_point + 1] = '\0'; 53158310Sache } 53275406Sache _rl_free_saved_history_line (); 53358310Sache} 53458310Sache 53521308Sache/* Search forward in the history for the string of characters 53621308Sache from the start of the line to rl_point. This is a non-incremental 53721308Sache search. */ 53821308Sacheint 53921308Sacherl_history_search_forward (count, ignore) 54021308Sache int count, ignore; 54121308Sache{ 54221308Sache if (count == 0) 54321308Sache return (0); 54458310Sache 54558310Sache if (rl_last_func != rl_history_search_forward && 54658310Sache rl_last_func != rl_history_search_backward) 54758310Sache rl_history_search_reinit (); 54858310Sache 54958310Sache if (rl_history_search_len == 0) 55058310Sache return (rl_get_next_history (count, ignore)); 55121308Sache return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 55221308Sache} 55321308Sache 55421308Sache/* Search backward through the history for the string of characters 55521308Sache from the start of the line to rl_point. This is a non-incremental 55621308Sache search. */ 55721308Sacheint 55821308Sacherl_history_search_backward (count, ignore) 55921308Sache int count, ignore; 56021308Sache{ 56121308Sache if (count == 0) 56221308Sache return (0); 56358310Sache 56458310Sache if (rl_last_func != rl_history_search_forward && 56558310Sache rl_last_func != rl_history_search_backward) 56658310Sache rl_history_search_reinit (); 56758310Sache 56858310Sache if (rl_history_search_len == 0) 56958310Sache return (rl_get_previous_history (count, ignore)); 57021308Sache return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 57121308Sache} 572