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