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