isearch.c revision 165670
121308Sache/* **************************************************************** */
221308Sache/*								    */
321308Sache/*			I-Search and Searching			    */
421308Sache/*								    */
521308Sache/* **************************************************************** */
621308Sache
7157184Sache/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
821308Sache
921308Sache   This file contains the Readline Library (the Library), a set of
1021308Sache   routines for providing Emacs style line input to programs that ask
1121308Sache   for it.
1221308Sache
1321308Sache   The Library is free software; you can redistribute it and/or modify
1421308Sache   it under the terms of the GNU General Public License as published by
1558310Sache   the Free Software Foundation; either version 2, or (at your option)
1621308Sache   any later version.
1721308Sache
1821308Sache   The Library is distributed in the hope that it will be useful, but
1921308Sache   WITHOUT ANY WARRANTY; without even the implied warranty of
2021308Sache   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2121308Sache   General Public License for more details.
2221308Sache
2321308Sache   The GNU General Public License is often shipped with GNU software, and
2421308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2521308Sache   have a copy of the license, write to the Free Software Foundation,
2658310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2721308Sache#define READLINE_LIBRARY
2821308Sache
2921308Sache#if defined (HAVE_CONFIG_H)
3021308Sache#  include <config.h>
3121308Sache#endif
3221308Sache
3326497Sache#include <sys/types.h>
3426497Sache
3521308Sache#include <stdio.h>
3621308Sache
3721308Sache#if defined (HAVE_UNISTD_H)
3821308Sache#  include <unistd.h>
3921308Sache#endif
4021308Sache
4126497Sache#if defined (HAVE_STDLIB_H)
4226497Sache#  include <stdlib.h>
4326497Sache#else
4426497Sache#  include "ansi_stdlib.h"
4526497Sache#endif
4621308Sache
4721308Sache#include "rldefs.h"
48119610Sache#include "rlmbutil.h"
49119610Sache
5021308Sache#include "readline.h"
5121308Sache#include "history.h"
5221308Sache
5358310Sache#include "rlprivate.h"
5458310Sache#include "xmalloc.h"
5558310Sache
5647558Sache/* Variables exported to other files in the readline library. */
57119610Sachechar *_rl_isearch_terminators = (char *)NULL;
5847558Sache
59157184Sache_rl_search_cxt *_rl_iscxt = 0;
60157184Sache
6121308Sache/* Variables imported from other files in the readline library. */
6275406Sacheextern HIST_ENTRY *_rl_saved_line_for_history;
6321308Sache
64119610Sachestatic int rl_search_history PARAMS((int, int));
6521308Sache
66157184Sachestatic _rl_search_cxt *_rl_isearch_init PARAMS((int));
67157184Sachestatic void _rl_isearch_fini PARAMS((_rl_search_cxt *));
68157184Sachestatic int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int));
69157184Sache
7021308Sache/* Last line found by the current incremental search, so we don't `find'
71165670Sache   identical lines many times in a row.  Now part of isearch context. */
72165670Sache/* static char *prev_line_found; */
7321308Sache
74119610Sache/* Last search string and its length. */
75119610Sachestatic char *last_isearch_string;
76119610Sachestatic int last_isearch_string_len;
7775406Sache
78119610Sachestatic char *default_isearch_terminators = "\033\012";
79119610Sache
80157184Sache_rl_search_cxt *
81157184Sache_rl_scxt_alloc (type, flags)
82157184Sache     int type, flags;
83157184Sache{
84157184Sache  _rl_search_cxt *cxt;
85157184Sache
86157184Sache  cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt));
87157184Sache
88157184Sache  cxt->type = type;
89157184Sache  cxt->sflags = flags;
90157184Sache
91157184Sache  cxt->search_string = 0;
92157184Sache  cxt->search_string_size = cxt->search_string_index = 0;
93157184Sache
94157184Sache  cxt->lines = 0;
95157184Sache  cxt->allocated_line = 0;
96157184Sache  cxt->hlen = cxt->hindex = 0;
97157184Sache
98157184Sache  cxt->save_point = rl_point;
99157184Sache  cxt->save_mark = rl_mark;
100157184Sache  cxt->save_line = where_history ();
101157184Sache  cxt->last_found_line = cxt->save_line;
102157184Sache  cxt->prev_line_found = 0;
103157184Sache
104157184Sache  cxt->save_undo_list = 0;
105157184Sache
106157184Sache  cxt->history_pos = 0;
107157184Sache  cxt->direction = 0;
108157184Sache
109157184Sache  cxt->lastc = 0;
110157184Sache
111157184Sache  cxt->sline = 0;
112157184Sache  cxt->sline_len = cxt->sline_index = 0;
113157184Sache
114157184Sache  cxt->search_terminators = 0;
115157184Sache
116157184Sache  return cxt;
117157184Sache}
118157184Sache
119157184Sachevoid
120157184Sache_rl_scxt_dispose (cxt, flags)
121157184Sache     _rl_search_cxt *cxt;
122157184Sache     int flags;
123157184Sache{
124157184Sache  FREE (cxt->search_string);
125157184Sache  FREE (cxt->allocated_line);
126157184Sache  FREE (cxt->lines);
127157184Sache
128157184Sache  free (cxt);
129157184Sache}
130157184Sache
13121308Sache/* Search backwards through the history looking for a string which is typed
13221308Sache   interactively.  Start with the current line. */
13321308Sacheint
13421308Sacherl_reverse_search_history (sign, key)
13521308Sache     int sign, key;
13621308Sache{
13721308Sache  return (rl_search_history (-sign, key));
13821308Sache}
13921308Sache
14021308Sache/* Search forwards through the history looking for a string which is typed
14121308Sache   interactively.  Start with the current line. */
14221308Sacheint
14321308Sacherl_forward_search_history (sign, key)
14421308Sache     int sign, key;
14521308Sache{
14621308Sache  return (rl_search_history (sign, key));
14721308Sache}
14821308Sache
14921308Sache/* Display the current state of the search in the echo-area.
15021308Sache   SEARCH_STRING contains the string that is being searched for,
151157184Sache   DIRECTION is zero for forward, or non-zero for reverse,
15221308Sache   WHERE is the history list number of the current line.  If it is
15321308Sache   -1, then this line is the starting one. */
15421308Sachestatic void
15521308Sacherl_display_search (search_string, reverse_p, where)
15621308Sache     char *search_string;
15721308Sache     int reverse_p, where;
15821308Sache{
15921308Sache  char *message;
16021308Sache  int msglen, searchlen;
16121308Sache
16221308Sache  searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
16321308Sache
164119610Sache  message = (char *)xmalloc (searchlen + 33);
16521308Sache  msglen = 0;
16621308Sache
16721308Sache#if defined (NOTDEF)
16821308Sache  if (where != -1)
16921308Sache    {
17021308Sache      sprintf (message, "[%d]", where + history_base);
17121308Sache      msglen = strlen (message);
17221308Sache    }
17321308Sache#endif /* NOTDEF */
17421308Sache
17521308Sache  message[msglen++] = '(';
17621308Sache
17721308Sache  if (reverse_p)
17821308Sache    {
17921308Sache      strcpy (message + msglen, "reverse-");
18021308Sache      msglen += 8;
18121308Sache    }
18221308Sache
18321308Sache  strcpy (message + msglen, "i-search)`");
18421308Sache  msglen += 10;
18521308Sache
18621308Sache  if (search_string)
18721308Sache    {
18821308Sache      strcpy (message + msglen, search_string);
18921308Sache      msglen += searchlen;
19021308Sache    }
19121308Sache
19221308Sache  strcpy (message + msglen, "': ");
19321308Sache
194119610Sache  rl_message ("%s", message);
19521308Sache  free (message);
19621308Sache  (*rl_redisplay_function) ();
19721308Sache}
19821308Sache
199157184Sachestatic _rl_search_cxt *
200157184Sache_rl_isearch_init (direction)
201157184Sache     int direction;
20221308Sache{
203157184Sache  _rl_search_cxt *cxt;
204157184Sache  register int i;
20521308Sache  HIST_ENTRY **hlist;
20621308Sache
207157184Sache  cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0);
208157184Sache  if (direction < 0)
209157184Sache    cxt->sflags |= SF_REVERSE;
21021308Sache
211157184Sache  cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
21275406Sache						: default_isearch_terminators;
21347558Sache
21421308Sache  /* Create an arrary of pointers to the lines that we want to search. */
215157184Sache  hlist = history_list ();
21675406Sache  rl_maybe_replace_line ();
21721308Sache  i = 0;
21821308Sache  if (hlist)
21921308Sache    for (i = 0; hlist[i]; i++);
22021308Sache
22121308Sache  /* Allocate space for this many lines, +1 for the current input line,
22221308Sache     and remember those lines. */
223157184Sache  cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *));
224157184Sache  for (i = 0; i < cxt->hlen; i++)
225157184Sache    cxt->lines[i] = hlist[i]->line;
22621308Sache
22775406Sache  if (_rl_saved_line_for_history)
228157184Sache    cxt->lines[i] = _rl_saved_line_for_history->line;
22921308Sache  else
23021308Sache    {
23121308Sache      /* Keep track of this so we can free it. */
232157184Sache      cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
233157184Sache      strcpy (cxt->allocated_line, &rl_line_buffer[0]);
234157184Sache      cxt->lines[i] = cxt->allocated_line;
23521308Sache    }
23621308Sache
237157184Sache  cxt->hlen++;
23821308Sache
23921308Sache  /* The line where we start the search. */
240157184Sache  cxt->history_pos = cxt->save_line;
24121308Sache
24247558Sache  rl_save_prompt ();
24321308Sache
24421308Sache  /* Initialize search parameters. */
245157184Sache  cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128);
246157184Sache  cxt->search_string[cxt->search_string_index = 0] = '\0';
24721308Sache
24821308Sache  /* Normalize DIRECTION into 1 or -1. */
249157184Sache  cxt->direction = (direction >= 0) ? 1 : -1;
25021308Sache
251157184Sache  cxt->sline = rl_line_buffer;
252157184Sache  cxt->sline_len = strlen (cxt->sline);
253157184Sache  cxt->sline_index = rl_point;
25421308Sache
255157184Sache  _rl_iscxt = cxt;		/* save globally */
25621308Sache
257157184Sache  return cxt;
258157184Sache}
259157184Sache
260157184Sachestatic void
261157184Sache_rl_isearch_fini (cxt)
262157184Sache     _rl_search_cxt *cxt;
263157184Sache{
264157184Sache  /* First put back the original state. */
265157184Sache  strcpy (rl_line_buffer, cxt->lines[cxt->save_line]);
266157184Sache
267157184Sache  rl_restore_prompt ();
268157184Sache
269157184Sache  /* Save the search string for possible later use. */
270157184Sache  FREE (last_isearch_string);
271157184Sache  last_isearch_string = cxt->search_string;
272157184Sache  last_isearch_string_len = cxt->search_string_index;
273157184Sache  cxt->search_string = 0;
274157184Sache
275157184Sache  if (cxt->last_found_line < cxt->save_line)
276157184Sache    rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0);
277157184Sache  else
278157184Sache    rl_get_next_history (cxt->last_found_line - cxt->save_line, 0);
279157184Sache
280157184Sache  /* If the string was not found, put point at the end of the last matching
281157184Sache     line.  If last_found_line == orig_line, we didn't find any matching
282157184Sache     history lines at all, so put point back in its original position. */
283157184Sache  if (cxt->sline_index < 0)
28421308Sache    {
285157184Sache      if (cxt->last_found_line == cxt->save_line)
286157184Sache	cxt->sline_index = cxt->save_point;
287157184Sache      else
288157184Sache	cxt->sline_index = strlen (rl_line_buffer);
289157184Sache      rl_mark = cxt->save_mark;
290157184Sache    }
29121308Sache
292157184Sache  rl_point = cxt->sline_index;
293157184Sache  /* Don't worry about where to put the mark here; rl_get_previous_history
294157184Sache     and rl_get_next_history take care of it. */
29521308Sache
296157184Sache  rl_clear_message ();
297157184Sache}
298157184Sache
299157184Sacheint
300157184Sache_rl_search_getchar (cxt)
301157184Sache     _rl_search_cxt *cxt;
302157184Sache{
303157184Sache  int c;
304157184Sache
305157184Sache  /* Read a key and decide how to proceed. */
306157184Sache  RL_SETSTATE(RL_STATE_MOREINPUT);
307157184Sache  c = cxt->lastc = rl_read_key ();
308157184Sache  RL_UNSETSTATE(RL_STATE_MOREINPUT);
309157184Sache
310119610Sache#if defined (HANDLE_MULTIBYTE)
311157184Sache  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
312157184Sache    c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
313119610Sache#endif
314119610Sache
315157184Sache  return c;
316157184Sache}
31721308Sache
318157184Sache/* Process just-read character C according to isearch context CXT.  Return
319157184Sache   -1 if the caller should just free the context and return, 0 if we should
320157184Sache   break out of the loop, and 1 if we should continue to read characters. */
321157184Sacheint
322157184Sache_rl_isearch_dispatch (cxt, c)
323157184Sache     _rl_search_cxt *cxt;
324157184Sache     int c;
325157184Sache{
326157184Sache  int n, wstart, wlen, limit, cval;
327157184Sache  rl_command_func_t *f;
32821308Sache
329157184Sache  f = (rl_command_func_t *)NULL;
330157184Sache
331157184Sache /* Translate the keys we do something with to opcodes. */
332157184Sache  if (c >= 0 && _rl_keymap[c].type == ISFUNC)
333157184Sache    {
334157184Sache      f = _rl_keymap[c].function;
33521308Sache
336157184Sache      if (f == rl_reverse_search_history)
337157184Sache	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
338157184Sache      else if (f == rl_forward_search_history)
339157184Sache	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
340157184Sache      else if (f == rl_rubout)
341157184Sache	cxt->lastc = -3;
342157184Sache      else if (c == CTRL ('G'))
343157184Sache	cxt->lastc = -4;
344157184Sache      else if (c == CTRL ('W'))	/* XXX */
345157184Sache	cxt->lastc = -5;
346157184Sache      else if (c == CTRL ('Y'))	/* XXX */
347157184Sache	cxt->lastc = -6;
348157184Sache    }
349157184Sache
350157184Sache  /* The characters in isearch_terminators (set from the user-settable
351157184Sache     variable isearch-terminators) are used to terminate the search but
352157184Sache     not subsequently execute the character as a command.  The default
353157184Sache     value is "\033\012" (ESC and C-J). */
354157184Sache  if (strchr (cxt->search_terminators, cxt->lastc))
355157184Sache    {
356157184Sache      /* ESC still terminates the search, but if there is pending
357157184Sache	 input or if input arrives within 0.1 seconds (on systems
358157184Sache	 with select(2)) it is used as a prefix character
359157184Sache	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
360157184Sache	 to allow the arrow keys to be used like ^F and ^B are used
361157184Sache	 to terminate the search and execute the movement command.
362157184Sache	 XXX - since _rl_input_available depends on the application-
363157184Sache	 settable keyboard timeout value, this could alternatively
364157184Sache	 use _rl_input_queued(100000) */
365157184Sache      if (cxt->lastc == ESC && _rl_input_available ())
366157184Sache	rl_execute_next (ESC);
367157184Sache      return (0);
368157184Sache    }
369157184Sache
370119610Sache#define ENDSRCH_CHAR(c) \
371119610Sache  ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
372119610Sache
373119610Sache#if defined (HANDLE_MULTIBYTE)
374157184Sache  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
375157184Sache    {
376157184Sache      if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
37721308Sache	{
37875406Sache	  /* This sets rl_pending_input to c; it will be picked up the next
37975406Sache	     time rl_read_key is called. */
380157184Sache	  rl_execute_next (cxt->lastc);
381157184Sache	  return (0);
38221308Sache	}
383157184Sache    }
384157184Sache  else
385157184Sache#endif
386157184Sache    if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
387157184Sache      {
388157184Sache	/* This sets rl_pending_input to LASTC; it will be picked up the next
389157184Sache	   time rl_read_key is called. */
390157184Sache	rl_execute_next (cxt->lastc);
391157184Sache	return (0);
392157184Sache      }
39321308Sache
394157184Sache  /* Now dispatch on the character.  `Opcodes' affect the search string or
395157184Sache     state.  Other characters are added to the string.  */
396157184Sache  switch (cxt->lastc)
397157184Sache    {
398157184Sache    /* search again */
399157184Sache    case -1:
400157184Sache      if (cxt->search_string_index == 0)
40121308Sache	{
402157184Sache	  if (last_isearch_string)
403119610Sache	    {
404157184Sache	      cxt->search_string_size = 64 + last_isearch_string_len;
405157184Sache	      cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
406157184Sache	      strcpy (cxt->search_string, last_isearch_string);
407157184Sache	      cxt->search_string_index = last_isearch_string_len;
408157184Sache	      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
409157184Sache	      break;
410119610Sache	    }
411157184Sache	  return (1);
412157184Sache	}
413157184Sache      else if (cxt->sflags & SF_REVERSE)
414157184Sache	cxt->sline_index--;
415157184Sache      else if (cxt->sline_index != cxt->sline_len)
416157184Sache	cxt->sline_index++;
417157184Sache      else
418157184Sache	rl_ding ();
419157184Sache      break;
42021308Sache
421157184Sache    /* switch directions */
422157184Sache    case -2:
423157184Sache      cxt->direction = -cxt->direction;
424157184Sache      if (cxt->direction < 0)
425157184Sache	cxt->sflags |= SF_REVERSE;
426157184Sache      else
427157184Sache	cxt->sflags &= ~SF_REVERSE;
428157184Sache      break;
42921308Sache
430157184Sache    /* delete character from search string. */
431157184Sache    case -3:	/* C-H, DEL */
432157184Sache      /* This is tricky.  To do this right, we need to keep a
433157184Sache	 stack of search positions for the current search, with
434157184Sache	 sentinels marking the beginning and end.  But this will
435157184Sache	 do until we have a real isearch-undo. */
436157184Sache      if (cxt->search_string_index == 0)
437157184Sache	rl_ding ();
438157184Sache      else
439157184Sache	cxt->search_string[--cxt->search_string_index] = '\0';
440157184Sache      break;
441119610Sache
442157184Sache    case -4:	/* C-G, abort */
443157184Sache      rl_replace_line (cxt->lines[cxt->save_line], 0);
444157184Sache      rl_point = cxt->save_point;
445157184Sache      rl_mark = cxt->save_mark;
446157184Sache      rl_restore_prompt();
447157184Sache      rl_clear_message ();
448119610Sache
449157184Sache      return -1;
45021308Sache
451157184Sache    case -5:	/* C-W */
452157184Sache      /* skip over portion of line we already matched and yank word */
453157184Sache      wstart = rl_point + cxt->search_string_index;
454157184Sache      if (wstart >= rl_end)
455157184Sache	{
456157184Sache	  rl_ding ();
457157184Sache	  break;
458157184Sache	}
459119610Sache
460157184Sache      /* if not in a word, move to one. */
461157184Sache      cval = _rl_char_value (rl_line_buffer, wstart);
462157184Sache      if (_rl_walphabetic (cval) == 0)
463157184Sache	{
464157184Sache	  rl_ding ();
46535486Sache	  break;
466157184Sache	}
467157184Sache      n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
468157184Sache      while (n < rl_end)
469157184Sache	{
470157184Sache	  cval = _rl_char_value (rl_line_buffer, n);
471157184Sache	  if (_rl_walphabetic (cval) == 0)
472157184Sache	    break;
473157184Sache	  n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
474157184Sache	}
475157184Sache      wlen = n - wstart + 1;
476157184Sache      if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
477157184Sache	{
478157184Sache	  cxt->search_string_size += wlen + 1;
479157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
480157184Sache	}
481157184Sache      for (; wstart < n; wstart++)
482157184Sache	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
483157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
484157184Sache      break;
48535486Sache
486157184Sache    case -6:	/* C-Y */
487157184Sache      /* skip over portion of line we already matched and yank rest */
488157184Sache      wstart = rl_point + cxt->search_string_index;
489157184Sache      if (wstart >= rl_end)
490157184Sache	{
491157184Sache	  rl_ding ();
492119610Sache	  break;
493157184Sache	}
494157184Sache      n = rl_end - wstart + 1;
495157184Sache      if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
496157184Sache	{
497157184Sache	  cxt->search_string_size += n + 1;
498157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
499157184Sache	}
500157184Sache      for (n = wstart; n < rl_end; n++)
501157184Sache	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
502157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
503157184Sache      break;
504119610Sache
505157184Sache    /* Add character to search string and continue search. */
506157184Sache    default:
507157184Sache      if (cxt->search_string_index + 2 >= cxt->search_string_size)
508157184Sache	{
509157184Sache	  cxt->search_string_size += 128;
510157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
511157184Sache	}
512119610Sache#if defined (HANDLE_MULTIBYTE)
513157184Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
514157184Sache	{
515157184Sache	  int j, l;
516157184Sache	  for (j = 0, l = strlen (cxt->mb); j < l; )
517157184Sache	    cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
518157184Sache	}
519157184Sache      else
520157184Sache#endif
521157184Sache	cxt->search_string[cxt->search_string_index++] = c;
522157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
523157184Sache      break;
524157184Sache    }
525157184Sache
526157184Sache  for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
527157184Sache    {
528157184Sache      limit = cxt->sline_len - cxt->search_string_index + 1;
529157184Sache
530157184Sache      /* Search the current line. */
531157184Sache      while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
532157184Sache	{
533157184Sache	  if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
534119610Sache	    {
535157184Sache	      cxt->sflags |= SF_FOUND;
536157184Sache	      break;
537119610Sache	    }
538119610Sache	  else
539157184Sache	    cxt->sline_index += cxt->direction;
54021308Sache	}
541157184Sache      if (cxt->sflags & SF_FOUND)
542157184Sache	break;
54321308Sache
544157184Sache      /* Move to the next line, but skip new copies of the line
545157184Sache	 we just found and lines shorter than the string we're
546157184Sache	 searching for. */
547157184Sache      do
54821308Sache	{
549157184Sache	  /* Move to the next line. */
550157184Sache	  cxt->history_pos += cxt->direction;
55121308Sache
552157184Sache	  /* At limit for direction? */
553157184Sache	  if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
55421308Sache	    {
555157184Sache	      cxt->sflags |= SF_FAILED;
556157184Sache	      break;
55721308Sache	    }
55821308Sache
559157184Sache	  /* We will need these later. */
560157184Sache	  cxt->sline = cxt->lines[cxt->history_pos];
561157184Sache	  cxt->sline_len = strlen (cxt->sline);
562157184Sache	}
563157184Sache      while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
564157184Sache	     (cxt->search_string_index > cxt->sline_len));
56521308Sache
566157184Sache      if (cxt->sflags & SF_FAILED)
567157184Sache	break;
56821308Sache
569157184Sache      /* Now set up the line for searching... */
570157184Sache      cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
571157184Sache    }
57221308Sache
573157184Sache  if (cxt->sflags & SF_FAILED)
574157184Sache    {
575157184Sache      /* We cannot find the search string.  Ding the bell. */
576157184Sache      rl_ding ();
577157184Sache      cxt->history_pos = cxt->last_found_line;
578157184Sache      return 1;
579157184Sache    }
58021308Sache
581157184Sache  /* We have found the search string.  Just display it.  But don't
582157184Sache     actually move there in the history list until the user accepts
583157184Sache     the location. */
584157184Sache  if (cxt->sflags & SF_FOUND)
585157184Sache    {
586157184Sache      cxt->prev_line_found = cxt->lines[cxt->history_pos];
587157184Sache      rl_replace_line (cxt->lines[cxt->history_pos], 0);
588157184Sache      rl_point = cxt->sline_index;
589157184Sache      cxt->last_found_line = cxt->history_pos;
590157184Sache      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
591157184Sache    }
59221308Sache
593157184Sache  return 1;
594157184Sache}
59521308Sache
596157184Sachestatic int
597157184Sache_rl_isearch_cleanup (cxt, r)
598157184Sache     _rl_search_cxt *cxt;
599157184Sache     int r;
600157184Sache{
601157184Sache  if (r >= 0)
602157184Sache    _rl_isearch_fini (cxt);
603157184Sache  _rl_scxt_dispose (cxt, 0);
604157184Sache  _rl_iscxt = 0;
60521308Sache
606157184Sache  RL_UNSETSTATE(RL_STATE_ISEARCH);
60721308Sache
608157184Sache  return (r != 0);
609157184Sache}
61021308Sache
611157184Sache/* Search through the history looking for an interactively typed string.
612157184Sache   This is analogous to i-search.  We start the search in the current line.
613157184Sache   DIRECTION is which direction to search; >= 0 means forward, < 0 means
614157184Sache   backwards. */
615157184Sachestatic int
616157184Sacherl_search_history (direction, invoking_key)
617157184Sache     int direction, invoking_key;
618157184Sache{
619157184Sache  _rl_search_cxt *cxt;		/* local for now, but saved globally */
620157184Sache  int c, r;
62121308Sache
622157184Sache  RL_SETSTATE(RL_STATE_ISEARCH);
623157184Sache  cxt = _rl_isearch_init (direction);
62421308Sache
625157184Sache  rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
62621308Sache
627157184Sache  /* If we are using the callback interface, all we do is set up here and
628157184Sache      return.  The key is that we leave RL_STATE_ISEARCH set. */
629157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
630157184Sache    return (0);
631157184Sache
632157184Sache  r = -1;
633157184Sache  for (;;)
634119610Sache    {
635157184Sache      c = _rl_search_getchar (cxt);
636157184Sache      /* We might want to handle EOF here (c == 0) */
637157184Sache      r = _rl_isearch_dispatch (cxt, cxt->lastc);
638157184Sache      if (r <= 0)
639157184Sache        break;
640119610Sache    }
641119610Sache
642157184Sache  /* The searching is over.  The user may have found the string that she
643157184Sache     was looking for, or else she may have exited a failing search.  If
644157184Sache     LINE_INDEX is -1, then that shows that the string searched for was
645157184Sache     not found.  We use this to determine where to place rl_point. */
646157184Sache  return (_rl_isearch_cleanup (cxt, r));
647157184Sache}
648119610Sache
649157184Sache#if defined (READLINE_CALLBACKS)
650157184Sache/* Called from the callback functions when we are ready to read a key.  The
651157184Sache   callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
652157184Sache   If _rl_isearch_dispatch finishes searching, this function is responsible
653157184Sache   for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
654157184Sacheint
655157184Sache_rl_isearch_callback (cxt)
656157184Sache     _rl_search_cxt *cxt;
657157184Sache{
658157184Sache  int c, r;
65921308Sache
660157184Sache  c = _rl_search_getchar (cxt);
661157184Sache  /* We might want to handle EOF here */
662157184Sache  r = _rl_isearch_dispatch (cxt, cxt->lastc);
66321308Sache
664157184Sache  return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
66521308Sache}
666157184Sache#endif
667