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