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