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