05641a19f46294b44de90fddcb6ef27f228bc8b1
[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 1, 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    675 Mass Ave, Cambridge, MA 02139, 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 #include "rldefs.h"
37 #include "readline.h"
38 #include "history.h"
39
40 #define abs(x)          (((x) > 0) ? (x) : -(x))
41
42 extern char *xmalloc (), *xrealloc ();
43
44 /* Variables imported from readline.c */
45 extern int rl_point, rl_end, rl_line_buffer_len;
46 extern int rl_editing_mode;
47 extern char *rl_prompt;
48 extern char *rl_line_buffer;
49 extern HIST_ENTRY *saved_line_for_history;
50 extern Function *rl_last_func;
51
52 /* Functions imported from the rest of the library. */
53 extern int _rl_free_history_entry ();
54 extern char *_rl_make_prompt_for_search ();
55 extern void _rl_restore_prompt ();
56 extern void rl_extend_line_buffer ();
57
58 static char *noninc_search_string = (char *) NULL;
59 static int noninc_history_pos;
60 static char *prev_line_found = (char *) NULL;
61
62 /* Search the history list for STRING starting at absolute history position
63    POS.  If STRING begins with `^', the search must match STRING at the
64    beginning of a history line, otherwise a full substring match is performed
65    for STRING.  DIR < 0 means to search backwards through the history list,
66    DIR >= 0 means to search forward. */
67 static int
68 noninc_search_from_pos (string, pos, dir)
69      char *string;
70      int pos, dir;
71 {
72   int ret, old;
73
74   old = where_history ();
75   history_set_pos (pos);
76
77   if (*string == '^')
78     ret = history_search_prefix (string + 1, dir);
79   else
80     ret = history_search (string, dir);
81
82   if (ret != -1)
83     ret = where_history ();
84
85   history_set_pos (old);
86   return (ret);
87 }
88
89 /* Search for a line in the history containing STRING.  If DIR is < 0, the
90    search is backwards through previous entries, else through subsequent
91    entries. */
92 static void
93 noninc_dosearch (string, dir)
94      char *string;
95      int dir;
96 {
97   int oldpos, pos, line_len;
98   HIST_ENTRY *entry;
99
100   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
101     {
102       ding ();
103       return;
104     }
105
106   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
107   if (pos == -1)
108     {
109       /* Search failed, current history position unchanged. */
110       maybe_unsave_line ();
111       rl_clear_message ();
112       rl_point = 0;
113       ding ();
114       return;
115     }
116
117   noninc_history_pos = pos;
118
119   oldpos = where_history ();
120   history_set_pos (noninc_history_pos);
121   entry = current_history ();
122 #if defined (VI_MODE)
123   if (rl_editing_mode != vi_mode)
124 #endif
125   history_set_pos (oldpos);
126
127   line_len = strlen (entry->line);
128   if (line_len >= rl_line_buffer_len)
129     rl_extend_line_buffer (line_len);
130   strcpy (rl_line_buffer, entry->line);
131
132   rl_undo_list = (UNDO_LIST *)entry->data;
133   rl_end = strlen (rl_line_buffer);
134   rl_point = 0;
135   rl_clear_message ();
136
137   if (saved_line_for_history)
138     _rl_free_history_entry (saved_line_for_history);
139   saved_line_for_history = (HIST_ENTRY *)NULL;
140 }
141
142 /* Search non-interactively through the history list.  DIR < 0 means to
143    search backwards through the history of previous commands; otherwise
144    the search is for commands subsequent to the current position in the
145    history list.  PCHAR is the character to use for prompting when reading
146    the search string; if not specified (0), it defaults to `:'. */
147 static void
148 noninc_search (dir, pchar)
149      int dir;
150      int pchar;
151 {
152   int saved_point, c;
153   char *p;
154
155   maybe_save_line ();
156   saved_point = rl_point;
157
158   /* Use the line buffer to read the search string. */
159   rl_line_buffer[0] = 0;
160   rl_end = rl_point = 0;
161
162   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
163   rl_message (p, 0, 0);
164   free (p);
165
166 #define SEARCH_RETURN _rl_restore_prompt (); return
167
168   /* Read the search string. */
169   while (c = rl_read_key ())
170     {
171       switch (c)
172         {
173         case CTRL('H'):
174         case RUBOUT:
175           if (rl_point == 0)
176             {
177               maybe_unsave_line ();
178               rl_clear_message ();
179               rl_point = saved_point;
180               SEARCH_RETURN;
181             }
182           rl_rubout (1, c);
183           break;
184
185         case CTRL('W'):
186           rl_unix_word_rubout (1, c);
187           break;
188
189         case CTRL('U'):
190           rl_unix_line_discard (1, c);
191           break;
192
193         case RETURN:
194         case NEWLINE:
195           goto dosearch;
196           /* NOTREACHED */
197           break;
198
199         case CTRL('C'):
200         case CTRL('G'):
201           maybe_unsave_line ();
202           rl_clear_message ();
203           rl_point = saved_point;
204           ding ();
205           SEARCH_RETURN;
206
207         default:
208           rl_insert (1, c);
209           break;
210         }
211       (*rl_redisplay_function) ();
212     }
213
214  dosearch:
215   /* If rl_point == 0, we want to re-use the previous search string and
216      start from the saved history position.  If there's no previous search
217      string, punt. */
218   if (rl_point == 0)
219     {
220       if (!noninc_search_string)
221         {
222           ding ();
223           SEARCH_RETURN;
224         }
225     }
226   else
227     {
228       /* We want to start the search from the current history position. */
229       noninc_history_pos = where_history ();
230       if (noninc_search_string)
231         free (noninc_search_string);
232       noninc_search_string = savestring (rl_line_buffer);
233     }
234
235   _rl_restore_prompt ();
236   noninc_dosearch (noninc_search_string, dir);
237 }
238
239 /* Search forward through the history list for a string.  If the vi-mode
240    code calls this, KEY will be `?'. */
241 int
242 rl_noninc_forward_search (count, key)
243      int count, key;
244 {
245   noninc_search (1, (key == '?') ? '?' : 0);
246   return 0;
247 }
248
249 /* Reverse search the history list for a string.  If the vi-mode code
250    calls this, KEY will be `/'. */
251 int
252 rl_noninc_reverse_search (count, key)
253      int count, key;
254 {
255   noninc_search (-1, (key == '/') ? '/' : 0);
256   return 0;
257 }
258
259 /* Search forward through the history list for the last string searched
260    for.  If there is no saved search string, abort. */
261 int
262 rl_noninc_forward_search_again (count, key)
263      int count, key;
264 {
265   if (!noninc_search_string)
266     {
267       ding ();
268       return (-1);
269     }
270   noninc_dosearch (noninc_search_string, 1);
271   return 0;
272 }
273
274 /* Reverse search in the history list for the last string searched
275    for.  If there is no saved search string, abort. */
276 int
277 rl_noninc_reverse_search_again (count, key)
278      int count, key;
279 {
280   if (!noninc_search_string)
281     {
282       ding ();
283       return (-1);
284     }
285   noninc_dosearch (noninc_search_string, -1);
286   return 0;
287 }
288
289 static int
290 rl_history_search_internal (count, direction)
291      int count, direction;
292 {
293   HIST_ENTRY *temp, *old_temp;
294   int line_len;
295
296   maybe_save_line ();
297
298   temp = old_temp = (HIST_ENTRY *)NULL;
299   while (count)
300     {
301       temp = (direction < 0) ? previous_history () : next_history ();
302       if (temp == 0)
303         break;
304       /* On an empty prefix, make this the same as previous-history. */
305       if (rl_point == 0)
306         {
307           count--;
308           continue;
309         }
310       if (STREQN (rl_line_buffer, temp->line, rl_point))
311         {
312           /* Don't find multiple instances of the same line. */
313           if (prev_line_found && STREQ (prev_line_found, temp->line))
314             continue;
315           if (direction < 0)
316             old_temp = temp;
317           prev_line_found = temp->line;
318           count--;
319         }
320     }
321
322   if (temp == 0)
323     {
324       if (direction < 0 && old_temp)
325         temp = old_temp;
326       else
327         {
328           maybe_unsave_line ();
329           ding ();
330           return 1;
331         }
332     }
333
334   line_len = strlen (temp->line);
335   if (line_len >= rl_line_buffer_len)
336     rl_extend_line_buffer (line_len);
337   strcpy (rl_line_buffer, temp->line);
338   rl_undo_list = (UNDO_LIST *)temp->data;
339   rl_end = line_len;
340   return 0;
341 }
342
343 /* Search forward in the history for the string of characters
344    from the start of the line to rl_point.  This is a non-incremental
345    search. */
346 int
347 rl_history_search_forward (count, ignore)
348      int count, ignore;
349 {
350   if (count == 0)
351     return (0);
352   if (rl_last_func != rl_history_search_forward)
353     prev_line_found = (char *)NULL;
354   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
355 }
356
357 /* Search backward through the history for the string of characters
358    from the start of the line to rl_point.  This is a non-incremental
359    search. */
360 int
361 rl_history_search_backward (count, ignore)
362      int count, ignore;
363 {
364   if (count == 0)
365     return (0);
366   if (rl_last_func != rl_history_search_backward)
367     prev_line_found = (char *)NULL;
368   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
369 }