1/* **************************************************************** */
2/*								    */
3/*			I-Search and Searching			    */
4/*								    */
5/* **************************************************************** */
6
7/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
8
9   This file contains the Readline Library (the Library), a set of
10   routines for providing Emacs style line input to programs that ask
11   for it.
12
13   The Library is free software; you can redistribute it and/or modify
14   it under the terms of the GNU General Public License as published by
15   the Free Software Foundation; either version 2, or (at your option)
16   any later version.
17
18   The Library is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   The GNU General Public License is often shipped with GNU software, and
24   is generally kept in a file called COPYING or LICENSE.  If you do not
25   have a copy of the license, write to the Free Software Foundation,
26   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
27#define READLINE_LIBRARY
28
29#if defined (HAVE_CONFIG_H)
30#  include <config.h>
31#endif
32
33#include <sys/types.h>
34
35#include <stdio.h>
36
37#if defined (HAVE_UNISTD_H)
38#  include <unistd.h>
39#endif
40
41#if defined (HAVE_STDLIB_H)
42#  include <stdlib.h>
43#else
44#  include "ansi_stdlib.h"
45#endif
46
47#include "rldefs.h"
48#include "rlmbutil.h"
49
50#include "readline.h"
51#include "history.h"
52
53#include "rlprivate.h"
54#include "xmalloc.h"
55
56/* Variables exported to other files in the readline library. */
57char *_rl_isearch_terminators = (char *)NULL;
58
59_rl_search_cxt *_rl_iscxt = 0;
60
61/* Variables imported from other files in the readline library. */
62extern HIST_ENTRY *_rl_saved_line_for_history;
63
64static int rl_search_history PARAMS((int, int));
65
66static _rl_search_cxt *_rl_isearch_init PARAMS((int));
67static void _rl_isearch_fini PARAMS((_rl_search_cxt *));
68static int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int));
69
70/* Last line found by the current incremental search, so we don't `find'
71   identical lines many times in a row.  Now part of isearch context. */
72/* static char *prev_line_found; */
73
74/* Last search string and its length. */
75static char *last_isearch_string;
76static int last_isearch_string_len;
77
78static char *default_isearch_terminators = "\033\012";
79
80_rl_search_cxt *
81_rl_scxt_alloc (type, flags)
82     int type, flags;
83{
84  _rl_search_cxt *cxt;
85
86  cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt));
87
88  cxt->type = type;
89  cxt->sflags = flags;
90
91  cxt->search_string = 0;
92  cxt->search_string_size = cxt->search_string_index = 0;
93
94  cxt->lines = 0;
95  cxt->allocated_line = 0;
96  cxt->hlen = cxt->hindex = 0;
97
98  cxt->save_point = rl_point;
99  cxt->save_mark = rl_mark;
100  cxt->save_line = where_history ();
101  cxt->last_found_line = cxt->save_line;
102  cxt->prev_line_found = 0;
103
104  cxt->save_undo_list = 0;
105
106  cxt->history_pos = 0;
107  cxt->direction = 0;
108
109  cxt->lastc = 0;
110
111  cxt->sline = 0;
112  cxt->sline_len = cxt->sline_index = 0;
113
114  cxt->search_terminators = 0;
115
116  return cxt;
117}
118
119void
120_rl_scxt_dispose (cxt, flags)
121     _rl_search_cxt *cxt;
122     int flags;
123{
124  FREE (cxt->search_string);
125  FREE (cxt->allocated_line);
126  FREE (cxt->lines);
127
128  free (cxt);
129}
130
131/* Search backwards through the history looking for a string which is typed
132   interactively.  Start with the current line. */
133int
134rl_reverse_search_history (sign, key)
135     int sign, key;
136{
137  return (rl_search_history (-sign, key));
138}
139
140/* Search forwards through the history looking for a string which is typed
141   interactively.  Start with the current line. */
142int
143rl_forward_search_history (sign, key)
144     int sign, key;
145{
146  return (rl_search_history (sign, key));
147}
148
149/* Display the current state of the search in the echo-area.
150   SEARCH_STRING contains the string that is being searched for,
151   DIRECTION is zero for forward, or non-zero for reverse,
152   WHERE is the history list number of the current line.  If it is
153   -1, then this line is the starting one. */
154static void
155rl_display_search (search_string, reverse_p, where)
156     char *search_string;
157     int reverse_p, where;
158{
159  char *message;
160  int msglen, searchlen;
161
162  searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
163
164  message = (char *)xmalloc (searchlen + 33);
165  msglen = 0;
166
167#if defined (NOTDEF)
168  if (where != -1)
169    {
170      sprintf (message, "[%d]", where + history_base);
171      msglen = strlen (message);
172    }
173#endif /* NOTDEF */
174
175  message[msglen++] = '(';
176
177  if (reverse_p)
178    {
179      strcpy (message + msglen, "reverse-");
180      msglen += 8;
181    }
182
183  strcpy (message + msglen, "i-search)`");
184  msglen += 10;
185
186  if (search_string)
187    {
188      strcpy (message + msglen, search_string);
189      msglen += searchlen;
190    }
191
192  strcpy (message + msglen, "': ");
193
194  rl_message ("%s", message);
195  free (message);
196  (*rl_redisplay_function) ();
197}
198
199static _rl_search_cxt *
200_rl_isearch_init (direction)
201     int direction;
202{
203  _rl_search_cxt *cxt;
204  register int i;
205  HIST_ENTRY **hlist;
206
207  cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0);
208  if (direction < 0)
209    cxt->sflags |= SF_REVERSE;
210
211  cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
212						: default_isearch_terminators;
213
214  /* Create an arrary of pointers to the lines that we want to search. */
215  hlist = history_list ();
216  rl_maybe_replace_line ();
217  i = 0;
218  if (hlist)
219    for (i = 0; hlist[i]; i++);
220
221  /* Allocate space for this many lines, +1 for the current input line,
222     and remember those lines. */
223  cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *));
224  for (i = 0; i < cxt->hlen; i++)
225    cxt->lines[i] = hlist[i]->line;
226
227  if (_rl_saved_line_for_history)
228    cxt->lines[i] = _rl_saved_line_for_history->line;
229  else
230    {
231      /* Keep track of this so we can free it. */
232      cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
233      strcpy (cxt->allocated_line, &rl_line_buffer[0]);
234      cxt->lines[i] = cxt->allocated_line;
235    }
236
237  cxt->hlen++;
238
239  /* The line where we start the search. */
240  cxt->history_pos = cxt->save_line;
241
242  rl_save_prompt ();
243
244  /* Initialize search parameters. */
245  cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128);
246  cxt->search_string[cxt->search_string_index = 0] = '\0';
247
248  /* Normalize DIRECTION into 1 or -1. */
249  cxt->direction = (direction >= 0) ? 1 : -1;
250
251  cxt->sline = rl_line_buffer;
252  cxt->sline_len = strlen (cxt->sline);
253  cxt->sline_index = rl_point;
254
255  _rl_iscxt = cxt;		/* save globally */
256
257  return cxt;
258}
259
260static void
261_rl_isearch_fini (cxt)
262     _rl_search_cxt *cxt;
263{
264  /* First put back the original state. */
265  strcpy (rl_line_buffer, cxt->lines[cxt->save_line]);
266
267  rl_restore_prompt ();
268
269  /* Save the search string for possible later use. */
270  FREE (last_isearch_string);
271  last_isearch_string = cxt->search_string;
272  last_isearch_string_len = cxt->search_string_index;
273  cxt->search_string = 0;
274
275  if (cxt->last_found_line < cxt->save_line)
276    rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0);
277  else
278    rl_get_next_history (cxt->last_found_line - cxt->save_line, 0);
279
280  /* If the string was not found, put point at the end of the last matching
281     line.  If last_found_line == orig_line, we didn't find any matching
282     history lines at all, so put point back in its original position. */
283  if (cxt->sline_index < 0)
284    {
285      if (cxt->last_found_line == cxt->save_line)
286	cxt->sline_index = cxt->save_point;
287      else
288	cxt->sline_index = strlen (rl_line_buffer);
289      rl_mark = cxt->save_mark;
290    }
291
292  rl_point = cxt->sline_index;
293  /* Don't worry about where to put the mark here; rl_get_previous_history
294     and rl_get_next_history take care of it. */
295
296  rl_clear_message ();
297}
298
299int
300_rl_search_getchar (cxt)
301     _rl_search_cxt *cxt;
302{
303  int c;
304
305  /* Read a key and decide how to proceed. */
306  RL_SETSTATE(RL_STATE_MOREINPUT);
307  c = cxt->lastc = rl_read_key ();
308  RL_UNSETSTATE(RL_STATE_MOREINPUT);
309
310#if defined (HANDLE_MULTIBYTE)
311  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
312    c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
313#endif
314
315  return c;
316}
317
318/* Process just-read character C according to isearch context CXT.  Return
319   -1 if the caller should just free the context and return, 0 if we should
320   break out of the loop, and 1 if we should continue to read characters. */
321int
322_rl_isearch_dispatch (cxt, c)
323     _rl_search_cxt *cxt;
324     int c;
325{
326  int n, wstart, wlen, limit, cval;
327  rl_command_func_t *f;
328
329  f = (rl_command_func_t *)NULL;
330
331  if (c < 0)
332    {
333      cxt->sflags |= SF_FAILED;
334      cxt->history_pos = cxt->last_found_line;
335      return -1;
336    }
337
338  /* Translate the keys we do something with to opcodes. */
339  if (c >= 0 && _rl_keymap[c].type == ISFUNC)
340    {
341      f = _rl_keymap[c].function;
342
343      if (f == rl_reverse_search_history)
344	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
345      else if (f == rl_forward_search_history)
346	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
347      else if (f == rl_rubout)
348	cxt->lastc = -3;
349      else if (c == CTRL ('G'))
350	cxt->lastc = -4;
351      else if (c == CTRL ('W'))	/* XXX */
352	cxt->lastc = -5;
353      else if (c == CTRL ('Y'))	/* XXX */
354	cxt->lastc = -6;
355    }
356
357  /* The characters in isearch_terminators (set from the user-settable
358     variable isearch-terminators) are used to terminate the search but
359     not subsequently execute the character as a command.  The default
360     value is "\033\012" (ESC and C-J). */
361  if (strchr (cxt->search_terminators, cxt->lastc))
362    {
363      /* ESC still terminates the search, but if there is pending
364	 input or if input arrives within 0.1 seconds (on systems
365	 with select(2)) it is used as a prefix character
366	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
367	 to allow the arrow keys to be used like ^F and ^B are used
368	 to terminate the search and execute the movement command.
369	 XXX - since _rl_input_available depends on the application-
370	 settable keyboard timeout value, this could alternatively
371	 use _rl_input_queued(100000) */
372      if (cxt->lastc == ESC && _rl_input_available ())
373	rl_execute_next (ESC);
374      return (0);
375    }
376
377#define ENDSRCH_CHAR(c) \
378  ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
379
380#if defined (HANDLE_MULTIBYTE)
381  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
382    {
383      if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
384	{
385	  /* This sets rl_pending_input to c; it will be picked up the next
386	     time rl_read_key is called. */
387	  rl_execute_next (cxt->lastc);
388	  return (0);
389	}
390    }
391  else
392#endif
393    if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
394      {
395	/* This sets rl_pending_input to LASTC; it will be picked up the next
396	   time rl_read_key is called. */
397	rl_execute_next (cxt->lastc);
398	return (0);
399      }
400
401  /* Now dispatch on the character.  `Opcodes' affect the search string or
402     state.  Other characters are added to the string.  */
403  switch (cxt->lastc)
404    {
405    /* search again */
406    case -1:
407      if (cxt->search_string_index == 0)
408	{
409	  if (last_isearch_string)
410	    {
411	      cxt->search_string_size = 64 + last_isearch_string_len;
412	      cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
413	      strcpy (cxt->search_string, last_isearch_string);
414	      cxt->search_string_index = last_isearch_string_len;
415	      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
416	      break;
417	    }
418	  return (1);
419	}
420      else if (cxt->sflags & SF_REVERSE)
421	cxt->sline_index--;
422      else if (cxt->sline_index != cxt->sline_len)
423	cxt->sline_index++;
424      else
425	rl_ding ();
426      break;
427
428    /* switch directions */
429    case -2:
430      cxt->direction = -cxt->direction;
431      if (cxt->direction < 0)
432	cxt->sflags |= SF_REVERSE;
433      else
434	cxt->sflags &= ~SF_REVERSE;
435      break;
436
437    /* delete character from search string. */
438    case -3:	/* C-H, DEL */
439      /* This is tricky.  To do this right, we need to keep a
440	 stack of search positions for the current search, with
441	 sentinels marking the beginning and end.  But this will
442	 do until we have a real isearch-undo. */
443      if (cxt->search_string_index == 0)
444	rl_ding ();
445      else
446	cxt->search_string[--cxt->search_string_index] = '\0';
447      break;
448
449    case -4:	/* C-G, abort */
450      rl_replace_line (cxt->lines[cxt->save_line], 0);
451      rl_point = cxt->save_point;
452      rl_mark = cxt->save_mark;
453      rl_restore_prompt();
454      rl_clear_message ();
455
456      return -1;
457
458    case -5:	/* C-W */
459      /* skip over portion of line we already matched and yank word */
460      wstart = rl_point + cxt->search_string_index;
461      if (wstart >= rl_end)
462	{
463	  rl_ding ();
464	  break;
465	}
466
467      /* if not in a word, move to one. */
468      cval = _rl_char_value (rl_line_buffer, wstart);
469      if (_rl_walphabetic (cval) == 0)
470	{
471	  rl_ding ();
472	  break;
473	}
474      n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
475      while (n < rl_end)
476	{
477	  cval = _rl_char_value (rl_line_buffer, n);
478	  if (_rl_walphabetic (cval) == 0)
479	    break;
480	  n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
481	}
482      wlen = n - wstart + 1;
483      if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
484	{
485	  cxt->search_string_size += wlen + 1;
486	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
487	}
488      for (; wstart < n; wstart++)
489	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
490      cxt->search_string[cxt->search_string_index] = '\0';
491      break;
492
493    case -6:	/* C-Y */
494      /* skip over portion of line we already matched and yank rest */
495      wstart = rl_point + cxt->search_string_index;
496      if (wstart >= rl_end)
497	{
498	  rl_ding ();
499	  break;
500	}
501      n = rl_end - wstart + 1;
502      if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
503	{
504	  cxt->search_string_size += n + 1;
505	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
506	}
507      for (n = wstart; n < rl_end; n++)
508	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
509      cxt->search_string[cxt->search_string_index] = '\0';
510      break;
511
512    /* Add character to search string and continue search. */
513    default:
514      if (cxt->search_string_index + 2 >= cxt->search_string_size)
515	{
516	  cxt->search_string_size += 128;
517	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
518	}
519#if defined (HANDLE_MULTIBYTE)
520      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
521	{
522	  int j, l;
523	  for (j = 0, l = strlen (cxt->mb); j < l; )
524	    cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
525	}
526      else
527#endif
528	cxt->search_string[cxt->search_string_index++] = c;
529      cxt->search_string[cxt->search_string_index] = '\0';
530      break;
531    }
532
533  for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
534    {
535      limit = cxt->sline_len - cxt->search_string_index + 1;
536
537      /* Search the current line. */
538      while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
539	{
540	  if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
541	    {
542	      cxt->sflags |= SF_FOUND;
543	      break;
544	    }
545	  else
546	    cxt->sline_index += cxt->direction;
547	}
548      if (cxt->sflags & SF_FOUND)
549	break;
550
551      /* Move to the next line, but skip new copies of the line
552	 we just found and lines shorter than the string we're
553	 searching for. */
554      do
555	{
556	  /* Move to the next line. */
557	  cxt->history_pos += cxt->direction;
558
559	  /* At limit for direction? */
560	  if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
561	    {
562	      cxt->sflags |= SF_FAILED;
563	      break;
564	    }
565
566	  /* We will need these later. */
567	  cxt->sline = cxt->lines[cxt->history_pos];
568	  cxt->sline_len = strlen (cxt->sline);
569	}
570      while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
571	     (cxt->search_string_index > cxt->sline_len));
572
573      if (cxt->sflags & SF_FAILED)
574	break;
575
576      /* Now set up the line for searching... */
577      cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
578    }
579
580  if (cxt->sflags & SF_FAILED)
581    {
582      /* We cannot find the search string.  Ding the bell. */
583      rl_ding ();
584      cxt->history_pos = cxt->last_found_line;
585      return 1;
586    }
587
588  /* We have found the search string.  Just display it.  But don't
589     actually move there in the history list until the user accepts
590     the location. */
591  if (cxt->sflags & SF_FOUND)
592    {
593      cxt->prev_line_found = cxt->lines[cxt->history_pos];
594      rl_replace_line (cxt->lines[cxt->history_pos], 0);
595      rl_point = cxt->sline_index;
596      cxt->last_found_line = cxt->history_pos;
597      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
598    }
599
600  return 1;
601}
602
603static int
604_rl_isearch_cleanup (cxt, r)
605     _rl_search_cxt *cxt;
606     int r;
607{
608  if (r >= 0)
609    _rl_isearch_fini (cxt);
610  _rl_scxt_dispose (cxt, 0);
611  _rl_iscxt = 0;
612
613  RL_UNSETSTATE(RL_STATE_ISEARCH);
614
615  return (r != 0);
616}
617
618/* Search through the history looking for an interactively typed string.
619   This is analogous to i-search.  We start the search in the current line.
620   DIRECTION is which direction to search; >= 0 means forward, < 0 means
621   backwards. */
622static int
623rl_search_history (direction, invoking_key)
624     int direction, invoking_key;
625{
626  _rl_search_cxt *cxt;		/* local for now, but saved globally */
627  int c, r;
628
629  RL_SETSTATE(RL_STATE_ISEARCH);
630  cxt = _rl_isearch_init (direction);
631
632  rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
633
634  /* If we are using the callback interface, all we do is set up here and
635      return.  The key is that we leave RL_STATE_ISEARCH set. */
636  if (RL_ISSTATE (RL_STATE_CALLBACK))
637    return (0);
638
639  r = -1;
640  for (;;)
641    {
642      c = _rl_search_getchar (cxt);
643      /* We might want to handle EOF here (c == 0) */
644      r = _rl_isearch_dispatch (cxt, cxt->lastc);
645      if (r <= 0)
646        break;
647    }
648
649  /* The searching is over.  The user may have found the string that she
650     was looking for, or else she may have exited a failing search.  If
651     LINE_INDEX is -1, then that shows that the string searched for was
652     not found.  We use this to determine where to place rl_point. */
653  return (_rl_isearch_cleanup (cxt, r));
654}
655
656#if defined (READLINE_CALLBACKS)
657/* Called from the callback functions when we are ready to read a key.  The
658   callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
659   If _rl_isearch_dispatch finishes searching, this function is responsible
660   for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
661int
662_rl_isearch_callback (cxt)
663     _rl_search_cxt *cxt;
664{
665  int c, r;
666
667  c = _rl_search_getchar (cxt);
668  /* We might want to handle EOF here */
669  r = _rl_isearch_dispatch (cxt, cxt->lastc);
670
671  return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
672}
673#endif
674