Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / lib / readline / search.c
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 "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 extern HIST_ENTRY *_rl_saved_line_for_history;
57
58 /* Functions imported from the rest of the library. */
59 extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
60
61 static char *noninc_search_string = (char *) NULL;
62 static int noninc_history_pos;
63
64 static char *prev_line_found = (char *) NULL;
65
66 static int rl_history_search_len;
67 static int rl_history_search_pos;
68 static char *history_search_string;
69 static int history_string_size;
70
71 static void make_history_line_current PARAMS((HIST_ENTRY *));
72 static int noninc_search_from_pos PARAMS((char *, int, int));
73 static void noninc_dosearch PARAMS((char *, int));
74 static void noninc_search PARAMS((int, int));
75 static int rl_history_search_internal PARAMS((int, int));
76 static void rl_history_search_reinit PARAMS((void));
77
78 /* Make the data from the history entry ENTRY be the contents of the
79    current line.  This doesn't do anything with rl_point; the caller
80    must set it. */
81 static void
82 make_history_line_current (entry)
83      HIST_ENTRY *entry;
84 {
85   rl_replace_line (entry->line, 0);
86   rl_undo_list = (UNDO_LIST *)entry->data;
87
88   if (_rl_saved_line_for_history)
89     _rl_free_history_entry (_rl_saved_line_for_history);
90   _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
91 }
92
93 /* Search the history list for STRING starting at absolute history position
94    POS.  If STRING begins with `^', the search must match STRING at the
95    beginning of a history line, otherwise a full substring match is performed
96    for STRING.  DIR < 0 means to search backwards through the history list,
97    DIR >= 0 means to search forward. */
98 static int
99 noninc_search_from_pos (string, pos, dir)
100      char *string;
101      int pos, dir;
102 {
103   int ret, old;
104
105   if (pos < 0)
106     return -1;
107
108   old = where_history ();
109   if (history_set_pos (pos) == 0)
110     return -1;
111
112   RL_SETSTATE(RL_STATE_SEARCH);
113   if (*string == '^')
114     ret = history_search_prefix (string + 1, dir);
115   else
116     ret = history_search (string, dir);
117   RL_UNSETSTATE(RL_STATE_SEARCH);
118
119   if (ret != -1)
120     ret = where_history ();
121
122   history_set_pos (old);
123   return (ret);
124 }
125
126 /* Search for a line in the history containing STRING.  If DIR is < 0, the
127    search is backwards through previous entries, else through subsequent
128    entries. */
129 static void
130 noninc_dosearch (string, dir)
131      char *string;
132      int dir;
133 {
134   int oldpos, pos;
135   HIST_ENTRY *entry;
136
137   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
138     {
139       rl_ding ();
140       return;
141     }
142
143   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
144   if (pos == -1)
145     {
146       /* Search failed, current history position unchanged. */
147       rl_maybe_unsave_line ();
148       rl_clear_message ();
149       rl_point = 0;
150       rl_ding ();
151       return;
152     }
153
154   noninc_history_pos = pos;
155
156   oldpos = where_history ();
157   history_set_pos (noninc_history_pos);
158   entry = current_history ();
159 #if defined (VI_MODE)
160   if (rl_editing_mode != vi_mode)
161 #endif
162   history_set_pos (oldpos);
163
164   make_history_line_current (entry);
165
166   rl_point = 0;
167   rl_mark = rl_end;
168
169   rl_clear_message ();
170 }
171
172 /* Search non-interactively through the history list.  DIR < 0 means to
173    search backwards through the history of previous commands; otherwise
174    the search is for commands subsequent to the current position in the
175    history list.  PCHAR is the character to use for prompting when reading
176    the search string; if not specified (0), it defaults to `:'. */
177 static void
178 noninc_search (dir, pchar)
179      int dir;
180      int pchar;
181 {
182   int saved_point, saved_mark, c;
183   char *p;
184 #if defined (HANDLE_MULTIBYTE)
185   char mb[MB_LEN_MAX];
186 #endif
187
188   rl_maybe_save_line ();
189   saved_point = rl_point;
190   saved_mark = rl_mark;
191
192   /* Use the line buffer to read the search string. */
193   rl_line_buffer[0] = 0;
194   rl_end = rl_point = 0;
195
196   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
197   rl_message (p, 0, 0);
198   free (p);
199
200 #define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return
201
202   RL_SETSTATE(RL_STATE_NSEARCH);
203   /* Read the search string. */
204   while (1)
205     {
206       RL_SETSTATE(RL_STATE_MOREINPUT);
207       c = rl_read_key ();
208       RL_UNSETSTATE(RL_STATE_MOREINPUT);
209
210 #if defined (HANDLE_MULTIBYTE)
211       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
212         c = _rl_read_mbstring (c, mb, MB_LEN_MAX);
213 #endif
214
215       if (c == 0)
216         break;
217
218       switch (c)
219         {
220         case CTRL('H'):
221         case RUBOUT:
222           if (rl_point == 0)
223             {
224               rl_maybe_unsave_line ();
225               rl_clear_message ();
226               rl_point = saved_point;
227               rl_mark = saved_mark;
228               SEARCH_RETURN;
229             }
230           _rl_rubout_char (1, c);
231           break;
232
233         case CTRL('W'):
234           rl_unix_word_rubout (1, c);
235           break;
236
237         case CTRL('U'):
238           rl_unix_line_discard (1, c);
239           break;
240
241         case RETURN:
242         case NEWLINE:
243           goto dosearch;
244           /* NOTREACHED */
245           break;
246
247         case CTRL('C'):
248         case CTRL('G'):
249           rl_maybe_unsave_line ();
250           rl_clear_message ();
251           rl_point = saved_point;
252           rl_mark = saved_mark;
253           rl_ding ();
254           SEARCH_RETURN;
255
256         default:
257 #if defined (HANDLE_MULTIBYTE)
258           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
259             rl_insert_text (mb);
260           else
261 #endif
262             _rl_insert_char (1, c);
263           break;
264         }
265       (*rl_redisplay_function) ();
266     }
267
268  dosearch:
269   rl_mark = saved_mark;
270
271   /* If rl_point == 0, we want to re-use the previous search string and
272      start from the saved history position.  If there's no previous search
273      string, punt. */
274   if (rl_point == 0)
275     {
276       if (!noninc_search_string)
277         {
278           rl_ding ();
279           SEARCH_RETURN;
280         }
281     }
282   else
283     {
284       /* We want to start the search from the current history position. */
285       noninc_history_pos = where_history ();
286       FREE (noninc_search_string);
287       noninc_search_string = savestring (rl_line_buffer);
288     }
289
290   rl_restore_prompt ();
291   noninc_dosearch (noninc_search_string, dir);
292   RL_UNSETSTATE(RL_STATE_NSEARCH);
293 }
294
295 /* Search forward through the history list for a string.  If the vi-mode
296    code calls this, KEY will be `?'. */
297 int
298 rl_noninc_forward_search (count, key)
299      int count, key;
300 {
301   noninc_search (1, (key == '?') ? '?' : 0);
302   return 0;
303 }
304
305 /* Reverse search the history list for a string.  If the vi-mode code
306    calls this, KEY will be `/'. */
307 int
308 rl_noninc_reverse_search (count, key)
309      int count, key;
310 {
311   noninc_search (-1, (key == '/') ? '/' : 0);
312   return 0;
313 }
314
315 /* Search forward through the history list for the last string searched
316    for.  If there is no saved search string, abort. */
317 int
318 rl_noninc_forward_search_again (count, key)
319      int count, key;
320 {
321   if (!noninc_search_string)
322     {
323       rl_ding ();
324       return (-1);
325     }
326   noninc_dosearch (noninc_search_string, 1);
327   return 0;
328 }
329
330 /* Reverse search in the history list for the last string searched
331    for.  If there is no saved search string, abort. */
332 int
333 rl_noninc_reverse_search_again (count, key)
334      int count, key;
335 {
336   if (!noninc_search_string)
337     {
338       rl_ding ();
339       return (-1);
340     }
341   noninc_dosearch (noninc_search_string, -1);
342   return 0;
343 }
344
345 static int
346 rl_history_search_internal (count, dir)
347      int count, dir;
348 {
349   HIST_ENTRY *temp;
350   int ret, oldpos;
351
352   rl_maybe_save_line ();
353   temp = (HIST_ENTRY *)NULL;
354
355   /* Search COUNT times through the history for a line whose prefix
356      matches history_search_string.  When this loop finishes, TEMP,
357      if non-null, is the history line to copy into the line buffer. */
358   while (count)
359     {
360       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
361       if (ret == -1)
362         break;
363
364       /* Get the history entry we found. */
365       rl_history_search_pos = ret;
366       oldpos = where_history ();
367       history_set_pos (rl_history_search_pos);
368       temp = current_history ();
369       history_set_pos (oldpos);
370
371       /* Don't find multiple instances of the same line. */
372       if (prev_line_found && STREQ (prev_line_found, temp->line))
373         continue;
374       prev_line_found = temp->line;
375       count--;
376     }
377
378   /* If we didn't find anything at all, return. */
379   if (temp == 0)
380     {
381       rl_maybe_unsave_line ();
382       rl_ding ();
383       /* If you don't want the saved history line (last match) to show up
384          in the line buffer after the search fails, change the #if 0 to
385          #if 1 */
386 #if 0
387       if (rl_point > rl_history_search_len)
388         {
389           rl_point = rl_end = rl_history_search_len;
390           rl_line_buffer[rl_end] = '\0';
391           rl_mark = 0;
392         }
393 #else
394       rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
395       rl_mark = rl_end;
396 #endif
397       return 1;
398     }
399
400   /* Copy the line we found into the current line buffer. */
401   make_history_line_current (temp);
402
403   rl_point = rl_history_search_len;
404   rl_mark = rl_end;
405
406   return 0;
407 }
408
409 static void
410 rl_history_search_reinit ()
411 {
412   rl_history_search_pos = where_history ();
413   rl_history_search_len = rl_point;
414   prev_line_found = (char *)NULL;
415   if (rl_point)
416     {
417       if (rl_history_search_len >= history_string_size - 2)
418         {
419           history_string_size = rl_history_search_len + 2;
420           history_search_string = (char *)xrealloc (history_search_string, history_string_size);
421         }
422       history_search_string[0] = '^';
423       strncpy (history_search_string + 1, rl_line_buffer, rl_point);
424       history_search_string[rl_point + 1] = '\0';
425     }
426   _rl_free_saved_history_line ();
427 }
428
429 /* Search forward in the history for the string of characters
430    from the start of the line to rl_point.  This is a non-incremental
431    search. */
432 int
433 rl_history_search_forward (count, ignore)
434      int count, ignore;
435 {
436   if (count == 0)
437     return (0);
438
439   if (rl_last_func != rl_history_search_forward &&
440       rl_last_func != rl_history_search_backward)
441     rl_history_search_reinit ();
442
443   if (rl_history_search_len == 0)
444     return (rl_get_next_history (count, ignore));
445   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
446 }
447
448 /* Search backward through the history for the string of characters
449    from the start of the line to rl_point.  This is a non-incremental
450    search. */
451 int
452 rl_history_search_backward (count, ignore)
453      int count, ignore;
454 {
455   if (count == 0)
456     return (0);
457
458   if (rl_last_func != rl_history_search_forward &&
459       rl_last_func != rl_history_search_backward)
460     rl_history_search_reinit ();
461
462   if (rl_history_search_len == 0)
463     return (rl_get_previous_history (count, ignore));
464   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
465 }