]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/search.c
Imported from ../bash-2.05.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 2, 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 59 Temple Place, Suite 330, Boston, MA 02111 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 #include "rlprivate.h"
47 #include "xmalloc.h"
48
49 #ifdef abs
50 # undef abs
51 #endif
52 #define abs(x) (((x) >= 0) ? (x) : -(x))
53
54 extern HIST_ENTRY *_rl_saved_line_for_history;
55
56 /* Functions imported from the rest of the library. */
57 extern int _rl_free_history_entry __P((HIST_ENTRY *));
58
59 static char *noninc_search_string = (char *) NULL;
60 static int noninc_history_pos;
61
62 static char *prev_line_found = (char *) NULL;
63
64 static int rl_history_search_len;
65 static int rl_history_search_pos;
66 static char *history_search_string;
67 static int history_string_size;
68
69 /* Make the data from the history entry ENTRY be the contents of the
70 current line. This doesn't do anything with rl_point; the caller
71 must set it. */
72 static void
73 make_history_line_current (entry)
74 HIST_ENTRY *entry;
75 {
76 int line_len;
77
78 line_len = strlen (entry->line);
79 if (line_len >= rl_line_buffer_len)
80 rl_extend_line_buffer (line_len);
81 strcpy (rl_line_buffer, entry->line);
82
83 rl_undo_list = (UNDO_LIST *)entry->data;
84 rl_end = line_len;
85
86 if (_rl_saved_line_for_history)
87 _rl_free_history_entry (_rl_saved_line_for_history);
88 _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
89 }
90
91 /* Search the history list for STRING starting at absolute history position
92 POS. If STRING begins with `^', the search must match STRING at the
93 beginning of a history line, otherwise a full substring match is performed
94 for STRING. DIR < 0 means to search backwards through the history list,
95 DIR >= 0 means to search forward. */
96 static int
97 noninc_search_from_pos (string, pos, dir)
98 char *string;
99 int pos, dir;
100 {
101 int ret, old;
102
103 if (pos < 0)
104 return -1;
105
106 old = where_history ();
107 if (history_set_pos (pos) == 0)
108 return -1;
109
110 RL_SETSTATE(RL_STATE_SEARCH);
111 if (*string == '^')
112 ret = history_search_prefix (string + 1, dir);
113 else
114 ret = history_search (string, dir);
115 RL_UNSETSTATE(RL_STATE_SEARCH);
116
117 if (ret != -1)
118 ret = where_history ();
119
120 history_set_pos (old);
121 return (ret);
122 }
123
124 /* Search for a line in the history containing STRING. If DIR is < 0, the
125 search is backwards through previous entries, else through subsequent
126 entries. */
127 static void
128 noninc_dosearch (string, dir)
129 char *string;
130 int dir;
131 {
132 int oldpos, pos;
133 HIST_ENTRY *entry;
134
135 if (string == 0 || *string == '\0' || noninc_history_pos < 0)
136 {
137 rl_ding ();
138 return;
139 }
140
141 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
142 if (pos == -1)
143 {
144 /* Search failed, current history position unchanged. */
145 rl_maybe_unsave_line ();
146 rl_clear_message ();
147 rl_point = 0;
148 rl_ding ();
149 return;
150 }
151
152 noninc_history_pos = pos;
153
154 oldpos = where_history ();
155 history_set_pos (noninc_history_pos);
156 entry = current_history ();
157 #if defined (VI_MODE)
158 if (rl_editing_mode != vi_mode)
159 #endif
160 history_set_pos (oldpos);
161
162 make_history_line_current (entry);
163
164 rl_point = 0;
165 rl_clear_message ();
166 }
167
168 /* Search non-interactively through the history list. DIR < 0 means to
169 search backwards through the history of previous commands; otherwise
170 the search is for commands subsequent to the current position in the
171 history list. PCHAR is the character to use for prompting when reading
172 the search string; if not specified (0), it defaults to `:'. */
173 static void
174 noninc_search (dir, pchar)
175 int dir;
176 int pchar;
177 {
178 int saved_point, c;
179 char *p;
180
181 rl_maybe_save_line ();
182 saved_point = rl_point;
183
184 /* Use the line buffer to read the search string. */
185 rl_line_buffer[0] = 0;
186 rl_end = rl_point = 0;
187
188 p = _rl_make_prompt_for_search (pchar ? pchar : ':');
189 rl_message (p, 0, 0);
190 free (p);
191
192 #define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return
193
194 RL_SETSTATE(RL_STATE_NSEARCH);
195 /* Read the search string. */
196 while (1)
197 {
198 RL_SETSTATE(RL_STATE_MOREINPUT);
199 c = rl_read_key ();
200 RL_UNSETSTATE(RL_STATE_MOREINPUT);
201
202 if (c == 0)
203 break;
204
205 switch (c)
206 {
207 case CTRL('H'):
208 case RUBOUT:
209 if (rl_point == 0)
210 {
211 rl_maybe_unsave_line ();
212 rl_clear_message ();
213 rl_point = saved_point;
214 SEARCH_RETURN;
215 }
216 rl_rubout (1, c);
217 break;
218
219 case CTRL('W'):
220 rl_unix_word_rubout (1, c);
221 break;
222
223 case CTRL('U'):
224 rl_unix_line_discard (1, c);
225 break;
226
227 case RETURN:
228 case NEWLINE:
229 goto dosearch;
230 /* NOTREACHED */
231 break;
232
233 case CTRL('C'):
234 case CTRL('G'):
235 rl_maybe_unsave_line ();
236 rl_clear_message ();
237 rl_point = saved_point;
238 rl_ding ();
239 SEARCH_RETURN;
240
241 default:
242 rl_insert (1, c);
243 break;
244 }
245 (*rl_redisplay_function) ();
246 }
247
248 dosearch:
249 /* If rl_point == 0, we want to re-use the previous search string and
250 start from the saved history position. If there's no previous search
251 string, punt. */
252 if (rl_point == 0)
253 {
254 if (!noninc_search_string)
255 {
256 rl_ding ();
257 SEARCH_RETURN;
258 }
259 }
260 else
261 {
262 /* We want to start the search from the current history position. */
263 noninc_history_pos = where_history ();
264 FREE (noninc_search_string);
265 noninc_search_string = savestring (rl_line_buffer);
266 }
267
268 rl_restore_prompt ();
269 noninc_dosearch (noninc_search_string, dir);
270 RL_UNSETSTATE(RL_STATE_NSEARCH);
271 }
272
273 /* Search forward through the history list for a string. If the vi-mode
274 code calls this, KEY will be `?'. */
275 int
276 rl_noninc_forward_search (count, key)
277 int count, key;
278 {
279 noninc_search (1, (key == '?') ? '?' : 0);
280 return 0;
281 }
282
283 /* Reverse search the history list for a string. If the vi-mode code
284 calls this, KEY will be `/'. */
285 int
286 rl_noninc_reverse_search (count, key)
287 int count, key;
288 {
289 noninc_search (-1, (key == '/') ? '/' : 0);
290 return 0;
291 }
292
293 /* Search forward through the history list for the last string searched
294 for. If there is no saved search string, abort. */
295 int
296 rl_noninc_forward_search_again (count, key)
297 int count, key;
298 {
299 if (!noninc_search_string)
300 {
301 rl_ding ();
302 return (-1);
303 }
304 noninc_dosearch (noninc_search_string, 1);
305 return 0;
306 }
307
308 /* Reverse search in the history list for the last string searched
309 for. If there is no saved search string, abort. */
310 int
311 rl_noninc_reverse_search_again (count, key)
312 int count, key;
313 {
314 if (!noninc_search_string)
315 {
316 rl_ding ();
317 return (-1);
318 }
319 noninc_dosearch (noninc_search_string, -1);
320 return 0;
321 }
322
323 static int
324 rl_history_search_internal (count, dir)
325 int count, dir;
326 {
327 HIST_ENTRY *temp;
328 int ret, oldpos;
329
330 rl_maybe_save_line ();
331 temp = (HIST_ENTRY *)NULL;
332
333 /* Search COUNT times through the history for a line whose prefix
334 matches history_search_string. When this loop finishes, TEMP,
335 if non-null, is the history line to copy into the line buffer. */
336 while (count)
337 {
338 ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
339 if (ret == -1)
340 break;
341
342 /* Get the history entry we found. */
343 rl_history_search_pos = ret;
344 oldpos = where_history ();
345 history_set_pos (rl_history_search_pos);
346 temp = current_history ();
347 history_set_pos (oldpos);
348
349 /* Don't find multiple instances of the same line. */
350 if (prev_line_found && STREQ (prev_line_found, temp->line))
351 continue;
352 prev_line_found = temp->line;
353 count--;
354 }
355
356 /* If we didn't find anything at all, return. */
357 if (temp == 0)
358 {
359 rl_maybe_unsave_line ();
360 rl_ding ();
361 /* If you don't want the saved history line (last match) to show up
362 in the line buffer after the search fails, change the #if 0 to
363 #if 1 */
364 #if 0
365 if (rl_point > rl_history_search_len)
366 {
367 rl_point = rl_end = rl_history_search_len;
368 rl_line_buffer[rl_end] = '\0';
369 }
370 #else
371 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
372 #endif
373 return 1;
374 }
375
376 /* Copy the line we found into the current line buffer. */
377 make_history_line_current (temp);
378
379 rl_point = rl_history_search_len;
380 return 0;
381 }
382
383 static void
384 rl_history_search_reinit ()
385 {
386 rl_history_search_pos = where_history ();
387 rl_history_search_len = rl_point;
388 prev_line_found = (char *)NULL;
389 if (rl_point)
390 {
391 if (rl_history_search_len >= history_string_size - 2)
392 {
393 history_string_size = rl_history_search_len + 2;
394 history_search_string = xrealloc (history_search_string, history_string_size);
395 }
396 history_search_string[0] = '^';
397 strncpy (history_search_string + 1, rl_line_buffer, rl_point);
398 history_search_string[rl_point + 1] = '\0';
399 }
400 _rl_free_saved_history_line ();
401 }
402
403 /* Search forward in the history for the string of characters
404 from the start of the line to rl_point. This is a non-incremental
405 search. */
406 int
407 rl_history_search_forward (count, ignore)
408 int count, ignore;
409 {
410 if (count == 0)
411 return (0);
412
413 if (rl_last_func != rl_history_search_forward &&
414 rl_last_func != rl_history_search_backward)
415 rl_history_search_reinit ();
416
417 if (rl_history_search_len == 0)
418 return (rl_get_next_history (count, ignore));
419 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
420 }
421
422 /* Search backward through the history for the string of characters
423 from the start of the line to rl_point. This is a non-incremental
424 search. */
425 int
426 rl_history_search_backward (count, ignore)
427 int count, ignore;
428 {
429 if (count == 0)
430 return (0);
431
432 if (rl_last_func != rl_history_search_forward &&
433 rl_last_func != rl_history_search_backward)
434 rl_history_search_reinit ();
435
436 if (rl_history_search_len == 0)
437 return (rl_get_previous_history (count, ignore));
438 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
439 }