Merge from vendor branch CVS:
[dragonfly.git] / contrib / readline-5.0 / 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 "rlmbutil.h"
44
45 #include "readline.h"
46 #include "history.h"
47
48 #include "rlprivate.h"
49 #include "xmalloc.h"
50
51 #ifdef abs
52 #  undef abs
53 #endif
54 #define abs(x)          (((x) >= 0) ? (x) : -(x))
55
56 extern HIST_ENTRY *_rl_saved_line_for_history;
57
58 /* Functions imported from the rest of the library. */
59 extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
60
61 static char *noninc_search_string = (char *) NULL;
62 static int noninc_history_pos;
63
64 static char *prev_line_found = (char *) NULL;
65
66 static int rl_history_search_len;
67 static int rl_history_search_pos;
68 static char *history_search_string;
69 static int history_string_size;
70
71 static void make_history_line_current PARAMS((HIST_ENTRY *));
72 static int noninc_search_from_pos PARAMS((char *, int, int));
73 static void noninc_dosearch PARAMS((char *, int));
74 static void noninc_search PARAMS((int, int));
75 static int rl_history_search_internal PARAMS((int, int));
76 static void rl_history_search_reinit PARAMS((void));
77
78 /* Make the data from the history entry ENTRY be the contents of the
79    current line.  This doesn't do anything with rl_point; the caller
80    must set it. */
81 static void
82 make_history_line_current (entry)
83      HIST_ENTRY *entry;
84 {
85 #if 0
86   rl_replace_line (entry->line, 1);
87   rl_undo_list = (UNDO_LIST *)entry->data;
88 #else
89   _rl_replace_text (entry->line, 0, rl_end);
90   _rl_fix_point (1);
91 #endif
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_mark = rl_end;
173
174   rl_clear_message ();
175 }
176
177 /* Search non-interactively through the history list.  DIR < 0 means to
178    search backwards through the history of previous commands; otherwise
179    the search is for commands subsequent to the current position in the
180    history list.  PCHAR is the character to use for prompting when reading
181    the search string; if not specified (0), it defaults to `:'. */
182 static void
183 noninc_search (dir, pchar)
184      int dir;
185      int pchar;
186 {
187   int saved_point, saved_mark, c;
188   char *p;
189 #if defined (HANDLE_MULTIBYTE)
190   char mb[MB_LEN_MAX];
191 #endif
192
193   rl_maybe_save_line ();
194   saved_point = rl_point;
195   saved_mark = rl_mark;
196
197   /* Clear the undo list, since reading the search string should create its
198      own undo list, and the whole list will end up being freed when we
199      finish reading the search string. */
200   rl_undo_list = 0;
201
202   /* Use the line buffer to read the search string. */
203   rl_line_buffer[0] = 0;
204   rl_end = rl_point = 0;
205
206   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
207   rl_message (p, 0, 0);
208   free (p);
209
210 #define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return
211
212   RL_SETSTATE(RL_STATE_NSEARCH);
213   /* Read the search string. */
214   while (1)
215     {
216       RL_SETSTATE(RL_STATE_MOREINPUT);
217       c = rl_read_key ();
218       RL_UNSETSTATE(RL_STATE_MOREINPUT);
219
220 #if defined (HANDLE_MULTIBYTE)
221       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
222         c = _rl_read_mbstring (c, mb, MB_LEN_MAX);
223 #endif
224
225       if (c == 0)
226         break;
227
228       switch (c)
229         {
230         case CTRL('H'):
231         case RUBOUT:
232           if (rl_point == 0)
233             {
234               rl_maybe_unsave_line ();
235               rl_clear_message ();
236               rl_point = saved_point;
237               rl_mark = saved_mark;
238               SEARCH_RETURN;
239             }
240           _rl_rubout_char (1, c);
241           break;
242
243         case CTRL('W'):
244           rl_unix_word_rubout (1, c);
245           break;
246
247         case CTRL('U'):
248           rl_unix_line_discard (1, c);
249           break;
250
251         case RETURN:
252         case NEWLINE:
253           goto dosearch;
254           /* NOTREACHED */
255           break;
256
257         case CTRL('C'):
258         case CTRL('G'):
259           rl_maybe_unsave_line ();
260           rl_clear_message ();
261           rl_point = saved_point;
262           rl_mark = saved_mark;
263           rl_ding ();
264           SEARCH_RETURN;
265
266         default:
267 #if defined (HANDLE_MULTIBYTE)
268           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
269             rl_insert_text (mb);
270           else
271 #endif
272             _rl_insert_char (1, c);
273           break;
274         }
275       (*rl_redisplay_function) ();
276     }
277
278  dosearch:
279   rl_mark = saved_mark;
280
281   /* If rl_point == 0, we want to re-use the previous search string and
282      start from the saved history position.  If there's no previous search
283      string, punt. */
284   if (rl_point == 0)
285     {
286       if (!noninc_search_string)
287         {
288           rl_ding ();
289           SEARCH_RETURN;
290         }
291     }
292   else
293     {
294       /* We want to start the search from the current history position. */
295       noninc_history_pos = where_history ();
296       FREE (noninc_search_string);
297       noninc_search_string = savestring (rl_line_buffer);
298     }
299
300   rl_restore_prompt ();
301   noninc_dosearch (noninc_search_string, dir);
302   RL_UNSETSTATE(RL_STATE_NSEARCH);
303 }
304
305 /* Search forward through the history list for a string.  If the vi-mode
306    code calls this, KEY will be `?'. */
307 int
308 rl_noninc_forward_search (count, key)
309      int count, key;
310 {
311   noninc_search (1, (key == '?') ? '?' : 0);
312   return 0;
313 }
314
315 /* Reverse search the history list for a string.  If the vi-mode code
316    calls this, KEY will be `/'. */
317 int
318 rl_noninc_reverse_search (count, key)
319      int count, key;
320 {
321   noninc_search (-1, (key == '/') ? '/' : 0);
322   return 0;
323 }
324
325 /* Search forward through the history list for the last string searched
326    for.  If there is no saved search string, abort. */
327 int
328 rl_noninc_forward_search_again (count, key)
329      int count, key;
330 {
331   if (!noninc_search_string)
332     {
333       rl_ding ();
334       return (-1);
335     }
336   noninc_dosearch (noninc_search_string, 1);
337   return 0;
338 }
339
340 /* Reverse search in the history list for the last string searched
341    for.  If there is no saved search string, abort. */
342 int
343 rl_noninc_reverse_search_again (count, key)
344      int count, key;
345 {
346   if (!noninc_search_string)
347     {
348       rl_ding ();
349       return (-1);
350     }
351   noninc_dosearch (noninc_search_string, -1);
352   return 0;
353 }
354
355 static int
356 rl_history_search_internal (count, dir)
357      int count, dir;
358 {
359   HIST_ENTRY *temp;
360   int ret, oldpos;
361
362   rl_maybe_save_line ();
363   temp = (HIST_ENTRY *)NULL;
364
365   /* Search COUNT times through the history for a line whose prefix
366      matches history_search_string.  When this loop finishes, TEMP,
367      if non-null, is the history line to copy into the line buffer. */
368   while (count)
369     {
370       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
371       if (ret == -1)
372         break;
373
374       /* Get the history entry we found. */
375       rl_history_search_pos = ret;
376       oldpos = where_history ();
377       history_set_pos (rl_history_search_pos);
378       temp = current_history ();
379       history_set_pos (oldpos);
380
381       /* Don't find multiple instances of the same line. */
382       if (prev_line_found && STREQ (prev_line_found, temp->line))
383         continue;
384       prev_line_found = temp->line;
385       count--;
386     }
387
388   /* If we didn't find anything at all, return. */
389   if (temp == 0)
390     {
391       rl_maybe_unsave_line ();
392       rl_ding ();
393       /* If you don't want the saved history line (last match) to show up
394          in the line buffer after the search fails, change the #if 0 to
395          #if 1 */
396 #if 0
397       if (rl_point > rl_history_search_len)
398         {
399           rl_point = rl_end = rl_history_search_len;
400           rl_line_buffer[rl_end] = '\0';
401           rl_mark = 0;
402         }
403 #else
404       rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
405       rl_mark = rl_end;
406 #endif
407       return 1;
408     }
409
410   /* Copy the line we found into the current line buffer. */
411   make_history_line_current (temp);
412
413   rl_point = rl_history_search_len;
414   rl_mark = rl_end;
415
416   return 0;
417 }
418
419 static void
420 rl_history_search_reinit ()
421 {
422   rl_history_search_pos = where_history ();
423   rl_history_search_len = rl_point;
424   prev_line_found = (char *)NULL;
425   if (rl_point)
426     {
427       if (rl_history_search_len >= history_string_size - 2)
428         {
429           history_string_size = rl_history_search_len + 2;
430           history_search_string = (char *)xrealloc (history_search_string, history_string_size);
431         }
432       history_search_string[0] = '^';
433       strncpy (history_search_string + 1, rl_line_buffer, rl_point);
434       history_search_string[rl_point + 1] = '\0';
435     }
436   _rl_free_saved_history_line ();
437 }
438
439 /* Search forward in the history for the string of characters
440    from the start of the line to rl_point.  This is a non-incremental
441    search. */
442 int
443 rl_history_search_forward (count, ignore)
444      int count, ignore;
445 {
446   if (count == 0)
447     return (0);
448
449   if (rl_last_func != rl_history_search_forward &&
450       rl_last_func != rl_history_search_backward)
451     rl_history_search_reinit ();
452
453   if (rl_history_search_len == 0)
454     return (rl_get_next_history (count, ignore));
455   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
456 }
457
458 /* Search backward through the history for the string of characters
459    from the start of the line to rl_point.  This is a non-incremental
460    search. */
461 int
462 rl_history_search_backward (count, ignore)
463      int count, ignore;
464 {
465   if (count == 0)
466     return (0);
467
468   if (rl_last_func != rl_history_search_forward &&
469       rl_last_func != rl_history_search_backward)
470     rl_history_search_reinit ();
471
472   if (rl_history_search_len == 0)
473     return (rl_get_previous_history (count, ignore));
474   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
475 }