Imported from ../bash-2.05.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 "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
54 extern HIST_ENTRY *_rl_saved_line_for_history;
55
56 /* Functions imported from the rest of the library. */
57 extern int _rl_free_history_entry __P((HIST_ENTRY *));
58
59 static char *noninc_search_string = (char *) NULL;
60 static int noninc_history_pos;
61
62 static char *prev_line_found = (char *) NULL;
63
64 static int rl_history_search_len;
65 static int rl_history_search_pos;
66 static char *history_search_string;
67 static 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. */
72 static void
73 make_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. */
96 static int
97 noninc_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. */
127 static void
128 noninc_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 `:'. */
173 static void
174 noninc_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 `?'. */
275 int
276 rl_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 `/'. */
285 int
286 rl_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. */
295 int
296 rl_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. */
310 int
311 rl_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
323 static int
324 rl_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
383 static void
384 rl_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. */
406 int
407 rl_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. */
425 int
426 rl_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 }