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;
330173403Sache
331173403Sache  if (c < 0)
332173403Sache    {
333173403Sache      cxt->sflags |= SF_FAILED;
334173403Sache      cxt->history_pos = cxt->last_found_line;
335173403Sache      return -1;
336173403Sache    }
337173403Sache
338173403Sache  /* Translate the keys we do something with to opcodes. */
339157184Sache  if (c >= 0 && _rl_keymap[c].type == ISFUNC)
340157184Sache    {
341157184Sache      f = _rl_keymap[c].function;
34221308Sache
343157184Sache      if (f == rl_reverse_search_history)
344157184Sache	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
345157184Sache      else if (f == rl_forward_search_history)
346157184Sache	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
347157184Sache      else if (f == rl_rubout)
348157184Sache	cxt->lastc = -3;
349157184Sache      else if (c == CTRL ('G'))
350157184Sache	cxt->lastc = -4;
351157184Sache      else if (c == CTRL ('W'))	/* XXX */
352157184Sache	cxt->lastc = -5;
353157184Sache      else if (c == CTRL ('Y'))	/* XXX */
354157184Sache	cxt->lastc = -6;
355157184Sache    }
356157184Sache
357157184Sache  /* The characters in isearch_terminators (set from the user-settable
358157184Sache     variable isearch-terminators) are used to terminate the search but
359157184Sache     not subsequently execute the character as a command.  The default
360157184Sache     value is "\033\012" (ESC and C-J). */
361157184Sache  if (strchr (cxt->search_terminators, cxt->lastc))
362157184Sache    {
363157184Sache      /* ESC still terminates the search, but if there is pending
364157184Sache	 input or if input arrives within 0.1 seconds (on systems
365157184Sache	 with select(2)) it is used as a prefix character
366157184Sache	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
367157184Sache	 to allow the arrow keys to be used like ^F and ^B are used
368157184Sache	 to terminate the search and execute the movement command.
369157184Sache	 XXX - since _rl_input_available depends on the application-
370157184Sache	 settable keyboard timeout value, this could alternatively
371157184Sache	 use _rl_input_queued(100000) */
372157184Sache      if (cxt->lastc == ESC && _rl_input_available ())
373157184Sache	rl_execute_next (ESC);
374157184Sache      return (0);
375157184Sache    }
376157184Sache
377119610Sache#define ENDSRCH_CHAR(c) \
378119610Sache  ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
379119610Sache
380119610Sache#if defined (HANDLE_MULTIBYTE)
381157184Sache  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
382157184Sache    {
383157184Sache      if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
38421308Sache	{
38575406Sache	  /* This sets rl_pending_input to c; it will be picked up the next
38675406Sache	     time rl_read_key is called. */
387157184Sache	  rl_execute_next (cxt->lastc);
388157184Sache	  return (0);
38921308Sache	}
390157184Sache    }
391157184Sache  else
392157184Sache#endif
393157184Sache    if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
394157184Sache      {
395157184Sache	/* This sets rl_pending_input to LASTC; it will be picked up the next
396157184Sache	   time rl_read_key is called. */
397157184Sache	rl_execute_next (cxt->lastc);
398157184Sache	return (0);
399157184Sache      }
40021308Sache
401157184Sache  /* Now dispatch on the character.  `Opcodes' affect the search string or
402157184Sache     state.  Other characters are added to the string.  */
403157184Sache  switch (cxt->lastc)
404157184Sache    {
405157184Sache    /* search again */
406157184Sache    case -1:
407157184Sache      if (cxt->search_string_index == 0)
40821308Sache	{
409157184Sache	  if (last_isearch_string)
410119610Sache	    {
411157184Sache	      cxt->search_string_size = 64 + last_isearch_string_len;
412157184Sache	      cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
413157184Sache	      strcpy (cxt->search_string, last_isearch_string);
414157184Sache	      cxt->search_string_index = last_isearch_string_len;
415157184Sache	      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
416157184Sache	      break;
417119610Sache	    }
418157184Sache	  return (1);
419157184Sache	}
420157184Sache      else if (cxt->sflags & SF_REVERSE)
421157184Sache	cxt->sline_index--;
422157184Sache      else if (cxt->sline_index != cxt->sline_len)
423157184Sache	cxt->sline_index++;
424157184Sache      else
425157184Sache	rl_ding ();
426157184Sache      break;
42721308Sache
428157184Sache    /* switch directions */
429157184Sache    case -2:
430157184Sache      cxt->direction = -cxt->direction;
431157184Sache      if (cxt->direction < 0)
432157184Sache	cxt->sflags |= SF_REVERSE;
433157184Sache      else
434157184Sache	cxt->sflags &= ~SF_REVERSE;
435157184Sache      break;
43621308Sache
437157184Sache    /* delete character from search string. */
438157184Sache    case -3:	/* C-H, DEL */
439157184Sache      /* This is tricky.  To do this right, we need to keep a
440157184Sache	 stack of search positions for the current search, with
441157184Sache	 sentinels marking the beginning and end.  But this will
442157184Sache	 do until we have a real isearch-undo. */
443157184Sache      if (cxt->search_string_index == 0)
444157184Sache	rl_ding ();
445157184Sache      else
446157184Sache	cxt->search_string[--cxt->search_string_index] = '\0';
447157184Sache      break;
448119610Sache
449157184Sache    case -4:	/* C-G, abort */
450157184Sache      rl_replace_line (cxt->lines[cxt->save_line], 0);
451157184Sache      rl_point = cxt->save_point;
452157184Sache      rl_mark = cxt->save_mark;
453157184Sache      rl_restore_prompt();
454157184Sache      rl_clear_message ();
455119610Sache
456157184Sache      return -1;
45721308Sache
458157184Sache    case -5:	/* C-W */
459157184Sache      /* skip over portion of line we already matched and yank word */
460157184Sache      wstart = rl_point + cxt->search_string_index;
461157184Sache      if (wstart >= rl_end)
462157184Sache	{
463157184Sache	  rl_ding ();
464157184Sache	  break;
465157184Sache	}
466119610Sache
467157184Sache      /* if not in a word, move to one. */
468157184Sache      cval = _rl_char_value (rl_line_buffer, wstart);
469157184Sache      if (_rl_walphabetic (cval) == 0)
470157184Sache	{
471157184Sache	  rl_ding ();
47235486Sache	  break;
473157184Sache	}
474157184Sache      n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
475157184Sache      while (n < rl_end)
476157184Sache	{
477157184Sache	  cval = _rl_char_value (rl_line_buffer, n);
478157184Sache	  if (_rl_walphabetic (cval) == 0)
479157184Sache	    break;
480157184Sache	  n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
481157184Sache	}
482157184Sache      wlen = n - wstart + 1;
483157184Sache      if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
484157184Sache	{
485157184Sache	  cxt->search_string_size += wlen + 1;
486157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
487157184Sache	}
488157184Sache      for (; wstart < n; wstart++)
489157184Sache	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
490157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
491157184Sache      break;
49235486Sache
493157184Sache    case -6:	/* C-Y */
494157184Sache      /* skip over portion of line we already matched and yank rest */
495157184Sache      wstart = rl_point + cxt->search_string_index;
496157184Sache      if (wstart >= rl_end)
497157184Sache	{
498157184Sache	  rl_ding ();
499119610Sache	  break;
500157184Sache	}
501157184Sache      n = rl_end - wstart + 1;
502157184Sache      if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
503157184Sache	{
504157184Sache	  cxt->search_string_size += n + 1;
505157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
506157184Sache	}
507157184Sache      for (n = wstart; n < rl_end; n++)
508157184Sache	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
509157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
510157184Sache      break;
511119610Sache
512157184Sache    /* Add character to search string and continue search. */
513157184Sache    default:
514157184Sache      if (cxt->search_string_index + 2 >= cxt->search_string_size)
515157184Sache	{
516157184Sache	  cxt->search_string_size += 128;
517157184Sache	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
518157184Sache	}
519119610Sache#if defined (HANDLE_MULTIBYTE)
520157184Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
521157184Sache	{
522157184Sache	  int j, l;
523157184Sache	  for (j = 0, l = strlen (cxt->mb); j < l; )
524157184Sache	    cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
525157184Sache	}
526157184Sache      else
527157184Sache#endif
528157184Sache	cxt->search_string[cxt->search_string_index++] = c;
529157184Sache      cxt->search_string[cxt->search_string_index] = '\0';
530157184Sache      break;
531157184Sache    }
532157184Sache
533157184Sache  for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
534157184Sache    {
535157184Sache      limit = cxt->sline_len - cxt->search_string_index + 1;
536157184Sache
537157184Sache      /* Search the current line. */
538157184Sache      while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
539157184Sache	{
540157184Sache	  if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
541119610Sache	    {
542157184Sache	      cxt->sflags |= SF_FOUND;
543157184Sache	      break;
544119610Sache	    }
545119610Sache	  else
546157184Sache	    cxt->sline_index += cxt->direction;
54721308Sache	}
548157184Sache      if (cxt->sflags & SF_FOUND)
549157184Sache	break;
55021308Sache
551157184Sache      /* Move to the next line, but skip new copies of the line
552157184Sache	 we just found and lines shorter than the string we're
553157184Sache	 searching for. */
554157184Sache      do
55521308Sache	{
556157184Sache	  /* Move to the next line. */
557157184Sache	  cxt->history_pos += cxt->direction;
55821308Sache
559157184Sache	  /* At limit for direction? */
560157184Sache	  if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
56121308Sache	    {
562157184Sache	      cxt->sflags |= SF_FAILED;
563157184Sache	      break;
56421308Sache	    }
56521308Sache
566157184Sache	  /* We will need these later. */
567157184Sache	  cxt->sline = cxt->lines[cxt->history_pos];
568157184Sache	  cxt->sline_len = strlen (cxt->sline);
569157184Sache	}
570157184Sache      while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
571157184Sache	     (cxt->search_string_index > cxt->sline_len));
57221308Sache
573157184Sache      if (cxt->sflags & SF_FAILED)
574157184Sache	break;
57521308Sache
576157184Sache      /* Now set up the line for searching... */
577157184Sache      cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
578157184Sache    }
57921308Sache
580157184Sache  if (cxt->sflags & SF_FAILED)
581157184Sache    {
582157184Sache      /* We cannot find the search string.  Ding the bell. */
583157184Sache      rl_ding ();
584157184Sache      cxt->history_pos = cxt->last_found_line;
585157184Sache      return 1;
586157184Sache    }
58721308Sache
588157184Sache  /* We have found the search string.  Just display it.  But don't
589157184Sache     actually move there in the history list until the user accepts
590157184Sache     the location. */
591157184Sache  if (cxt->sflags & SF_FOUND)
592157184Sache    {
593157184Sache      cxt->prev_line_found = cxt->lines[cxt->history_pos];
594157184Sache      rl_replace_line (cxt->lines[cxt->history_pos], 0);
595157184Sache      rl_point = cxt->sline_index;
596157184Sache      cxt->last_found_line = cxt->history_pos;
597157184Sache      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
598157184Sache    }
59921308Sache
600157184Sache  return 1;
601157184Sache}
60221308Sache
603157184Sachestatic int
604157184Sache_rl_isearch_cleanup (cxt, r)
605157184Sache     _rl_search_cxt *cxt;
606157184Sache     int r;
607157184Sache{
608157184Sache  if (r >= 0)
609157184Sache    _rl_isearch_fini (cxt);
610157184Sache  _rl_scxt_dispose (cxt, 0);
611157184Sache  _rl_iscxt = 0;
61221308Sache
613157184Sache  RL_UNSETSTATE(RL_STATE_ISEARCH);
61421308Sache
615157184Sache  return (r != 0);
616157184Sache}
61721308Sache
618157184Sache/* Search through the history looking for an interactively typed string.
619157184Sache   This is analogous to i-search.  We start the search in the current line.
620157184Sache   DIRECTION is which direction to search; >= 0 means forward, < 0 means
621157184Sache   backwards. */
622157184Sachestatic int
623157184Sacherl_search_history (direction, invoking_key)
624157184Sache     int direction, invoking_key;
625157184Sache{
626157184Sache  _rl_search_cxt *cxt;		/* local for now, but saved globally */
627157184Sache  int c, r;
62821308Sache
629157184Sache  RL_SETSTATE(RL_STATE_ISEARCH);
630157184Sache  cxt = _rl_isearch_init (direction);
63121308Sache
632157184Sache  rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
63321308Sache
634157184Sache  /* If we are using the callback interface, all we do is set up here and
635157184Sache      return.  The key is that we leave RL_STATE_ISEARCH set. */
636157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
637157184Sache    return (0);
638157184Sache
639157184Sache  r = -1;
640157184Sache  for (;;)
641119610Sache    {
642157184Sache      c = _rl_search_getchar (cxt);
643157184Sache      /* We might want to handle EOF here (c == 0) */
644157184Sache      r = _rl_isearch_dispatch (cxt, cxt->lastc);
645157184Sache      if (r <= 0)
646157184Sache        break;
647119610Sache    }
648119610Sache
649157184Sache  /* The searching is over.  The user may have found the string that she
650157184Sache     was looking for, or else she may have exited a failing search.  If
651157184Sache     LINE_INDEX is -1, then that shows that the string searched for was
652157184Sache     not found.  We use this to determine where to place rl_point. */
653157184Sache  return (_rl_isearch_cleanup (cxt, r));
654157184Sache}
655119610Sache
656157184Sache#if defined (READLINE_CALLBACKS)
657157184Sache/* Called from the callback functions when we are ready to read a key.  The
658157184Sache   callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
659157184Sache   If _rl_isearch_dispatch finishes searching, this function is responsible
660157184Sache   for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
661157184Sacheint
662157184Sache_rl_isearch_callback (cxt)
663157184Sache     _rl_search_cxt *cxt;
664157184Sache{
665157184Sache  int c, r;
66621308Sache
667157184Sache  c = _rl_search_getchar (cxt);
668157184Sache  /* We might want to handle EOF here */
669157184Sache  r = _rl_isearch_dispatch (cxt, cxt->lastc);
67021308Sache
671157184Sache  return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
67221308Sache}
673157184Sache#endif
674