search.c revision 75406
1/* search.c - code for non-incremental searching in emacs and vi modes. */ 2 3/* Copyright (C) 1992 Free Software Foundation, Inc. 4 5 This file is part of the Readline Library (the Library), a set of 6 routines for providing Emacs style line input to programs that ask 7 for it. 8 9 The Library is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 The Library is distributed in the hope that it will be useful, but 15 WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 General Public License for more details. 18 19 The GNU General Public License is often shipped with GNU software, and 20 is generally kept in a file called COPYING or LICENSE. If you do not 21 have a copy of the license, write to the Free Software Foundation, 22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 23#define READLINE_LIBRARY 24 25#if defined (HAVE_CONFIG_H) 26# include <config.h> 27#endif 28 29#include <sys/types.h> 30#include <stdio.h> 31 32#if defined (HAVE_UNISTD_H) 33# include <unistd.h> 34#endif 35 36#if defined (HAVE_STDLIB_H) 37# include <stdlib.h> 38#else 39# include "ansi_stdlib.h" 40#endif 41 42#include "rldefs.h" 43#include "readline.h" 44#include "history.h" 45 46#include "rlprivate.h" 47#include "xmalloc.h" 48 49#ifdef abs 50# undef abs 51#endif 52#define abs(x) (((x) >= 0) ? (x) : -(x)) 53 54extern HIST_ENTRY *_rl_saved_line_for_history; 55 56/* Functions imported from the rest of the library. */ 57extern int _rl_free_history_entry __P((HIST_ENTRY *)); 58 59static char *noninc_search_string = (char *) NULL; 60static int noninc_history_pos; 61 62static char *prev_line_found = (char *) NULL; 63 64static int rl_history_search_len; 65static int rl_history_search_pos; 66static char *history_search_string; 67static int history_string_size; 68 69/* Make the data from the history entry ENTRY be the contents of the 70 current line. This doesn't do anything with rl_point; the caller 71 must set it. */ 72static void 73make_history_line_current (entry) 74 HIST_ENTRY *entry; 75{ 76 int line_len; 77 78 line_len = strlen (entry->line); 79 if (line_len >= rl_line_buffer_len) 80 rl_extend_line_buffer (line_len); 81 strcpy (rl_line_buffer, entry->line); 82 83 rl_undo_list = (UNDO_LIST *)entry->data; 84 rl_end = line_len; 85 86 if (_rl_saved_line_for_history) 87 _rl_free_history_entry (_rl_saved_line_for_history); 88 _rl_saved_line_for_history = (HIST_ENTRY *)NULL; 89} 90 91/* Search the history list for STRING starting at absolute history position 92 POS. If STRING begins with `^', the search must match STRING at the 93 beginning of a history line, otherwise a full substring match is performed 94 for STRING. DIR < 0 means to search backwards through the history list, 95 DIR >= 0 means to search forward. */ 96static int 97noninc_search_from_pos (string, pos, dir) 98 char *string; 99 int pos, dir; 100{ 101 int ret, old; 102 103 if (pos < 0) 104 return -1; 105 106 old = where_history (); 107 if (history_set_pos (pos) == 0) 108 return -1; 109 110 RL_SETSTATE(RL_STATE_SEARCH); 111 if (*string == '^') 112 ret = history_search_prefix (string + 1, dir); 113 else 114 ret = history_search (string, dir); 115 RL_UNSETSTATE(RL_STATE_SEARCH); 116 117 if (ret != -1) 118 ret = where_history (); 119 120 history_set_pos (old); 121 return (ret); 122} 123 124/* Search for a line in the history containing STRING. If DIR is < 0, the 125 search is backwards through previous entries, else through subsequent 126 entries. */ 127static void 128noninc_dosearch (string, dir) 129 char *string; 130 int dir; 131{ 132 int oldpos, pos; 133 HIST_ENTRY *entry; 134 135 if (string == 0 || *string == '\0' || noninc_history_pos < 0) 136 { 137 rl_ding (); 138 return; 139 } 140 141 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); 142 if (pos == -1) 143 { 144 /* Search failed, current history position unchanged. */ 145 rl_maybe_unsave_line (); 146 rl_clear_message (); 147 rl_point = 0; 148 rl_ding (); 149 return; 150 } 151 152 noninc_history_pos = pos; 153 154 oldpos = where_history (); 155 history_set_pos (noninc_history_pos); 156 entry = current_history (); 157#if defined (VI_MODE) 158 if (rl_editing_mode != vi_mode) 159#endif 160 history_set_pos (oldpos); 161 162 make_history_line_current (entry); 163 164 rl_point = 0; 165 rl_clear_message (); 166} 167 168/* Search non-interactively through the history list. DIR < 0 means to 169 search backwards through the history of previous commands; otherwise 170 the search is for commands subsequent to the current position in the 171 history list. PCHAR is the character to use for prompting when reading 172 the search string; if not specified (0), it defaults to `:'. */ 173static void 174noninc_search (dir, pchar) 175 int dir; 176 int pchar; 177{ 178 int saved_point, c; 179 char *p; 180 181 rl_maybe_save_line (); 182 saved_point = rl_point; 183 184 /* Use the line buffer to read the search string. */ 185 rl_line_buffer[0] = 0; 186 rl_end = rl_point = 0; 187 188 p = _rl_make_prompt_for_search (pchar ? pchar : ':'); 189 rl_message (p, 0, 0); 190 free (p); 191 192#define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return 193 194 RL_SETSTATE(RL_STATE_NSEARCH); 195 /* Read the search string. */ 196 while (1) 197 { 198 RL_SETSTATE(RL_STATE_MOREINPUT); 199 c = rl_read_key (); 200 RL_UNSETSTATE(RL_STATE_MOREINPUT); 201 202 if (c == 0) 203 break; 204 205 switch (c) 206 { 207 case CTRL('H'): 208 case RUBOUT: 209 if (rl_point == 0) 210 { 211 rl_maybe_unsave_line (); 212 rl_clear_message (); 213 rl_point = saved_point; 214 SEARCH_RETURN; 215 } 216 rl_rubout (1, c); 217 break; 218 219 case CTRL('W'): 220 rl_unix_word_rubout (1, c); 221 break; 222 223 case CTRL('U'): 224 rl_unix_line_discard (1, c); 225 break; 226 227 case RETURN: 228 case NEWLINE: 229 goto dosearch; 230 /* NOTREACHED */ 231 break; 232 233 case CTRL('C'): 234 case CTRL('G'): 235 rl_maybe_unsave_line (); 236 rl_clear_message (); 237 rl_point = saved_point; 238 rl_ding (); 239 SEARCH_RETURN; 240 241 default: 242 rl_insert (1, c); 243 break; 244 } 245 (*rl_redisplay_function) (); 246 } 247 248 dosearch: 249 /* If rl_point == 0, we want to re-use the previous search string and 250 start from the saved history position. If there's no previous search 251 string, punt. */ 252 if (rl_point == 0) 253 { 254 if (!noninc_search_string) 255 { 256 rl_ding (); 257 SEARCH_RETURN; 258 } 259 } 260 else 261 { 262 /* We want to start the search from the current history position. */ 263 noninc_history_pos = where_history (); 264 FREE (noninc_search_string); 265 noninc_search_string = savestring (rl_line_buffer); 266 } 267 268 rl_restore_prompt (); 269 noninc_dosearch (noninc_search_string, dir); 270 RL_UNSETSTATE(RL_STATE_NSEARCH); 271} 272 273/* Search forward through the history list for a string. If the vi-mode 274 code calls this, KEY will be `?'. */ 275int 276rl_noninc_forward_search (count, key) 277 int count, key; 278{ 279 noninc_search (1, (key == '?') ? '?' : 0); 280 return 0; 281} 282 283/* Reverse search the history list for a string. If the vi-mode code 284 calls this, KEY will be `/'. */ 285int 286rl_noninc_reverse_search (count, key) 287 int count, key; 288{ 289 noninc_search (-1, (key == '/') ? '/' : 0); 290 return 0; 291} 292 293/* Search forward through the history list for the last string searched 294 for. If there is no saved search string, abort. */ 295int 296rl_noninc_forward_search_again (count, key) 297 int count, key; 298{ 299 if (!noninc_search_string) 300 { 301 rl_ding (); 302 return (-1); 303 } 304 noninc_dosearch (noninc_search_string, 1); 305 return 0; 306} 307 308/* Reverse search in the history list for the last string searched 309 for. If there is no saved search string, abort. */ 310int 311rl_noninc_reverse_search_again (count, key) 312 int count, key; 313{ 314 if (!noninc_search_string) 315 { 316 rl_ding (); 317 return (-1); 318 } 319 noninc_dosearch (noninc_search_string, -1); 320 return 0; 321} 322 323static int 324rl_history_search_internal (count, dir) 325 int count, dir; 326{ 327 HIST_ENTRY *temp; 328 int ret, oldpos; 329 330 rl_maybe_save_line (); 331 temp = (HIST_ENTRY *)NULL; 332 333 /* Search COUNT times through the history for a line whose prefix 334 matches history_search_string. When this loop finishes, TEMP, 335 if non-null, is the history line to copy into the line buffer. */ 336 while (count) 337 { 338 ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir); 339 if (ret == -1) 340 break; 341 342 /* Get the history entry we found. */ 343 rl_history_search_pos = ret; 344 oldpos = where_history (); 345 history_set_pos (rl_history_search_pos); 346 temp = current_history (); 347 history_set_pos (oldpos); 348 349 /* Don't find multiple instances of the same line. */ 350 if (prev_line_found && STREQ (prev_line_found, temp->line)) 351 continue; 352 prev_line_found = temp->line; 353 count--; 354 } 355 356 /* If we didn't find anything at all, return. */ 357 if (temp == 0) 358 { 359 rl_maybe_unsave_line (); 360 rl_ding (); 361 /* If you don't want the saved history line (last match) to show up 362 in the line buffer after the search fails, change the #if 0 to 363 #if 1 */ 364#if 0 365 if (rl_point > rl_history_search_len) 366 { 367 rl_point = rl_end = rl_history_search_len; 368 rl_line_buffer[rl_end] = '\0'; 369 } 370#else 371 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ 372#endif 373 return 1; 374 } 375 376 /* Copy the line we found into the current line buffer. */ 377 make_history_line_current (temp); 378 379 rl_point = rl_history_search_len; 380 return 0; 381} 382 383static void 384rl_history_search_reinit () 385{ 386 rl_history_search_pos = where_history (); 387 rl_history_search_len = rl_point; 388 prev_line_found = (char *)NULL; 389 if (rl_point) 390 { 391 if (rl_history_search_len >= history_string_size - 2) 392 { 393 history_string_size = rl_history_search_len + 2; 394 history_search_string = xrealloc (history_search_string, history_string_size); 395 } 396 history_search_string[0] = '^'; 397 strncpy (history_search_string + 1, rl_line_buffer, rl_point); 398 history_search_string[rl_point + 1] = '\0'; 399 } 400 _rl_free_saved_history_line (); 401} 402 403/* Search forward in the history for the string of characters 404 from the start of the line to rl_point. This is a non-incremental 405 search. */ 406int 407rl_history_search_forward (count, ignore) 408 int count, ignore; 409{ 410 if (count == 0) 411 return (0); 412 413 if (rl_last_func != rl_history_search_forward && 414 rl_last_func != rl_history_search_backward) 415 rl_history_search_reinit (); 416 417 if (rl_history_search_len == 0) 418 return (rl_get_next_history (count, ignore)); 419 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); 420} 421 422/* Search backward through the history for the string of characters 423 from the start of the line to rl_point. This is a non-incremental 424 search. */ 425int 426rl_history_search_backward (count, ignore) 427 int count, ignore; 428{ 429 if (count == 0) 430 return (0); 431 432 if (rl_last_func != rl_history_search_forward && 433 rl_last_func != rl_history_search_backward) 434 rl_history_search_reinit (); 435 436 if (rl_history_search_len == 0) 437 return (rl_get_previous_history (count, ignore)); 438 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); 439} 440