1/* search.c - code for non-incremental searching in emacs and vi modes. */
2
3/* Copyright (C) 1992-2005 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_rl_search_cxt *_rl_nscxt = 0;
57
58extern HIST_ENTRY *_rl_saved_line_for_history;
59
60/* Functions imported from the rest of the library. */
61extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
62
63static char *noninc_search_string = (char *) NULL;
64static int noninc_history_pos;
65
66static char *prev_line_found = (char *) NULL;
67
68static int rl_history_search_len;
69static int rl_history_search_pos;
70static char *history_search_string;
71static int history_string_size;
72
73static UNDO_LIST *noninc_saved_undo_list;
74static void make_history_line_current PARAMS((HIST_ENTRY *));
75static int noninc_search_from_pos PARAMS((char *, int, int));
76static int noninc_dosearch PARAMS((char *, int));
77static int noninc_search PARAMS((int, int));
78static int rl_history_search_internal PARAMS((int, int));
79static void rl_history_search_reinit PARAMS((void));
80
81static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
82static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
83static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
84static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
85
86/* Make the data from the history entry ENTRY be the contents of the
87   current line.  This doesn't do anything with rl_point; the caller
88   must set it. */
89static void
90make_history_line_current (entry)
91     HIST_ENTRY *entry;
92{
93  _rl_replace_text (entry->line, 0, rl_end);
94  _rl_fix_point (1);
95#if defined (VI_MODE)
96  if (rl_editing_mode == vi_mode)
97    /* POSIX.2 says that the `U' command doesn't affect the copy of any
98       command lines to the edit line.  We're going to implement that by
99       making the undo list start after the matching line is copied to the
100       current editing buffer. */
101    rl_free_undo_list ();
102#endif
103
104  if (_rl_saved_line_for_history)
105    _rl_free_history_entry (_rl_saved_line_for_history);
106  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
107}
108
109/* Search the history list for STRING starting at absolute history position
110   POS.  If STRING begins with `^', the search must match STRING at the
111   beginning of a history line, otherwise a full substring match is performed
112   for STRING.  DIR < 0 means to search backwards through the history list,
113   DIR >= 0 means to search forward. */
114static int
115noninc_search_from_pos (string, pos, dir)
116     char *string;
117     int pos, dir;
118{
119  int ret, old;
120
121  if (pos < 0)
122    return -1;
123
124  old = where_history ();
125  if (history_set_pos (pos) == 0)
126    return -1;
127
128  RL_SETSTATE(RL_STATE_SEARCH);
129  if (*string == '^')
130    ret = history_search_prefix (string + 1, dir);
131  else
132    ret = history_search (string, dir);
133  RL_UNSETSTATE(RL_STATE_SEARCH);
134
135  if (ret != -1)
136    ret = where_history ();
137
138  history_set_pos (old);
139  return (ret);
140}
141
142/* Search for a line in the history containing STRING.  If DIR is < 0, the
143   search is backwards through previous entries, else through subsequent
144   entries.  Returns 1 if the search was successful, 0 otherwise. */
145static int
146noninc_dosearch (string, dir)
147     char *string;
148     int dir;
149{
150  int oldpos, pos;
151  HIST_ENTRY *entry;
152
153  if (string == 0 || *string == '\0' || noninc_history_pos < 0)
154    {
155      rl_ding ();
156      return 0;
157    }
158
159  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
160  if (pos == -1)
161    {
162      /* Search failed, current history position unchanged. */
163      rl_maybe_unsave_line ();
164      rl_clear_message ();
165      rl_point = 0;
166      rl_ding ();
167      return 0;
168    }
169
170  noninc_history_pos = pos;
171
172  oldpos = where_history ();
173  history_set_pos (noninc_history_pos);
174  entry = current_history ();
175#if defined (VI_MODE)
176  if (rl_editing_mode != vi_mode)
177#endif
178    history_set_pos (oldpos);
179
180  make_history_line_current (entry);
181
182  rl_point = 0;
183  rl_mark = rl_end;
184
185  rl_clear_message ();
186  return 1;
187}
188
189static _rl_search_cxt *
190_rl_nsearch_init (dir, pchar)
191     int dir, pchar;
192{
193  _rl_search_cxt *cxt;
194  char *p;
195
196  cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
197  if (dir < 0)
198    cxt->sflags |= SF_REVERSE;		/* not strictly needed */
199
200  cxt->direction = dir;
201  cxt->history_pos = cxt->save_line;
202
203  rl_maybe_save_line ();
204
205  /* Clear the undo list, since reading the search string should create its
206     own undo list, and the whole list will end up being freed when we
207     finish reading the search string. */
208  rl_undo_list = 0;
209
210  /* Use the line buffer to read the search string. */
211  rl_line_buffer[0] = 0;
212  rl_end = rl_point = 0;
213
214  p = _rl_make_prompt_for_search (pchar ? pchar : ':');
215  rl_message (p, 0, 0);
216  free (p);
217
218  RL_SETSTATE(RL_STATE_NSEARCH);
219
220  _rl_nscxt = cxt;
221
222  return cxt;
223}
224
225static int
226_rl_nsearch_cleanup (cxt, r)
227     _rl_search_cxt *cxt;
228     int r;
229{
230  _rl_scxt_dispose (cxt, 0);
231  _rl_nscxt = 0;
232
233  RL_UNSETSTATE(RL_STATE_NSEARCH);
234
235  return (r != 1);
236}
237
238static void
239_rl_nsearch_abort (cxt)
240     _rl_search_cxt *cxt;
241{
242  rl_maybe_unsave_line ();
243  rl_clear_message ();
244  rl_point = cxt->save_point;
245  rl_mark = cxt->save_mark;
246  rl_restore_prompt ();
247
248  RL_UNSETSTATE (RL_STATE_NSEARCH);
249}
250
251/* Process just-read character C according to search context CXT.  Return -1
252   if the caller should abort the search, 0 if we should break out of the
253   loop, and 1 if we should continue to read characters. */
254static int
255_rl_nsearch_dispatch (cxt, c)
256     _rl_search_cxt *cxt;
257     int c;
258{
259  switch (c)
260    {
261    case CTRL('W'):
262      rl_unix_word_rubout (1, c);
263      break;
264
265    case CTRL('U'):
266      rl_unix_line_discard (1, c);
267      break;
268
269    case RETURN:
270    case NEWLINE:
271      return 0;
272
273    case CTRL('H'):
274    case RUBOUT:
275      if (rl_point == 0)
276	{
277	  _rl_nsearch_abort (cxt);
278	  return -1;
279	}
280      _rl_rubout_char (1, c);
281      break;
282
283    case CTRL('C'):
284    case CTRL('G'):
285      rl_ding ();
286      _rl_nsearch_abort (cxt);
287      return -1;
288
289    default:
290#if defined (HANDLE_MULTIBYTE)
291      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
292	rl_insert_text (cxt->mb);
293      else
294#endif
295	_rl_insert_char (1, c);
296      break;
297    }
298
299  (*rl_redisplay_function) ();
300  return 1;
301}
302
303/* Perform one search according to CXT, using NONINC_SEARCH_STRING.  Return
304   -1 if the search should be aborted, any other value means to clean up
305   using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
306   0 otherwise. */
307static int
308_rl_nsearch_dosearch (cxt)
309     _rl_search_cxt *cxt;
310{
311  rl_mark = cxt->save_mark;
312
313  /* If rl_point == 0, we want to re-use the previous search string and
314     start from the saved history position.  If there's no previous search
315     string, punt. */
316  if (rl_point == 0)
317    {
318      if (noninc_search_string == 0)
319	{
320	  rl_ding ();
321	  rl_restore_prompt ();
322	  RL_UNSETSTATE (RL_STATE_NSEARCH);
323	  return -1;
324	}
325    }
326  else
327    {
328      /* We want to start the search from the current history position. */
329      noninc_history_pos = cxt->save_line;
330      FREE (noninc_search_string);
331      noninc_search_string = savestring (rl_line_buffer);
332
333      /* If we don't want the subsequent undo list generated by the search
334	 matching a history line to include the contents of the search string,
335	 we need to clear rl_line_buffer here.  For now, we just clear the
336	 undo list generated by reading the search string.  (If the search
337	 fails, the old undo list will be restored by rl_maybe_unsave_line.) */
338      rl_free_undo_list ();
339    }
340
341  rl_restore_prompt ();
342  return (noninc_dosearch (noninc_search_string, cxt->direction));
343}
344
345/* Search non-interactively through the history list.  DIR < 0 means to
346   search backwards through the history of previous commands; otherwise
347   the search is for commands subsequent to the current position in the
348   history list.  PCHAR is the character to use for prompting when reading
349   the search string; if not specified (0), it defaults to `:'. */
350static int
351noninc_search (dir, pchar)
352     int dir;
353     int pchar;
354{
355  _rl_search_cxt *cxt;
356  int c, r;
357
358  cxt = _rl_nsearch_init (dir, pchar);
359
360  if (RL_ISSTATE (RL_STATE_CALLBACK))
361    return (0);
362
363  /* Read the search string. */
364  r = 0;
365  while (1)
366    {
367      c = _rl_search_getchar (cxt);
368
369      if (c == 0)
370	break;
371
372      r = _rl_nsearch_dispatch (cxt, c);
373      if (r < 0)
374        return 1;
375      else if (r == 0)
376	break;
377    }
378
379  r = _rl_nsearch_dosearch (cxt);
380  return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
381}
382
383/* Search forward through the history list for a string.  If the vi-mode
384   code calls this, KEY will be `?'. */
385int
386rl_noninc_forward_search (count, key)
387     int count, key;
388{
389  return noninc_search (1, (key == '?') ? '?' : 0);
390}
391
392/* Reverse search the history list for a string.  If the vi-mode code
393   calls this, KEY will be `/'. */
394int
395rl_noninc_reverse_search (count, key)
396     int count, key;
397{
398  return noninc_search (-1, (key == '/') ? '/' : 0);
399}
400
401/* Search forward through the history list for the last string searched
402   for.  If there is no saved search string, abort. */
403int
404rl_noninc_forward_search_again (count, key)
405     int count, key;
406{
407  int r;
408
409  if (!noninc_search_string)
410    {
411      rl_ding ();
412      return (-1);
413    }
414  r = noninc_dosearch (noninc_search_string, 1);
415  return (r != 1);
416}
417
418/* Reverse search in the history list for the last string searched
419   for.  If there is no saved search string, abort. */
420int
421rl_noninc_reverse_search_again (count, key)
422     int count, key;
423{
424  int r;
425
426  if (!noninc_search_string)
427    {
428      rl_ding ();
429      return (-1);
430    }
431  r = noninc_dosearch (noninc_search_string, -1);
432  return (r != 1);
433}
434
435#if defined (READLINE_CALLBACKS)
436int
437_rl_nsearch_callback (cxt)
438     _rl_search_cxt *cxt;
439{
440  int c, r;
441
442  c = _rl_search_getchar (cxt);
443  r = _rl_nsearch_dispatch (cxt, c);
444  if (r != 0)
445    return 1;
446
447  r = _rl_nsearch_dosearch (cxt);
448  return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
449}
450#endif
451
452static int
453rl_history_search_internal (count, dir)
454     int count, dir;
455{
456  HIST_ENTRY *temp;
457  int ret, oldpos;
458
459  rl_maybe_save_line ();
460  temp = (HIST_ENTRY *)NULL;
461
462  /* Search COUNT times through the history for a line whose prefix
463     matches history_search_string.  When this loop finishes, TEMP,
464     if non-null, is the history line to copy into the line buffer. */
465  while (count)
466    {
467      ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
468      if (ret == -1)
469	break;
470
471      /* Get the history entry we found. */
472      rl_history_search_pos = ret;
473      oldpos = where_history ();
474      history_set_pos (rl_history_search_pos);
475      temp = current_history ();
476      history_set_pos (oldpos);
477
478      /* Don't find multiple instances of the same line. */
479      if (prev_line_found && STREQ (prev_line_found, temp->line))
480        continue;
481      prev_line_found = temp->line;
482      count--;
483    }
484
485  /* If we didn't find anything at all, return. */
486  if (temp == 0)
487    {
488      rl_maybe_unsave_line ();
489      rl_ding ();
490      /* If you don't want the saved history line (last match) to show up
491         in the line buffer after the search fails, change the #if 0 to
492         #if 1 */
493#if 0
494      if (rl_point > rl_history_search_len)
495        {
496          rl_point = rl_end = rl_history_search_len;
497          rl_line_buffer[rl_end] = '\0';
498          rl_mark = 0;
499        }
500#else
501      rl_point = rl_history_search_len;	/* rl_maybe_unsave_line changes it */
502      rl_mark = rl_end;
503#endif
504      return 1;
505    }
506
507  /* Copy the line we found into the current line buffer. */
508  make_history_line_current (temp);
509
510  rl_point = rl_history_search_len;
511  rl_mark = rl_end;
512
513  return 0;
514}
515
516static void
517rl_history_search_reinit ()
518{
519  rl_history_search_pos = where_history ();
520  rl_history_search_len = rl_point;
521  prev_line_found = (char *)NULL;
522  if (rl_point)
523    {
524      if (rl_history_search_len >= history_string_size - 2)
525	{
526	  history_string_size = rl_history_search_len + 2;
527	  history_search_string = (char *)xrealloc (history_search_string, history_string_size);
528	}
529      history_search_string[0] = '^';
530      strncpy (history_search_string + 1, rl_line_buffer, rl_point);
531      history_search_string[rl_point + 1] = '\0';
532    }
533  _rl_free_saved_history_line ();
534}
535
536/* Search forward in the history for the string of characters
537   from the start of the line to rl_point.  This is a non-incremental
538   search. */
539int
540rl_history_search_forward (count, ignore)
541     int count, ignore;
542{
543  if (count == 0)
544    return (0);
545
546  if (rl_last_func != rl_history_search_forward &&
547      rl_last_func != rl_history_search_backward)
548    rl_history_search_reinit ();
549
550  if (rl_history_search_len == 0)
551    return (rl_get_next_history (count, ignore));
552  return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
553}
554
555/* Search backward through the history for the string of characters
556   from the start of the line to rl_point.  This is a non-incremental
557   search. */
558int
559rl_history_search_backward (count, ignore)
560     int count, ignore;
561{
562  if (count == 0)
563    return (0);
564
565  if (rl_last_func != rl_history_search_forward &&
566      rl_last_func != rl_history_search_backward)
567    rl_history_search_reinit ();
568
569  if (rl_history_search_len == 0)
570    return (rl_get_previous_history (count, ignore));
571  return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
572}
573