1 /* **************************************************************** */ 2 /* */ 3 /* I-Search and Searching */ 4 /* */ 5 /* **************************************************************** */ 6 7 /* Copyright (C) 1987-2002 Free Software Foundation, Inc. 8 9 This file contains the Readline Library (the Library), a set of 10 routines for providing Emacs style line input to programs that ask 11 for it. 12 13 The Library is free software; you can redistribute it and/or modify 14 it under the terms of the GNU General Public License as published by 15 the Free Software Foundation; either version 2, or (at your option) 16 any later version. 17 18 The Library is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 The GNU General Public License is often shipped with GNU software, and 24 is generally kept in a file called COPYING or LICENSE. If you do not 25 have a copy of the license, write to the Free Software Foundation, 26 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 27 #define READLINE_LIBRARY 28 29 #if defined (HAVE_CONFIG_H) 30 # include <config.h> 31 #endif 32 33 #include <sys/types.h> 34 35 #include <stdio.h> 36 37 #if defined (HAVE_UNISTD_H) 38 # include <unistd.h> 39 #endif 40 41 #if defined (HAVE_STDLIB_H) 42 # include <stdlib.h> 43 #else 44 # include "ansi_stdlib.h" 45 #endif 46 47 #include "rldefs.h" 48 #include "rlmbutil.h" 49 50 #include "readline.h" 51 #include "history.h" 52 53 #include "rlprivate.h" 54 #include "xmalloc.h" 55 56 /* Variables exported to other files in the readline library. */ 57 char *_rl_isearch_terminators = (char *)NULL; 58 59 /* Variables imported from other files in the readline library. */ 60 extern HIST_ENTRY *_rl_saved_line_for_history; 61 62 /* Forward declarations */ 63 static int rl_search_history PARAMS((int, int)); 64 65 /* Last line found by the current incremental search, so we don't `find' 66 identical lines many times in a row. */ 67 static char *prev_line_found; 68 69 /* Last search string and its length. */ 70 static char *last_isearch_string; 71 static int last_isearch_string_len; 72 73 static char *default_isearch_terminators = "\033\012"; 74 75 /* Search backwards through the history looking for a string which is typed 76 interactively. Start with the current line. */ 77 int 78 rl_reverse_search_history (sign, key) 79 int sign, key; 80 { 81 return (rl_search_history (-sign, key)); 82 } 83 84 /* Search forwards through the history looking for a string which is typed 85 interactively. Start with the current line. */ 86 int 87 rl_forward_search_history (sign, key) 88 int sign, key; 89 { 90 return (rl_search_history (sign, key)); 91 } 92 93 /* Display the current state of the search in the echo-area. 94 SEARCH_STRING contains the string that is being searched for, 95 DIRECTION is zero for forward, or 1 for reverse, 96 WHERE is the history list number of the current line. If it is 97 -1, then this line is the starting one. */ 98 static void 99 rl_display_search (search_string, reverse_p, where) 100 char *search_string; 101 int reverse_p, where; 102 { 103 char *message; 104 int msglen, searchlen, mlen; 105 106 searchlen = (search_string && *search_string) ? strlen (search_string) : 0; 107 108 mlen = searchlen + 33; 109 message = (char *)xmalloc (mlen); 110 msglen = 0; 111 112 #if defined (NOTDEF) 113 if (where != -1) 114 { 115 snprintf (message, mlen, "[%d]", where + history_base); 116 msglen = strlen (message); 117 } 118 #endif /* NOTDEF */ 119 120 message[msglen++] = '('; 121 message[msglen] = '\0'; 122 123 if (reverse_p) 124 { 125 strlcat (message, "reverse-", mlen); 126 } 127 128 strlcat (message, "i-search)`", mlen); 129 130 if (search_string) 131 { 132 strlcat (message, search_string, mlen); 133 } 134 135 strlcat (message, "': ", mlen); 136 137 rl_message ("%s", message); 138 free (message); 139 (*rl_redisplay_function) (); 140 } 141 142 /* Search through the history looking for an interactively typed string. 143 This is analogous to i-search. We start the search in the current line. 144 DIRECTION is which direction to search; >= 0 means forward, < 0 means 145 backwards. */ 146 static int 147 rl_search_history (direction, invoking_key) 148 int direction, invoking_key; 149 { 150 /* The string that the user types in to search for. */ 151 char *search_string; 152 153 /* The current length of SEARCH_STRING. */ 154 int search_string_index; 155 156 /* The amount of space that SEARCH_STRING has allocated to it. */ 157 int search_string_size; 158 159 /* The list of lines to search through. */ 160 char **lines, *allocated_line; 161 162 /* The length of LINES. */ 163 int hlen; 164 165 /* Where we get LINES from. */ 166 HIST_ENTRY **hlist; 167 168 register int i; 169 int orig_point, orig_mark, orig_line, last_found_line; 170 int c, found, failed, sline_len; 171 int n, wstart, wlen; 172 #if defined (HANDLE_MULTIBYTE) 173 char mb[MB_LEN_MAX]; 174 #endif 175 176 /* The line currently being searched. */ 177 char *sline; 178 179 /* Offset in that line. */ 180 int line_index; 181 182 /* Non-zero if we are doing a reverse search. */ 183 int reverse; 184 185 /* The list of characters which terminate the search, but are not 186 subsequently executed. If the variable isearch-terminators has 187 been set, we use that value, otherwise we use ESC and C-J. */ 188 char *isearch_terminators; 189 190 RL_SETSTATE(RL_STATE_ISEARCH); 191 orig_point = rl_point; 192 orig_mark = rl_mark; 193 last_found_line = orig_line = where_history (); 194 reverse = direction < 0; 195 hlist = history_list (); 196 allocated_line = (char *)NULL; 197 198 isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators 199 : default_isearch_terminators; 200 201 /* Create an arrary of pointers to the lines that we want to search. */ 202 rl_maybe_replace_line (); 203 i = 0; 204 if (hlist) 205 for (i = 0; hlist[i]; i++); 206 207 /* Allocate space for this many lines, +1 for the current input line, 208 and remember those lines. */ 209 lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); 210 for (i = 0; i < hlen; i++) 211 lines[i] = hlist[i]->line; 212 213 if (_rl_saved_line_for_history) 214 lines[i] = _rl_saved_line_for_history->line; 215 else 216 { 217 /* Keep track of this so we can free it. */ 218 allocated_line = strdup(rl_line_buffer); 219 if (allocated_line == NULL) 220 memory_error_and_abort("strdup"); 221 lines[i] = allocated_line; 222 } 223 224 hlen++; 225 226 /* The line where we start the search. */ 227 i = orig_line; 228 229 rl_save_prompt (); 230 231 /* Initialize search parameters. */ 232 search_string = (char *)xmalloc (search_string_size = 128); 233 *search_string = '\0'; 234 search_string_index = 0; 235 prev_line_found = (char *)0; /* XXX */ 236 237 /* Normalize DIRECTION into 1 or -1. */ 238 direction = (direction >= 0) ? 1 : -1; 239 240 rl_display_search (search_string, reverse, -1); 241 242 sline = rl_line_buffer; 243 sline_len = strlen (sline); 244 line_index = rl_point; 245 246 found = failed = 0; 247 for (;;) 248 { 249 rl_command_func_t *f = (rl_command_func_t *)NULL; 250 251 /* Read a key and decide how to proceed. */ 252 RL_SETSTATE(RL_STATE_MOREINPUT); 253 c = rl_read_key (); 254 RL_UNSETSTATE(RL_STATE_MOREINPUT); 255 256 #if defined (HANDLE_MULTIBYTE) 257 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 258 c = _rl_read_mbstring (c, mb, MB_LEN_MAX); 259 #endif 260 261 /* Translate the keys we do something with to opcodes. */ 262 if (c >= 0 && _rl_keymap[c].type == ISFUNC) 263 { 264 f = _rl_keymap[c].function; 265 266 if (f == rl_reverse_search_history) 267 c = reverse ? -1 : -2; 268 else if (f == rl_forward_search_history) 269 c = !reverse ? -1 : -2; 270 else if (f == rl_rubout) 271 c = -3; 272 else if (c == CTRL ('G')) 273 c = -4; 274 else if (c == CTRL ('W')) /* XXX */ 275 c = -5; 276 else if (c == CTRL ('Y')) /* XXX */ 277 c = -6; 278 } 279 280 /* The characters in isearch_terminators (set from the user-settable 281 variable isearch-terminators) are used to terminate the search but 282 not subsequently execute the character as a command. The default 283 value is "\033\012" (ESC and C-J). */ 284 if (strchr (isearch_terminators, c)) 285 { 286 /* ESC still terminates the search, but if there is pending 287 input or if input arrives within 0.1 seconds (on systems 288 with select(2)) it is used as a prefix character 289 with rl_execute_next. WATCH OUT FOR THIS! This is intended 290 to allow the arrow keys to be used like ^F and ^B are used 291 to terminate the search and execute the movement command. 292 XXX - since _rl_input_available depends on the application- 293 settable keyboard timeout value, this could alternatively 294 use _rl_input_queued(100000) */ 295 if (c == ESC && _rl_input_available ()) 296 rl_execute_next (ESC); 297 break; 298 } 299 300 #define ENDSRCH_CHAR(c) \ 301 ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) 302 303 #if defined (HANDLE_MULTIBYTE) 304 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 305 { 306 if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c)) 307 { 308 /* This sets rl_pending_input to c; it will be picked up the next 309 time rl_read_key is called. */ 310 rl_execute_next (c); 311 break; 312 } 313 } 314 else 315 #endif 316 if (c >= 0 && ENDSRCH_CHAR (c)) 317 { 318 /* This sets rl_pending_input to c; it will be picked up the next 319 time rl_read_key is called. */ 320 rl_execute_next (c); 321 break; 322 } 323 324 switch (c) 325 { 326 case -1: 327 if (search_string_index == 0) 328 { 329 if (last_isearch_string) 330 { 331 search_string_size = 64 + last_isearch_string_len; 332 search_string = (char *)xrealloc (search_string, search_string_size); 333 strlcpy (search_string, last_isearch_string, search_string_size); 334 search_string_index = last_isearch_string_len; 335 rl_display_search (search_string, reverse, -1); 336 break; 337 } 338 continue; 339 } 340 else if (reverse) 341 --line_index; 342 else if (line_index != sline_len) 343 ++line_index; 344 else 345 rl_ding (); 346 break; 347 348 /* switch directions */ 349 case -2: 350 direction = -direction; 351 reverse = direction < 0; 352 break; 353 354 /* delete character from search string. */ 355 case -3: /* C-H, DEL */ 356 /* This is tricky. To do this right, we need to keep a 357 stack of search positions for the current search, with 358 sentinels marking the beginning and end. But this will 359 do until we have a real isearch-undo. */ 360 if (search_string_index == 0) 361 rl_ding (); 362 else 363 search_string[--search_string_index] = '\0'; 364 365 break; 366 367 case -4: /* C-G */ 368 rl_replace_line (lines[orig_line], 0); 369 rl_point = orig_point; 370 rl_mark = orig_mark; 371 rl_restore_prompt(); 372 rl_clear_message (); 373 if (allocated_line) 374 free (allocated_line); 375 free (lines); 376 RL_UNSETSTATE(RL_STATE_ISEARCH); 377 return 0; 378 379 case -5: /* C-W */ 380 /* skip over portion of line we already matched */ 381 wstart = rl_point + search_string_index; 382 if (wstart >= rl_end) 383 { 384 rl_ding (); 385 break; 386 } 387 388 /* if not in a word, move to one. */ 389 if (rl_alphabetic(rl_line_buffer[wstart]) == 0) 390 { 391 rl_ding (); 392 break; 393 } 394 n = wstart; 395 while (n < rl_end && rl_alphabetic(rl_line_buffer[n])) 396 n++; 397 wlen = n - wstart + 1; 398 if (search_string_index + wlen + 1 >= search_string_size) 399 { 400 search_string_size += wlen + 1; 401 search_string = (char *)xrealloc (search_string, search_string_size); 402 } 403 for (; wstart < n; wstart++) 404 search_string[search_string_index++] = rl_line_buffer[wstart]; 405 search_string[search_string_index] = '\0'; 406 break; 407 408 case -6: /* C-Y */ 409 /* skip over portion of line we already matched */ 410 wstart = rl_point + search_string_index; 411 if (wstart >= rl_end) 412 { 413 rl_ding (); 414 break; 415 } 416 n = rl_end - wstart + 1; 417 if (search_string_index + n + 1 >= search_string_size) 418 { 419 search_string_size += n + 1; 420 search_string = (char *)xrealloc (search_string, search_string_size); 421 } 422 for (n = wstart; n < rl_end; n++) 423 search_string[search_string_index++] = rl_line_buffer[n]; 424 search_string[search_string_index] = '\0'; 425 break; 426 427 default: 428 /* Add character to search string and continue search. */ 429 if (search_string_index + 2 >= search_string_size) 430 { 431 search_string_size += 128; 432 search_string = (char *)xrealloc (search_string, search_string_size); 433 } 434 #if defined (HANDLE_MULTIBYTE) 435 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 436 { 437 int j, l; 438 for (j = 0, l = strlen (mb); j < l; ) 439 search_string[search_string_index++] = mb[j++]; 440 } 441 else 442 #endif 443 search_string[search_string_index++] = c; 444 search_string[search_string_index] = '\0'; 445 break; 446 } 447 448 for (found = failed = 0;;) 449 { 450 int limit = sline_len - search_string_index + 1; 451 452 /* Search the current line. */ 453 while (reverse ? (line_index >= 0) : (line_index < limit)) 454 { 455 if (STREQN (search_string, sline + line_index, search_string_index)) 456 { 457 found++; 458 break; 459 } 460 else 461 line_index += direction; 462 } 463 if (found) 464 break; 465 466 /* Move to the next line, but skip new copies of the line 467 we just found and lines shorter than the string we're 468 searching for. */ 469 do 470 { 471 /* Move to the next line. */ 472 i += direction; 473 474 /* At limit for direction? */ 475 if (reverse ? (i < 0) : (i == hlen)) 476 { 477 failed++; 478 break; 479 } 480 481 /* We will need these later. */ 482 sline = lines[i]; 483 sline_len = strlen (sline); 484 } 485 while ((prev_line_found && STREQ (prev_line_found, lines[i])) || 486 (search_string_index > sline_len)); 487 488 if (failed) 489 break; 490 491 /* Now set up the line for searching... */ 492 line_index = reverse ? sline_len - search_string_index : 0; 493 } 494 495 if (failed) 496 { 497 /* We cannot find the search string. Ding the bell. */ 498 rl_ding (); 499 i = last_found_line; 500 continue; /* XXX - was break */ 501 } 502 503 /* We have found the search string. Just display it. But don't 504 actually move there in the history list until the user accepts 505 the location. */ 506 if (found) 507 { 508 prev_line_found = lines[i]; 509 rl_replace_line (lines[i], 0); 510 rl_point = line_index; 511 last_found_line = i; 512 rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); 513 } 514 } 515 516 /* The searching is over. The user may have found the string that she 517 was looking for, or else she may have exited a failing search. If 518 LINE_INDEX is -1, then that shows that the string searched for was 519 not found. We use this to determine where to place rl_point. */ 520 521 /* First put back the original state. */ 522 strlcpy (rl_line_buffer, lines[orig_line], rl_line_buffer_len); 523 524 rl_restore_prompt (); 525 526 /* Save the search string for possible later use. */ 527 FREE (last_isearch_string); 528 last_isearch_string = search_string; 529 last_isearch_string_len = search_string_index; 530 531 if (last_found_line < orig_line) 532 rl_get_previous_history (orig_line - last_found_line, 0); 533 else 534 rl_get_next_history (last_found_line - orig_line, 0); 535 536 /* If the string was not found, put point at the end of the last matching 537 line. If last_found_line == orig_line, we didn't find any matching 538 history lines at all, so put point back in its original position. */ 539 if (line_index < 0) 540 { 541 if (last_found_line == orig_line) 542 line_index = orig_point; 543 else 544 line_index = strlen (rl_line_buffer); 545 rl_mark = orig_mark; 546 } 547 548 rl_point = line_index; 549 /* Don't worry about where to put the mark here; rl_get_previous_history 550 and rl_get_next_history take care of it. */ 551 552 rl_clear_message (); 553 554 FREE (allocated_line); 555 free (lines); 556 557 RL_UNSETSTATE(RL_STATE_ISEARCH); 558 559 return 0; 560 } 561