]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/libreadline/search.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / libreadline / search.c
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
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
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
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 *
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   rl_message ("%s", p, 0);
215   free (p);
216
217   RL_SETSTATE(RL_STATE_NSEARCH);
218
219   _rl_nscxt = cxt;
220
221   return cxt;
222 }
223
224 static int
225 _rl_nsearch_cleanup (cxt, r)
226      _rl_search_cxt *cxt;
227      int r;
228 {
229   _rl_scxt_dispose (cxt, 0);
230   _rl_nscxt = 0;
231
232   RL_UNSETSTATE(RL_STATE_NSEARCH);
233
234   return (r != 1);
235 }
236
237 static void
238 _rl_nsearch_abort (cxt)
239      _rl_search_cxt *cxt;
240 {
241   rl_maybe_unsave_line ();
242   rl_clear_message ();
243   rl_point = cxt->save_point;
244   rl_mark = cxt->save_mark;
245   rl_restore_prompt ();
246
247   RL_UNSETSTATE (RL_STATE_NSEARCH);
248 }
249
250 /* Process just-read character C according to search context CXT.  Return -1
251    if the caller should abort the search, 0 if we should break out of the
252    loop, and 1 if we should continue to read characters. */
253 static int
254 _rl_nsearch_dispatch (cxt, c)
255      _rl_search_cxt *cxt;
256      int c;
257 {
258   switch (c)
259     {
260     case CTRL('W'):
261       rl_unix_word_rubout (1, c);
262       break;
263
264     case CTRL('U'):
265       rl_unix_line_discard (1, c);
266       break;
267
268     case RETURN:
269     case NEWLINE:
270       return 0;
271
272     case CTRL('H'):
273     case RUBOUT:
274       if (rl_point == 0)
275         {
276           _rl_nsearch_abort (cxt);
277           return -1;
278         }
279       _rl_rubout_char (1, c);
280       break;
281
282     case CTRL('C'):
283     case CTRL('G'):
284       rl_ding ();
285       _rl_nsearch_abort (cxt);
286       return -1;
287
288     default:
289 #if defined (HANDLE_MULTIBYTE)
290       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
291         rl_insert_text (cxt->mb);
292       else
293 #endif
294         _rl_insert_char (1, c);
295       break;
296     }
297
298   (*rl_redisplay_function) ();
299   return 1;
300 }
301
302 /* Perform one search according to CXT, using NONINC_SEARCH_STRING.  Return
303    -1 if the search should be aborted, any other value means to clean up
304    using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
305    0 otherwise. */
306 static int
307 _rl_nsearch_dosearch (cxt)
308      _rl_search_cxt *cxt;
309 {
310   rl_mark = cxt->save_mark;
311
312   /* If rl_point == 0, we want to re-use the previous search string and
313      start from the saved history position.  If there's no previous search
314      string, punt. */
315   if (rl_point == 0)
316     {
317       if (noninc_search_string == 0)
318         {
319           rl_ding ();
320           rl_restore_prompt ();
321           RL_UNSETSTATE (RL_STATE_NSEARCH);
322           return -1;
323         }
324     }
325   else
326     {
327       /* We want to start the search from the current history position. */
328       noninc_history_pos = cxt->save_line;
329       FREE (noninc_search_string);
330       noninc_search_string = savestring (rl_line_buffer);
331
332       /* If we don't want the subsequent undo list generated by the search
333          matching a history line to include the contents of the search string,
334          we need to clear rl_line_buffer here.  For now, we just clear the
335          undo list generated by reading the search string.  (If the search
336          fails, the old undo list will be restored by rl_maybe_unsave_line.) */
337       rl_free_undo_list ();
338     }
339
340   rl_restore_prompt ();
341   return (noninc_dosearch (noninc_search_string, cxt->direction));
342 }
343
344 /* Search non-interactively through the history list.  DIR < 0 means to
345    search backwards through the history of previous commands; otherwise
346    the search is for commands subsequent to the current position in the
347    history list.  PCHAR is the character to use for prompting when reading
348    the search string; if not specified (0), it defaults to `:'. */
349 static int
350 noninc_search (dir, pchar)
351      int dir;
352      int pchar;
353 {
354   _rl_search_cxt *cxt;
355   int c, r;
356
357   cxt = _rl_nsearch_init (dir, pchar);
358
359   if (RL_ISSTATE (RL_STATE_CALLBACK))
360     return (0);
361
362   /* Read the search string. */
363   r = 0;
364   while (1)
365     {
366       c = _rl_search_getchar (cxt);
367
368       if (c == 0)
369         break;
370
371       r = _rl_nsearch_dispatch (cxt, c);
372       if (r < 0)
373         return 1;
374       else if (r == 0)
375         break;        
376     }
377
378   r = _rl_nsearch_dosearch (cxt);
379   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
380 }
381
382 /* Search forward through the history list for a string.  If the vi-mode
383    code calls this, KEY will be `?'. */
384 int
385 rl_noninc_forward_search (count, key)
386      int count, key;
387 {
388   return noninc_search (1, (key == '?') ? '?' : 0);
389 }
390
391 /* Reverse search the history list for a string.  If the vi-mode code
392    calls this, KEY will be `/'. */
393 int
394 rl_noninc_reverse_search (count, key)
395      int count, key;
396 {
397   return noninc_search (-1, (key == '/') ? '/' : 0);
398 }
399
400 /* Search forward through the history list for the last string searched
401    for.  If there is no saved search string, abort. */
402 int
403 rl_noninc_forward_search_again (count, key)
404      int count, key;
405 {
406   int r;
407
408   if (!noninc_search_string)
409     {
410       rl_ding ();
411       return (-1);
412     }
413   r = noninc_dosearch (noninc_search_string, 1);
414   return (r != 1);
415 }
416
417 /* Reverse search in the history list for the last string searched
418    for.  If there is no saved search string, abort. */
419 int
420 rl_noninc_reverse_search_again (count, key)
421      int count, key;
422 {
423   int r;
424
425   if (!noninc_search_string)
426     {
427       rl_ding ();
428       return (-1);
429     }
430   r = noninc_dosearch (noninc_search_string, -1);
431   return (r != 1);
432 }
433
434 #if defined (READLINE_CALLBACKS)
435 int
436 _rl_nsearch_callback (cxt)
437      _rl_search_cxt *cxt;
438 {
439   int c, r;
440
441   c = _rl_search_getchar (cxt);
442   r = _rl_nsearch_dispatch (cxt, c);
443   if (r != 0)
444     return 1;
445
446   r = _rl_nsearch_dosearch (cxt);
447   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
448 }
449 #endif
450   
451 static int
452 rl_history_search_internal (count, dir)
453      int count, dir;
454 {
455   HIST_ENTRY *temp;
456   int ret, oldpos;
457
458   rl_maybe_save_line ();
459   temp = (HIST_ENTRY *)NULL;
460
461   /* Search COUNT times through the history for a line whose prefix
462      matches history_search_string.  When this loop finishes, TEMP,
463      if non-null, is the history line to copy into the line buffer. */
464   while (count)
465     {
466       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
467       if (ret == -1)
468         break;
469
470       /* Get the history entry we found. */
471       rl_history_search_pos = ret;
472       oldpos = where_history ();
473       history_set_pos (rl_history_search_pos);
474       temp = current_history ();
475       history_set_pos (oldpos);
476
477       /* Don't find multiple instances of the same line. */
478       if (prev_line_found && STREQ (prev_line_found, temp->line))
479         continue;
480       prev_line_found = temp->line;
481       count--;
482     }
483
484   /* If we didn't find anything at all, return. */
485   if (temp == 0)
486     {
487       rl_maybe_unsave_line ();
488       rl_ding ();
489       /* If you don't want the saved history line (last match) to show up
490          in the line buffer after the search fails, change the #if 0 to
491          #if 1 */
492 #if 0
493       if (rl_point > rl_history_search_len)
494         {
495           rl_point = rl_end = rl_history_search_len;
496           rl_line_buffer[rl_end] = '\0';
497           rl_mark = 0;
498         }
499 #else
500       rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
501       rl_mark = rl_end;
502 #endif
503       return 1;
504     }
505
506   /* Copy the line we found into the current line buffer. */
507   make_history_line_current (temp);
508
509   rl_point = rl_history_search_len;
510   rl_mark = rl_end;
511
512   return 0;
513 }
514
515 static void
516 rl_history_search_reinit ()
517 {
518   rl_history_search_pos = where_history ();
519   rl_history_search_len = rl_point;
520   prev_line_found = (char *)NULL;
521   if (rl_point)
522     {
523       if (rl_history_search_len >= history_string_size - 2)
524         {
525           history_string_size = rl_history_search_len + 2;
526           history_search_string = (char *)xrealloc (history_search_string, history_string_size);
527         }
528       history_search_string[0] = '^';
529       strncpy (history_search_string + 1, rl_line_buffer, rl_point);
530       history_search_string[rl_point + 1] = '\0';
531     }
532   _rl_free_saved_history_line ();
533 }
534
535 /* Search forward in the history for the string of characters
536    from the start of the line to rl_point.  This is a non-incremental
537    search. */
538 int
539 rl_history_search_forward (count, ignore)
540      int count, ignore;
541 {
542   if (count == 0)
543     return (0);
544
545   if (rl_last_func != rl_history_search_forward &&
546       rl_last_func != rl_history_search_backward)
547     rl_history_search_reinit ();
548
549   if (rl_history_search_len == 0)
550     return (rl_get_next_history (count, ignore));
551   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
552 }
553
554 /* Search backward through the history for the string of characters
555    from the start of the line to rl_point.  This is a non-incremental
556    search. */
557 int
558 rl_history_search_backward (count, ignore)
559      int count, ignore;
560 {
561   if (count == 0)
562     return (0);
563
564   if (rl_last_func != rl_history_search_forward &&
565       rl_last_func != rl_history_search_backward)
566     rl_history_search_reinit ();
567
568   if (rl_history_search_len == 0)
569     return (rl_get_previous_history (count, ignore));
570   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
571 }