]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/search.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / lib / readline / search.c
CommitLineData
726f6388
JA
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
bb70624e 11 the Free Software Foundation; either version 2, or (at your option)
726f6388
JA
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,
bb70624e 22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388
JA
23#define READLINE_LIBRARY
24
ccc6cda3
JA
25#if defined (HAVE_CONFIG_H)
26# include <config.h>
27#endif
28
726f6388
JA
29#include <sys/types.h>
30#include <stdio.h>
31
32#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
d166f048
JA
36#if defined (HAVE_STDLIB_H)
37# include <stdlib.h>
38#else
39# include "ansi_stdlib.h"
40#endif
41
726f6388
JA
42#include "rldefs.h"
43#include "readline.h"
44#include "history.h"
45
bb70624e
JA
46#include "rlprivate.h"
47#include "xmalloc.h"
48
d166f048
JA
49#ifdef abs
50# undef abs
51#endif
52#define abs(x) (((x) >= 0) ? (x) : -(x))
726f6388 53
28ef6c31 54extern HIST_ENTRY *_rl_saved_line_for_history;
726f6388
JA
55
56/* Functions imported from the rest of the library. */
bb70624e 57extern int _rl_free_history_entry __P((HIST_ENTRY *));
726f6388
JA
58
59static char *noninc_search_string = (char *) NULL;
ccc6cda3 60static int noninc_history_pos;
bb70624e 61
726f6388
JA
62static char *prev_line_found = (char *) NULL;
63
bb70624e
JA
64static int rl_history_search_len;
65static int rl_history_search_pos;
66static char *history_search_string;
67static 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. */
72static void
73make_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
28ef6c31
JA
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;
bb70624e
JA
89}
90
726f6388
JA
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. */
96static int
97noninc_search_from_pos (string, pos, dir)
98 char *string;
99 int pos, dir;
100{
101 int ret, old;
102
28ef6c31
JA
103 if (pos < 0)
104 return -1;
105
726f6388 106 old = where_history ();
28ef6c31
JA
107 if (history_set_pos (pos) == 0)
108 return -1;
726f6388 109
28ef6c31 110 RL_SETSTATE(RL_STATE_SEARCH);
726f6388
JA
111 if (*string == '^')
112 ret = history_search_prefix (string + 1, dir);
113 else
114 ret = history_search (string, dir);
28ef6c31 115 RL_UNSETSTATE(RL_STATE_SEARCH);
726f6388
JA
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. */
127static void
128noninc_dosearch (string, dir)
129 char *string;
130 int dir;
131{
bb70624e 132 int oldpos, pos;
726f6388
JA
133 HIST_ENTRY *entry;
134
135 if (string == 0 || *string == '\0' || noninc_history_pos < 0)
136 {
28ef6c31 137 rl_ding ();
726f6388
JA
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. */
28ef6c31 145 rl_maybe_unsave_line ();
726f6388
JA
146 rl_clear_message ();
147 rl_point = 0;
28ef6c31 148 rl_ding ();
726f6388
JA
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
bb70624e 162 make_history_line_current (entry);
726f6388 163
726f6388
JA
164 rl_point = 0;
165 rl_clear_message ();
726f6388
JA
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 `:'. */
173static void
174noninc_search (dir, pchar)
175 int dir;
176 int pchar;
177{
ccc6cda3 178 int saved_point, c;
726f6388
JA
179 char *p;
180
28ef6c31 181 rl_maybe_save_line ();
726f6388
JA
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
ccc6cda3 188 p = _rl_make_prompt_for_search (pchar ? pchar : ':');
726f6388
JA
189 rl_message (p, 0, 0);
190 free (p);
191
28ef6c31 192#define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return
ccc6cda3 193
28ef6c31 194 RL_SETSTATE(RL_STATE_NSEARCH);
726f6388 195 /* Read the search string. */
28ef6c31 196 while (1)
726f6388 197 {
28ef6c31
JA
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
726f6388
JA
205 switch (c)
206 {
207 case CTRL('H'):
208 case RUBOUT:
209 if (rl_point == 0)
210 {
28ef6c31 211 rl_maybe_unsave_line ();
726f6388
JA
212 rl_clear_message ();
213 rl_point = saved_point;
ccc6cda3 214 SEARCH_RETURN;
726f6388 215 }
ccc6cda3 216 rl_rubout (1, c);
726f6388
JA
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'):
28ef6c31 235 rl_maybe_unsave_line ();
726f6388
JA
236 rl_clear_message ();
237 rl_point = saved_point;
28ef6c31 238 rl_ding ();
ccc6cda3 239 SEARCH_RETURN;
726f6388
JA
240
241 default:
242 rl_insert (1, c);
243 break;
244 }
ccc6cda3 245 (*rl_redisplay_function) ();
726f6388
JA
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 {
28ef6c31 256 rl_ding ();
ccc6cda3 257 SEARCH_RETURN;
726f6388
JA
258 }
259 }
260 else
261 {
262 /* We want to start the search from the current history position. */
263 noninc_history_pos = where_history ();
bb70624e 264 FREE (noninc_search_string);
726f6388
JA
265 noninc_search_string = savestring (rl_line_buffer);
266 }
267
b72432fd 268 rl_restore_prompt ();
726f6388 269 noninc_dosearch (noninc_search_string, dir);
28ef6c31 270 RL_UNSETSTATE(RL_STATE_NSEARCH);
726f6388
JA
271}
272
273/* Search forward through the history list for a string. If the vi-mode
274 code calls this, KEY will be `?'. */
ccc6cda3 275int
726f6388
JA
276rl_noninc_forward_search (count, key)
277 int count, key;
278{
ccc6cda3 279 noninc_search (1, (key == '?') ? '?' : 0);
726f6388
JA
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 `/'. */
ccc6cda3 285int
726f6388
JA
286rl_noninc_reverse_search (count, key)
287 int count, key;
288{
ccc6cda3 289 noninc_search (-1, (key == '/') ? '/' : 0);
726f6388
JA
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. */
ccc6cda3 295int
726f6388
JA
296rl_noninc_forward_search_again (count, key)
297 int count, key;
298{
299 if (!noninc_search_string)
300 {
28ef6c31 301 rl_ding ();
726f6388
JA
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. */
ccc6cda3 310int
726f6388
JA
311rl_noninc_reverse_search_again (count, key)
312 int count, key;
313{
314 if (!noninc_search_string)
315 {
28ef6c31 316 rl_ding ();
726f6388
JA
317 return (-1);
318 }
319 noninc_dosearch (noninc_search_string, -1);
320 return 0;
321}
322
323static int
bb70624e
JA
324rl_history_search_internal (count, dir)
325 int count, dir;
726f6388 326{
bb70624e
JA
327 HIST_ENTRY *temp;
328 int ret, oldpos;
726f6388 329
28ef6c31 330 rl_maybe_save_line ();
bb70624e 331 temp = (HIST_ENTRY *)NULL;
726f6388 332
bb70624e
JA
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. */
726f6388
JA
336 while (count)
337 {
bb70624e
JA
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--;
726f6388
JA
354 }
355
bb70624e 356 /* If we didn't find anything at all, return. */
ccc6cda3 357 if (temp == 0)
726f6388 358 {
28ef6c31
JA
359 rl_maybe_unsave_line ();
360 rl_ding ();
bb70624e
JA
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
28ef6c31 371 rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
bb70624e
JA
372#endif
373 return 1;
726f6388
JA
374 }
375
bb70624e
JA
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;
726f6388
JA
380 return 0;
381}
382
bb70624e
JA
383static void
384rl_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 }
28ef6c31 400 _rl_free_saved_history_line ();
bb70624e
JA
401}
402
726f6388
JA
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. */
406int
407rl_history_search_forward (count, ignore)
408 int count, ignore;
409{
410 if (count == 0)
411 return (0);
bb70624e
JA
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));
726f6388
JA
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. */
425int
426rl_history_search_backward (count, ignore)
427 int count, ignore;
428{
429 if (count == 0)
430 return (0);
bb70624e
JA
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));
726f6388
JA
438 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
439}