]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/search.c
Imported from ../bash-2.0.tar.gz.
[thirdparty/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 }