Merge in changes from bash-1.13. The most obvious one is
[external/binutils.git] / 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
24 #include <stdio.h>
25
26 #if defined (__GNUC__)
27 #  define alloca __builtin_alloca
28 #else
29 #  if defined (sparc) || defined (HAVE_ALLOCA_H)
30 #    include <alloca.h>
31 #  endif
32 #endif
33
34 #include "readline.h"
35 #include "history.h"
36
37 extern char *xmalloc (), *xrealloc ();
38
39 /* Variables imported from readline.c */
40 extern int rl_point, rl_end, rl_line_buffer_len;
41 extern Keymap _rl_keymap;
42 extern char *rl_prompt;
43 extern char *rl_line_buffer;
44 extern HIST_ENTRY *saved_line_for_history;
45
46 static char *noninc_search_string = (char *) NULL;
47 static int noninc_history_pos = 0;
48
49 /* Search the history list for STRING starting at absolute history position
50    POS.  If STRING begins with `^', the search must match STRING at the
51    beginning of a history line, otherwise a full substring match is performed
52    for STRING.  DIR < 0 means to search backwards through the history list,
53    DIR >= 0 means to search forward. */
54 static int
55 noninc_search_from_pos (string, pos, dir)
56      char *string;
57      int pos, dir;
58 {
59   int ret, old;
60
61   old = where_history ();
62   history_set_pos (pos);
63
64   if (*string == '^')
65     ret = history_search_prefix (string + 1, dir);
66   else
67     ret = history_search (string, dir);
68
69   if (ret != -1)
70     ret = where_history ();
71
72   history_set_pos (old);
73   return (ret);
74 }
75
76 /* Search for a line in the history containing STRING.  If DIR is < 0, the
77    search is backwards through previous entries, else through subsequent
78    entries. */
79 static void
80 noninc_dosearch (string, dir)
81      char *string;
82      int dir;
83 {
84   int oldpos, pos;
85   HIST_ENTRY *entry;
86
87   if (string == 0 || *string == 0 || noninc_history_pos < 0)
88     {
89       ding ();
90       return;
91     }
92
93   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
94   if (pos == -1)
95     {
96       /* Search failed, current history position unchanged. */
97       maybe_unsave_line ();
98       rl_clear_message ();
99       rl_point = 0;
100       ding ();
101       return;
102     }
103
104   noninc_history_pos = pos;
105
106   oldpos = where_history ();
107   history_set_pos (noninc_history_pos);
108   entry = current_history ();
109   history_set_pos (oldpos);
110
111   {
112     int line_len;
113
114     line_len = strlen (entry->line);
115     if (line_len >= rl_line_buffer_len)
116       rl_extend_line_buffer (line_len);
117     strcpy (rl_line_buffer, entry->line);
118   }
119
120   rl_undo_list = (UNDO_LIST *)entry->data;
121   rl_end = strlen (rl_line_buffer);
122   rl_point = 0;
123   rl_clear_message ();
124
125   if (saved_line_for_history)
126     free_history_entry (saved_line_for_history);
127   saved_line_for_history = (HIST_ENTRY *)NULL;
128 }
129
130 /* Search non-interactively through the history list.  DIR < 0 means to
131    search backwards through the history of previous commands; otherwise
132    the search is for commands subsequent to the current position in the
133    history list.  PCHAR is the character to use for prompting when reading
134    the search string; if not specified (0), it defaults to `:'. */
135 static void
136 noninc_search (dir, pchar)
137      int dir;
138      int pchar;
139 {
140   int saved_point, c, pmtlen;
141   char *p;
142
143   maybe_save_line ();
144   saved_point = rl_point;
145
146   /* Use the line buffer to read the search string. */
147   rl_line_buffer[0] = 0;
148   rl_end = rl_point = 0;
149
150   pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
151   p = (char *)alloca (2 + pmtlen);
152   if (pmtlen)
153     strcpy (p, rl_prompt);
154   p[pmtlen] = pchar ? pchar : ':';
155   p[pmtlen + 1]  = '\0';
156
157   rl_message (p, 0, 0);
158
159   /* Read the search string. */
160   while (c = rl_read_key ())
161     {
162       switch (c)
163         {
164         case CTRL('H'):
165         case RUBOUT:
166           if (rl_point == 0)
167             {
168               maybe_unsave_line ();
169               rl_clear_message ();
170               rl_point = saved_point;
171               return;
172             }
173           /* FALLTHROUGH */
174
175         case CTRL('W'):
176         case CTRL('U'):
177           rl_dispatch (c, _rl_keymap);
178           break;
179
180         case RETURN:
181         case NEWLINE:
182           goto dosearch;
183           /* NOTREACHED */
184           break;
185
186         case CTRL('C'):
187         case CTRL('G'):
188           maybe_unsave_line ();
189           rl_clear_message ();
190           rl_point = saved_point;
191           ding ();
192           return;
193
194         default:
195           rl_insert (1, c);
196           break;
197         }
198       rl_redisplay ();
199     }
200
201  dosearch:
202   /* If rl_point == 0, we want to re-use the previous search string and
203      start from the saved history position.  If there's no previous search
204      string, punt. */
205   if (rl_point == 0)
206     {
207       if (!noninc_search_string)
208         {
209           ding ();
210           return;
211         }
212     }
213   else
214     {
215       /* We want to start the search from the current history position. */
216       noninc_history_pos = where_history ();
217       if (noninc_search_string)
218         free (noninc_search_string);
219       noninc_search_string = savestring (rl_line_buffer);
220     }
221
222   noninc_dosearch (noninc_search_string, dir);
223 }
224
225 /* Search forward through the history list for a string.  If the vi-mode
226    code calls this, KEY will be `?'. */
227 rl_noninc_forward_search (count, key)
228      int count, key;
229 {
230   if (key == '?')
231     noninc_search (1, '?');
232   else
233     noninc_search (1, 0);
234 }
235
236 /* Reverse search the history list for a string.  If the vi-mode code
237    calls this, KEY will be `/'. */
238 rl_noninc_reverse_search (count, key)
239      int count, key;
240 {
241   if (key == '/')
242     noninc_search (-1, '/');
243   else
244     noninc_search (-1, 0);
245 }
246
247 /* Search forward through the history list for the last string searched
248    for.  If there is no saved search string, abort. */
249 rl_noninc_forward_search_again (count, key)
250      int count, key;
251 {
252   if (!noninc_search_string)
253     {
254       ding ();
255       return (-1);
256     }
257   noninc_dosearch (noninc_search_string, 1);
258 }
259
260 /* Reverse search in the history list for the last string searched
261    for.  If there is no saved search string, abort. */
262 rl_noninc_reverse_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 }