1 /* search.c - code for non-incremental searching in emacs and vi modes. */
2
3 /* Copyright (C) 1992-2005 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 "rlmbutil.h"
44
45 #include "readline.h"
46 #include "history.h"
47
48 #include "rlprivate.h"
49 #include "xmalloc.h"
50
51 #ifdef abs
52 # undef abs
53 #endif
54 #define abs(x) (((x) >= 0) ? (x) : -(x))
55
56 _rl_search_cxt *_rl_nscxt = 0;
57
58 extern HIST_ENTRY *_rl_saved_line_for_history;
59
60 /* Functions imported from the rest of the library. */
61 extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
62
63 static char *noninc_search_string = (char *) NULL;
64 static int noninc_history_pos;
65
66 static char *prev_line_found = (char *) NULL;
67
68 static int rl_history_search_len;
69 static int rl_history_search_pos;
70 static char *history_search_string;
71 static int history_string_size;
72
73 static void make_history_line_current PARAMS((HIST_ENTRY *));
74 static int noninc_search_from_pos PARAMS((char *, int, int));
75 static int noninc_dosearch PARAMS((char *, int));
76 static int noninc_search PARAMS((int, int));
77 static int rl_history_search_internal PARAMS((int, int));
78 static void rl_history_search_reinit PARAMS((void));
79
80 static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
81 static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
82 static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
83 static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
84
85 /* Make the data from the history entry ENTRY be the contents of the
86 current line. This doesn't do anything with rl_point; the caller
87 must set it. */
88 static void
make_history_line_current(entry)89 make_history_line_current (entry)
90 HIST_ENTRY *entry;
91 {
92 _rl_replace_text (entry->line, 0, rl_end);
93 _rl_fix_point (1);
94 #if defined (VI_MODE)
95 if (rl_editing_mode == vi_mode)
96 /* POSIX.2 says that the `U' command doesn't affect the copy of any
97 command lines to the edit line. We're going to implement that by
98 making the undo list start after the matching line is copied to the
99 current editing buffer. */
100 rl_free_undo_list ();
101 #endif
102
103 if (_rl_saved_line_for_history)
104 _rl_free_history_entry (_rl_saved_line_for_history);
105 _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
106 }
107
108 /* Search the history list for STRING starting at absolute history position
109 POS. If STRING begins with `^', the search must match STRING at the
110 beginning of a history line, otherwise a full substring match is performed
111 for STRING. DIR < 0 means to search backwards through the history list,
112 DIR >= 0 means to search forward. */
113 static int
noninc_search_from_pos(string,pos,dir)114 noninc_search_from_pos (string, pos, dir)
115 char *string;
116 int pos, dir;
117 {
118 int ret, old;
119
120 if (pos < 0)
121 return -1;
122
123 old = where_history ();
124 if (history_set_pos (pos) == 0)
125 return -1;
126
127 RL_SETSTATE(RL_STATE_SEARCH);
128 if (*string == '^')
129 ret = history_search_prefix (string + 1, dir);
130 else
131 ret = history_search (string, dir);
132 RL_UNSETSTATE(RL_STATE_SEARCH);
133
134 if (ret != -1)
135 ret = where_history ();
136
137 history_set_pos (old);
138 return (ret);
139 }
140
141 /* Search for a line in the history containing STRING. If DIR is < 0, the
142 search is backwards through previous entries, else through subsequent
143 entries. Returns 1 if the search was successful, 0 otherwise. */
144 static int
noninc_dosearch(string,dir)145 noninc_dosearch (string, dir)
146 char *string;
147 int dir;
148 {
149 int oldpos, pos;
150 HIST_ENTRY *entry;
151
152 if (string == 0 || *string == '\0' || noninc_history_pos < 0)
153 {
154 rl_ding ();
155 return 0;
156 }
157
158 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
159 if (pos == -1)
160 {
161 /* Search failed, current history position unchanged. */
162 rl_maybe_unsave_line ();
163 rl_clear_message ();
164 rl_point = 0;
165 rl_ding ();
166 return 0;
167 }
168
169 noninc_history_pos = pos;
170
171 oldpos = where_history ();
172 history_set_pos (noninc_history_pos);
173 entry = current_history ();
174 #if defined (VI_MODE)
175 if (rl_editing_mode != vi_mode)
176 #endif
177 history_set_pos (oldpos);
178
179 make_history_line_current (entry);
180
181 rl_point = 0;
182 rl_mark = rl_end;
183
184 rl_clear_message ();
185 return 1;
186 }
187
188 static _rl_search_cxt *
_rl_nsearch_init(dir,pchar)189 _rl_nsearch_init (dir, pchar)
190 int dir, pchar;
191 {
192 _rl_search_cxt *cxt;
193 char *p;
194
195 cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
196 if (dir < 0)
197 cxt->sflags |= SF_REVERSE; /* not strictly needed */
198
199 cxt->direction = dir;
200 cxt->history_pos = cxt->save_line;
201
202 rl_maybe_save_line ();
203
204 /* Clear the undo list, since reading the search string should create its
205 own undo list, and the whole list will end up being freed when we
206 finish reading the search string. */
207 rl_undo_list = 0;
208
209 /* Use the line buffer to read the search string. */
210 rl_line_buffer[0] = 0;
211 rl_end = rl_point = 0;
212
213 p = _rl_make_prompt_for_search (pchar ? pchar : ':');
214 #if defined (PREFER_STDARG)
215 rl_message ("%s", p);
216 #else
217 rl_message ("%s", p, 0);
218 #endif
219 free (p);
220
221 RL_SETSTATE(RL_STATE_NSEARCH);
222
223 _rl_nscxt = cxt;
224
225 return cxt;
226 }
227
228 static int
_rl_nsearch_cleanup(cxt,r)229 _rl_nsearch_cleanup (cxt, r)
230 _rl_search_cxt *cxt;
231 int r;
232 {
233 _rl_scxt_dispose (cxt, 0);
234 _rl_nscxt = 0;
235
236 RL_UNSETSTATE(RL_STATE_NSEARCH);
237
238 return (r != 1);
239 }
240
241 static void
_rl_nsearch_abort(cxt)242 _rl_nsearch_abort (cxt)
243 _rl_search_cxt *cxt;
244 {
245 rl_maybe_unsave_line ();
246 rl_clear_message ();
247 rl_point = cxt->save_point;
248 rl_mark = cxt->save_mark;
249 rl_restore_prompt ();
250
251 RL_UNSETSTATE (RL_STATE_NSEARCH);
252 }
253
254 /* Process just-read character C according to search context CXT. Return -1
255 if the caller should abort the search, 0 if we should break out of the
256 loop, and 1 if we should continue to read characters. */
257 static int
_rl_nsearch_dispatch(cxt,c)258 _rl_nsearch_dispatch (cxt, c)
259 _rl_search_cxt *cxt;
260 int c;
261 {
262 switch (c)
263 {
264 case CTRL('W'):
265 rl_unix_word_rubout (1, c);
266 break;
267
268 case CTRL('U'):
269 rl_unix_line_discard (1, c);
270 break;
271
272 case RETURN:
273 case NEWLINE:
274 return 0;
275
276 case CTRL('H'):
277 case RUBOUT:
278 if (rl_point == 0)
279 {
280 _rl_nsearch_abort (cxt);
281 return -1;
282 }
283 _rl_rubout_char (1, c);
284 break;
285
286 case CTRL('C'):
287 case CTRL('G'):
288 rl_ding ();
289 _rl_nsearch_abort (cxt);
290 return -1;
291
292 default:
293 #if defined (HANDLE_MULTIBYTE)
294 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
295 rl_insert_text (cxt->mb);
296 else
297 #endif
298 _rl_insert_char (1, c);
299 break;
300 }
301
302 (*rl_redisplay_function) ();
303 return 1;
304 }
305
306 /* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return
307 -1 if the search should be aborted, any other value means to clean up
308 using _rl_nsearch_cleanup (). Returns 1 if the search was successful,
309 0 otherwise. */
310 static int
_rl_nsearch_dosearch(cxt)311 _rl_nsearch_dosearch (cxt)
312 _rl_search_cxt *cxt;
313 {
314 rl_mark = cxt->save_mark;
315
316 /* If rl_point == 0, we want to re-use the previous search string and
317 start from the saved history position. If there's no previous search
318 string, punt. */
319 if (rl_point == 0)
320 {
321 if (noninc_search_string == 0)
322 {
323 rl_ding ();
324 rl_restore_prompt ();
325 RL_UNSETSTATE (RL_STATE_NSEARCH);
326 return -1;
327 }
328 }
329 else
330 {
331 /* We want to start the search from the current history position. */
332 noninc_history_pos = cxt->save_line;
333 FREE (noninc_search_string);
334 noninc_search_string = savestring (rl_line_buffer);
335
336 /* If we don't want the subsequent undo list generated by the search
337 matching a history line to include the contents of the search string,
338 we need to clear rl_line_buffer here. For now, we just clear the
339 undo list generated by reading the search string. (If the search
340 fails, the old undo list will be restored by rl_maybe_unsave_line.) */
341 rl_free_undo_list ();
342 }
343
344 rl_restore_prompt ();
345 return (noninc_dosearch (noninc_search_string, cxt->direction));
346 }
347
348 /* Search non-interactively through the history list. DIR < 0 means to
349 search backwards through the history of previous commands; otherwise
350 the search is for commands subsequent to the current position in the
351 history list. PCHAR is the character to use for prompting when reading
352 the search string; if not specified (0), it defaults to `:'. */
353 static int
noninc_search(dir,pchar)354 noninc_search (dir, pchar)
355 int dir;
356 int pchar;
357 {
358 _rl_search_cxt *cxt;
359 int c, r;
360
361 cxt = _rl_nsearch_init (dir, pchar);
362
363 if (RL_ISSTATE (RL_STATE_CALLBACK))
364 return (0);
365
366 /* Read the search string. */
367 r = 0;
368 while (1)
369 {
370 c = _rl_search_getchar (cxt);
371
372 if (c == 0)
373 break;
374
375 r = _rl_nsearch_dispatch (cxt, c);
376 if (r < 0)
377 return 1;
378 else if (r == 0)
379 break;
380 }
381
382 r = _rl_nsearch_dosearch (cxt);
383 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
384 }
385
386 /* Search forward through the history list for a string. If the vi-mode
387 code calls this, KEY will be `?'. */
388 int
rl_noninc_forward_search(count,key)389 rl_noninc_forward_search (count, key)
390 int count, key;
391 {
392 return noninc_search (1, (key == '?') ? '?' : 0);
393 }
394
395 /* Reverse search the history list for a string. If the vi-mode code
396 calls this, KEY will be `/'. */
397 int
rl_noninc_reverse_search(count,key)398 rl_noninc_reverse_search (count, key)
399 int count, key;
400 {
401 return noninc_search (-1, (key == '/') ? '/' : 0);
402 }
403
404 /* Search forward through the history list for the last string searched
405 for. If there is no saved search string, abort. */
406 int
rl_noninc_forward_search_again(count,key)407 rl_noninc_forward_search_again (count, key)
408 int count, key;
409 {
410 int r;
411
412 if (!noninc_search_string)
413 {
414 rl_ding ();
415 return (-1);
416 }
417 r = noninc_dosearch (noninc_search_string, 1);
418 return (r != 1);
419 }
420
421 /* Reverse search in the history list for the last string searched
422 for. If there is no saved search string, abort. */
423 int
rl_noninc_reverse_search_again(count,key)424 rl_noninc_reverse_search_again (count, key)
425 int count, key;
426 {
427 int r;
428
429 if (!noninc_search_string)
430 {
431 rl_ding ();
432 return (-1);
433 }
434 r = noninc_dosearch (noninc_search_string, -1);
435 return (r != 1);
436 }
437
438 #if defined (READLINE_CALLBACKS)
439 int
_rl_nsearch_callback(cxt)440 _rl_nsearch_callback (cxt)
441 _rl_search_cxt *cxt;
442 {
443 int c, r;
444
445 c = _rl_search_getchar (cxt);
446 r = _rl_nsearch_dispatch (cxt, c);
447 if (r != 0)
448 return 1;
449
450 r = _rl_nsearch_dosearch (cxt);
451 return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
452 }
453 #endif
454
455 static int
rl_history_search_internal(count,dir)456 rl_history_search_internal (count, dir)
457 int count, dir;
458 {
459 HIST_ENTRY *temp;
460 int ret, oldpos;
461
462 rl_maybe_save_line ();
463 temp = (HIST_ENTRY *)NULL;
464
465 /* Search COUNT times through the history for a line whose prefix
466 matches history_search_string. When this loop finishes, TEMP,
467 if non-null, is the history line to copy into the line buffer. */
468 while (count)
469 {
470 ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
471 if (ret == -1)
472 break;
473
474 /* Get the history entry we found. */
475 rl_history_search_pos = ret;
476 oldpos = where_history ();
477 history_set_pos (rl_history_search_pos);
478 temp = current_history ();
479 history_set_pos (oldpos);
480
481 /* Don't find multiple instances of the same line. */
482 if (prev_line_found && STREQ (prev_line_found, temp->line))
483 continue;
484 prev_line_found = temp->line;
485 count--;
486 }
487
488 /* If we didn't find anything at all, return. */
489 if (temp == 0)
490 {
491 rl_maybe_unsave_line ();
492 rl_ding ();
493 /* If you don't want the saved history line (last match) to show up
494 in the line buffer after the search fails, change the #if 0 to
495 #if 1 */
496 #if 0
497 if (rl_point > rl_history_search_len)
498 {
499 rl_point = rl_end = rl_history_search_len;
500 rl_line_buffer[rl_end] = '\0';
501 rl_mark = 0;
502 }
503 #else
504 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
505 rl_mark = rl_end;
506 #endif
507 return 1;
508 }
509
510 /* Copy the line we found into the current line buffer. */
511 make_history_line_current (temp);
512
513 rl_point = rl_history_search_len;
514 rl_mark = rl_end;
515
516 return 0;
517 }
518
519 static void
rl_history_search_reinit()520 rl_history_search_reinit ()
521 {
522 rl_history_search_pos = where_history ();
523 rl_history_search_len = rl_point;
524 prev_line_found = (char *)NULL;
525 if (rl_point)
526 {
527 if (rl_history_search_len >= history_string_size - 2)
528 {
529 history_string_size = rl_history_search_len + 2;
530 history_search_string = (char *)xrealloc (history_search_string, history_string_size);
531 }
532 history_search_string[0] = '^';
533 strncpy (history_search_string + 1, rl_line_buffer, rl_point);
534 history_search_string[rl_point + 1] = '\0';
535 }
536 _rl_free_saved_history_line ();
537 }
538
539 /* Search forward in the history for the string of characters
540 from the start of the line to rl_point. This is a non-incremental
541 search. */
542 int
rl_history_search_forward(count,ignore)543 rl_history_search_forward (count, ignore)
544 int count, ignore;
545 {
546 if (count == 0)
547 return (0);
548
549 if (rl_last_func != rl_history_search_forward &&
550 rl_last_func != rl_history_search_backward)
551 rl_history_search_reinit ();
552
553 if (rl_history_search_len == 0)
554 return (rl_get_next_history (count, ignore));
555 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
556 }
557
558 /* Search backward through the history for the string of characters
559 from the start of the line to rl_point. This is a non-incremental
560 search. */
561 int
rl_history_search_backward(count,ignore)562 rl_history_search_backward (count, ignore)
563 int count, ignore;
564 {
565 if (count == 0)
566 return (0);
567
568 if (rl_last_func != rl_history_search_forward &&
569 rl_last_func != rl_history_search_backward)
570 rl_history_search_reinit ();
571
572 if (rl_history_search_len == 0)
573 return (rl_get_previous_history (count, ignore));
574 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
575 }
576