isearch.c revision 173404
1210284Sjmallett/* **************************************************************** */
2215990Sjmallett/*								    */
3215990Sjmallett/*			I-Search and Searching			    */
4210284Sjmallett/*								    */
5210284Sjmallett/* **************************************************************** */
6215990Sjmallett
7215990Sjmallett/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
8215990Sjmallett
9210284Sjmallett   This file contains the Readline Library (the Library), a set of
10215990Sjmallett   routines for providing Emacs style line input to programs that ask
11215990Sjmallett   for it.
12210284Sjmallett
13215990Sjmallett   The Library is free software; you can redistribute it and/or modify
14215990Sjmallett   it under the terms of the GNU General Public License as published by
15215990Sjmallett   the Free Software Foundation; either version 2, or (at your option)
16215990Sjmallett   any later version.
17210284Sjmallett
18215990Sjmallett   The Library is distributed in the hope that it will be useful, but
19215990Sjmallett   WITHOUT ANY WARRANTY; without even the implied warranty of
20215990Sjmallett   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21215990Sjmallett   General Public License for more details.
22210284Sjmallett
23215990Sjmallett   The GNU General Public License is often shipped with GNU software, and
24215990Sjmallett   is generally kept in a file called COPYING or LICENSE.  If you do not
25215990Sjmallett   have a copy of the license, write to the Free Software Foundation,
26215990Sjmallett   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
27210284Sjmallett#define READLINE_LIBRARY
28215990Sjmallett
29215990Sjmallett#if defined (HAVE_CONFIG_H)
30215990Sjmallett#  include <config.h>
31215990Sjmallett#endif
32215990Sjmallett
33215990Sjmallett#include <sys/types.h>
34215990Sjmallett
35215990Sjmallett#include <stdio.h>
36215990Sjmallett
37215990Sjmallett#if defined (HAVE_UNISTD_H)
38215990Sjmallett#  include <unistd.h>
39210284Sjmallett#endif
40210284Sjmallett
41210284Sjmallett#if defined (HAVE_STDLIB_H)
42210284Sjmallett#  include <stdlib.h>
43210284Sjmallett#else
44210284Sjmallett#  include "ansi_stdlib.h"
45210284Sjmallett#endif
46210284Sjmallett
47210284Sjmallett#include "rldefs.h"
48210284Sjmallett#include "rlmbutil.h"
49210284Sjmallett
50210284Sjmallett#include "readline.h"
51210284Sjmallett#include "history.h"
52210284Sjmallett
53210284Sjmallett#include "rlprivate.h"
54210284Sjmallett#include "xmalloc.h"
55210284Sjmallett
56210284Sjmallett/* Variables exported to other files in the readline library. */
57210284Sjmallettchar *_rl_isearch_terminators = (char *)NULL;
58210284Sjmallett
59210284Sjmallett_rl_search_cxt *_rl_iscxt = 0;
60210284Sjmallett
61210284Sjmallett/* Variables imported from other files in the readline library. */
62210284Sjmallettextern HIST_ENTRY *_rl_saved_line_for_history;
63210284Sjmallett
64215990Sjmallettstatic int rl_search_history PARAMS((int, int));
65210284Sjmallett
66210284Sjmallettstatic _rl_search_cxt *_rl_isearch_init PARAMS((int));
67210284Sjmallettstatic void _rl_isearch_fini PARAMS((_rl_search_cxt *));
68210284Sjmallettstatic int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int));
69210284Sjmallett
70210284Sjmallett/* Last line found by the current incremental search, so we don't `find'
71210284Sjmallett   identical lines many times in a row.  Now part of isearch context. */
72215990Sjmallett/* static char *prev_line_found; */
73215990Sjmallett
74210284Sjmallett/* Last search string and its length. */
75215990Sjmallettstatic char *last_isearch_string;
76210284Sjmallettstatic int last_isearch_string_len;
77210284Sjmallett
78210284Sjmallettstatic char *default_isearch_terminators = "\033\012";
79210284Sjmallett
80210284Sjmallett_rl_search_cxt *
81210284Sjmallett_rl_scxt_alloc (type, flags)
82210284Sjmallett     int type, flags;
83210284Sjmallett{
84210284Sjmallett  _rl_search_cxt *cxt;
85210284Sjmallett
86210284Sjmallett  cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt));
87210284Sjmallett
88210284Sjmallett  cxt->type = type;
89210284Sjmallett  cxt->sflags = flags;
90210284Sjmallett
91210284Sjmallett  cxt->search_string = 0;
92210284Sjmallett  cxt->search_string_size = cxt->search_string_index = 0;
93210284Sjmallett
94210284Sjmallett  cxt->lines = 0;
95210284Sjmallett  cxt->allocated_line = 0;
96210284Sjmallett  cxt->hlen = cxt->hindex = 0;
97210284Sjmallett
98210284Sjmallett  cxt->save_point = rl_point;
99210284Sjmallett  cxt->save_mark = rl_mark;
100210284Sjmallett  cxt->save_line = where_history ();
101210284Sjmallett  cxt->last_found_line = cxt->save_line;
102210284Sjmallett  cxt->prev_line_found = 0;
103210284Sjmallett
104210284Sjmallett  cxt->save_undo_list = 0;
105210284Sjmallett
106210284Sjmallett  cxt->history_pos = 0;
107210284Sjmallett  cxt->direction = 0;
108210284Sjmallett
109210284Sjmallett  cxt->lastc = 0;
110210284Sjmallett
111210284Sjmallett  cxt->sline = 0;
112210284Sjmallett  cxt->sline_len = cxt->sline_index = 0;
113210284Sjmallett
114210284Sjmallett  cxt->search_terminators = 0;
115210284Sjmallett
116210284Sjmallett  return cxt;
117210284Sjmallett}
118210284Sjmallett
119210284Sjmallettvoid
120210284Sjmallett_rl_scxt_dispose (cxt, flags)
121210284Sjmallett     _rl_search_cxt *cxt;
122210284Sjmallett     int flags;
123210284Sjmallett{
124210284Sjmallett  FREE (cxt->search_string);
125210284Sjmallett  FREE (cxt->allocated_line);
126210284Sjmallett  FREE (cxt->lines);
127210284Sjmallett
128210284Sjmallett  free (cxt);
129210284Sjmallett}
130210284Sjmallett
131210284Sjmallett/* Search backwards through the history looking for a string which is typed
132210284Sjmallett   interactively.  Start with the current line. */
133210284Sjmallettint
134210284Sjmallettrl_reverse_search_history (sign, key)
135210284Sjmallett     int sign, key;
136210284Sjmallett{
137210284Sjmallett  return (rl_search_history (-sign, key));
138210284Sjmallett}
139210284Sjmallett
140210284Sjmallett/* Search forwards through the history looking for a string which is typed
141210284Sjmallett   interactively.  Start with the current line. */
142210284Sjmallettint
143210284Sjmallettrl_forward_search_history (sign, key)
144210284Sjmallett     int sign, key;
145210284Sjmallett{
146210284Sjmallett  return (rl_search_history (sign, key));
147210284Sjmallett}
148210284Sjmallett
149210284Sjmallett/* Display the current state of the search in the echo-area.
150210284Sjmallett   SEARCH_STRING contains the string that is being searched for,
151210284Sjmallett   DIRECTION is zero for forward, or non-zero for reverse,
152210284Sjmallett   WHERE is the history list number of the current line.  If it is
153210284Sjmallett   -1, then this line is the starting one. */
154210284Sjmallettstatic void
155210284Sjmallettrl_display_search (search_string, reverse_p, where)
156210284Sjmallett     char *search_string;
157210284Sjmallett     int reverse_p, where;
158210284Sjmallett{
159210284Sjmallett  char *message;
160210284Sjmallett  int msglen, searchlen;
161210284Sjmallett
162210284Sjmallett  searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
163210284Sjmallett
164210284Sjmallett  message = (char *)xmalloc (searchlen + 33);
165210284Sjmallett  msglen = 0;
166210284Sjmallett
167210284Sjmallett#if defined (NOTDEF)
168210284Sjmallett  if (where != -1)
169210284Sjmallett    {
170210284Sjmallett      sprintf (message, "[%d]", where + history_base);
171210284Sjmallett      msglen = strlen (message);
172210284Sjmallett    }
173210284Sjmallett#endif /* NOTDEF */
174210284Sjmallett
175210284Sjmallett  message[msglen++] = '(';
176210284Sjmallett
177210284Sjmallett  if (reverse_p)
178210284Sjmallett    {
179210284Sjmallett      strcpy (message + msglen, "reverse-");
180210284Sjmallett      msglen += 8;
181210284Sjmallett    }
182210284Sjmallett
183210284Sjmallett  strcpy (message + msglen, "i-search)`");
184210284Sjmallett  msglen += 10;
185210284Sjmallett
186210284Sjmallett  if (search_string)
187210284Sjmallett    {
188210284Sjmallett      strcpy (message + msglen, search_string);
189210284Sjmallett      msglen += searchlen;
190210284Sjmallett    }
191210284Sjmallett
192210284Sjmallett  strcpy (message + msglen, "': ");
193210284Sjmallett
194210284Sjmallett  rl_message ("%s", message);
195210284Sjmallett  free (message);
196210284Sjmallett  (*rl_redisplay_function) ();
197210284Sjmallett}
198210284Sjmallett
199210284Sjmallettstatic _rl_search_cxt *
200210284Sjmallett_rl_isearch_init (direction)
201210284Sjmallett     int direction;
202210284Sjmallett{
203210284Sjmallett  _rl_search_cxt *cxt;
204210284Sjmallett  register int i;
205210284Sjmallett  HIST_ENTRY **hlist;
206210284Sjmallett
207210284Sjmallett  cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0);
208210284Sjmallett  if (direction < 0)
209210284Sjmallett    cxt->sflags |= SF_REVERSE;
210210284Sjmallett
211210284Sjmallett  cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
212210284Sjmallett						: default_isearch_terminators;
213210284Sjmallett
214210284Sjmallett  /* Create an arrary of pointers to the lines that we want to search. */
215210284Sjmallett  hlist = history_list ();
216210284Sjmallett  rl_maybe_replace_line ();
217210284Sjmallett  i = 0;
218210284Sjmallett  if (hlist)
219210284Sjmallett    for (i = 0; hlist[i]; i++);
220210284Sjmallett
221210284Sjmallett  /* Allocate space for this many lines, +1 for the current input line,
222210284Sjmallett     and remember those lines. */
223210284Sjmallett  cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *));
224210284Sjmallett  for (i = 0; i < cxt->hlen; i++)
225210284Sjmallett    cxt->lines[i] = hlist[i]->line;
226210284Sjmallett
227210284Sjmallett  if (_rl_saved_line_for_history)
228210284Sjmallett    cxt->lines[i] = _rl_saved_line_for_history->line;
229210284Sjmallett  else
230210284Sjmallett    {
231210284Sjmallett      /* Keep track of this so we can free it. */
232210284Sjmallett      cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
233210284Sjmallett      strcpy (cxt->allocated_line, &rl_line_buffer[0]);
234210284Sjmallett      cxt->lines[i] = cxt->allocated_line;
235210284Sjmallett    }
236210284Sjmallett
237210284Sjmallett  cxt->hlen++;
238210284Sjmallett
239210284Sjmallett  /* The line where we start the search. */
240210284Sjmallett  cxt->history_pos = cxt->save_line;
241210284Sjmallett
242210284Sjmallett  rl_save_prompt ();
243210284Sjmallett
244210284Sjmallett  /* Initialize search parameters. */
245210284Sjmallett  cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128);
246210284Sjmallett  cxt->search_string[cxt->search_string_index = 0] = '\0';
247210284Sjmallett
248210284Sjmallett  /* Normalize DIRECTION into 1 or -1. */
249210284Sjmallett  cxt->direction = (direction >= 0) ? 1 : -1;
250210284Sjmallett
251210284Sjmallett  cxt->sline = rl_line_buffer;
252210284Sjmallett  cxt->sline_len = strlen (cxt->sline);
253210284Sjmallett  cxt->sline_index = rl_point;
254210284Sjmallett
255210284Sjmallett  _rl_iscxt = cxt;		/* save globally */
256210284Sjmallett
257210284Sjmallett  return cxt;
258210284Sjmallett}
259210284Sjmallett
260210284Sjmallettstatic void
261210284Sjmallett_rl_isearch_fini (cxt)
262210284Sjmallett     _rl_search_cxt *cxt;
263210284Sjmallett{
264210284Sjmallett  /* First put back the original state. */
265210284Sjmallett  strcpy (rl_line_buffer, cxt->lines[cxt->save_line]);
266210284Sjmallett
267210284Sjmallett  rl_restore_prompt ();
268210284Sjmallett
269210284Sjmallett  /* Save the search string for possible later use. */
270210284Sjmallett  FREE (last_isearch_string);
271210284Sjmallett  last_isearch_string = cxt->search_string;
272210284Sjmallett  last_isearch_string_len = cxt->search_string_index;
273210284Sjmallett  cxt->search_string = 0;
274210284Sjmallett
275210284Sjmallett  if (cxt->last_found_line < cxt->save_line)
276210284Sjmallett    rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0);
277210284Sjmallett  else
278210284Sjmallett    rl_get_next_history (cxt->last_found_line - cxt->save_line, 0);
279210284Sjmallett
280210284Sjmallett  /* If the string was not found, put point at the end of the last matching
281210284Sjmallett     line.  If last_found_line == orig_line, we didn't find any matching
282210284Sjmallett     history lines at all, so put point back in its original position. */
283210284Sjmallett  if (cxt->sline_index < 0)
284210284Sjmallett    {
285210284Sjmallett      if (cxt->last_found_line == cxt->save_line)
286210284Sjmallett	cxt->sline_index = cxt->save_point;
287210284Sjmallett      else
288210284Sjmallett	cxt->sline_index = strlen (rl_line_buffer);
289210284Sjmallett      rl_mark = cxt->save_mark;
290210284Sjmallett    }
291210284Sjmallett
292210284Sjmallett  rl_point = cxt->sline_index;
293210284Sjmallett  /* Don't worry about where to put the mark here; rl_get_previous_history
294210284Sjmallett     and rl_get_next_history take care of it. */
295210284Sjmallett
296210284Sjmallett  rl_clear_message ();
297210284Sjmallett}
298210284Sjmallett
299210284Sjmallettint
300210284Sjmallett_rl_search_getchar (cxt)
301210284Sjmallett     _rl_search_cxt *cxt;
302210284Sjmallett{
303210284Sjmallett  int c;
304210284Sjmallett
305210284Sjmallett  /* Read a key and decide how to proceed. */
306210284Sjmallett  RL_SETSTATE(RL_STATE_MOREINPUT);
307210284Sjmallett  c = cxt->lastc = rl_read_key ();
308210284Sjmallett  RL_UNSETSTATE(RL_STATE_MOREINPUT);
309210284Sjmallett
310210284Sjmallett#if defined (HANDLE_MULTIBYTE)
311210284Sjmallett  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
312210284Sjmallett    c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
313210284Sjmallett#endif
314210284Sjmallett
315210284Sjmallett  return c;
316210284Sjmallett}
317210284Sjmallett
318210284Sjmallett/* Process just-read character C according to isearch context CXT.  Return
319210284Sjmallett   -1 if the caller should just free the context and return, 0 if we should
320210284Sjmallett   break out of the loop, and 1 if we should continue to read characters. */
321210284Sjmallettint
322210284Sjmallett_rl_isearch_dispatch (cxt, c)
323210284Sjmallett     _rl_search_cxt *cxt;
324210284Sjmallett     int c;
325210284Sjmallett{
326210284Sjmallett  int n, wstart, wlen, limit, cval;
327210284Sjmallett  rl_command_func_t *f;
328210284Sjmallett
329210284Sjmallett  f = (rl_command_func_t *)NULL;
330210284Sjmallett
331210284Sjmallett  if (c < 0)
332210284Sjmallett    {
333210284Sjmallett      cxt->sflags |= SF_FAILED;
334210284Sjmallett      cxt->history_pos = cxt->last_found_line;
335210284Sjmallett      return -1;
336210284Sjmallett    }
337210284Sjmallett
338210284Sjmallett  /* Translate the keys we do something with to opcodes. */
339210284Sjmallett  if (c >= 0 && _rl_keymap[c].type == ISFUNC)
340210284Sjmallett    {
341210284Sjmallett      f = _rl_keymap[c].function;
342210284Sjmallett
343210284Sjmallett      if (f == rl_reverse_search_history)
344210284Sjmallett	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
345210284Sjmallett      else if (f == rl_forward_search_history)
346210284Sjmallett	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
347210284Sjmallett      else if (f == rl_rubout)
348210284Sjmallett	cxt->lastc = -3;
349210284Sjmallett      else if (c == CTRL ('G'))
350210284Sjmallett	cxt->lastc = -4;
351210284Sjmallett      else if (c == CTRL ('W'))	/* XXX */
352210284Sjmallett	cxt->lastc = -5;
353210284Sjmallett      else if (c == CTRL ('Y'))	/* XXX */
354210284Sjmallett	cxt->lastc = -6;
355210284Sjmallett    }
356210284Sjmallett
357210284Sjmallett  /* The characters in isearch_terminators (set from the user-settable
358210284Sjmallett     variable isearch-terminators) are used to terminate the search but
359210284Sjmallett     not subsequently execute the character as a command.  The default
360210284Sjmallett     value is "\033\012" (ESC and C-J). */
361210284Sjmallett  if (strchr (cxt->search_terminators, cxt->lastc))
362210284Sjmallett    {
363210284Sjmallett      /* ESC still terminates the search, but if there is pending
364210284Sjmallett	 input or if input arrives within 0.1 seconds (on systems
365210284Sjmallett	 with select(2)) it is used as a prefix character
366210284Sjmallett	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
367210284Sjmallett	 to allow the arrow keys to be used like ^F and ^B are used
368210284Sjmallett	 to terminate the search and execute the movement command.
369210284Sjmallett	 XXX - since _rl_input_available depends on the application-
370210284Sjmallett	 settable keyboard timeout value, this could alternatively
371210284Sjmallett	 use _rl_input_queued(100000) */
372210284Sjmallett      if (cxt->lastc == ESC && _rl_input_available ())
373210284Sjmallett	rl_execute_next (ESC);
374210284Sjmallett      return (0);
375210284Sjmallett    }
376210284Sjmallett
377210284Sjmallett#define ENDSRCH_CHAR(c) \
378210284Sjmallett  ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
379210284Sjmallett
380210284Sjmallett#if defined (HANDLE_MULTIBYTE)
381210284Sjmallett  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
382210284Sjmallett    {
383210284Sjmallett      if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
384210284Sjmallett	{
385210284Sjmallett	  /* This sets rl_pending_input to c; it will be picked up the next
386210284Sjmallett	     time rl_read_key is called. */
387210284Sjmallett	  rl_execute_next (cxt->lastc);
388210284Sjmallett	  return (0);
389210284Sjmallett	}
390210284Sjmallett    }
391210284Sjmallett  else
392210284Sjmallett#endif
393210284Sjmallett    if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
394210284Sjmallett      {
395210284Sjmallett	/* This sets rl_pending_input to LASTC; it will be picked up the next
396210284Sjmallett	   time rl_read_key is called. */
397210284Sjmallett	rl_execute_next (cxt->lastc);
398210284Sjmallett	return (0);
399210284Sjmallett      }
400210284Sjmallett
401210284Sjmallett  /* Now dispatch on the character.  `Opcodes' affect the search string or
402210284Sjmallett     state.  Other characters are added to the string.  */
403210284Sjmallett  switch (cxt->lastc)
404210284Sjmallett    {
405210284Sjmallett    /* search again */
406210284Sjmallett    case -1:
407210284Sjmallett      if (cxt->search_string_index == 0)
408210284Sjmallett	{
409210284Sjmallett	  if (last_isearch_string)
410210284Sjmallett	    {
411210284Sjmallett	      cxt->search_string_size = 64 + last_isearch_string_len;
412210284Sjmallett	      cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
413210284Sjmallett	      strcpy (cxt->search_string, last_isearch_string);
414210284Sjmallett	      cxt->search_string_index = last_isearch_string_len;
415210284Sjmallett	      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
416210284Sjmallett	      break;
417210284Sjmallett	    }
418210284Sjmallett	  return (1);
419210284Sjmallett	}
420210284Sjmallett      else if (cxt->sflags & SF_REVERSE)
421210284Sjmallett	cxt->sline_index--;
422210284Sjmallett      else if (cxt->sline_index != cxt->sline_len)
423210284Sjmallett	cxt->sline_index++;
424210284Sjmallett      else
425210284Sjmallett	rl_ding ();
426210284Sjmallett      break;
427210284Sjmallett
428210284Sjmallett    /* switch directions */
429210284Sjmallett    case -2:
430210284Sjmallett      cxt->direction = -cxt->direction;
431210284Sjmallett      if (cxt->direction < 0)
432210284Sjmallett	cxt->sflags |= SF_REVERSE;
433210284Sjmallett      else
434210284Sjmallett	cxt->sflags &= ~SF_REVERSE;
435210284Sjmallett      break;
436210284Sjmallett
437210284Sjmallett    /* delete character from search string. */
438210284Sjmallett    case -3:	/* C-H, DEL */
439210284Sjmallett      /* This is tricky.  To do this right, we need to keep a
440210284Sjmallett	 stack of search positions for the current search, with
441210284Sjmallett	 sentinels marking the beginning and end.  But this will
442210284Sjmallett	 do until we have a real isearch-undo. */
443210284Sjmallett      if (cxt->search_string_index == 0)
444210284Sjmallett	rl_ding ();
445210284Sjmallett      else
446210284Sjmallett	cxt->search_string[--cxt->search_string_index] = '\0';
447210284Sjmallett      break;
448210284Sjmallett
449210284Sjmallett    case -4:	/* C-G, abort */
450210284Sjmallett      rl_replace_line (cxt->lines[cxt->save_line], 0);
451210284Sjmallett      rl_point = cxt->save_point;
452210284Sjmallett      rl_mark = cxt->save_mark;
453210284Sjmallett      rl_restore_prompt();
454210284Sjmallett      rl_clear_message ();
455210284Sjmallett
456210284Sjmallett      return -1;
457210284Sjmallett
458210284Sjmallett    case -5:	/* C-W */
459210284Sjmallett      /* skip over portion of line we already matched and yank word */
460210284Sjmallett      wstart = rl_point + cxt->search_string_index;
461210284Sjmallett      if (wstart >= rl_end)
462210284Sjmallett	{
463210284Sjmallett	  rl_ding ();
464210284Sjmallett	  break;
465210284Sjmallett	}
466210284Sjmallett
467210284Sjmallett      /* if not in a word, move to one. */
468210284Sjmallett      cval = _rl_char_value (rl_line_buffer, wstart);
469210284Sjmallett      if (_rl_walphabetic (cval) == 0)
470210284Sjmallett	{
471210284Sjmallett	  rl_ding ();
472210284Sjmallett	  break;
473210284Sjmallett	}
474210284Sjmallett      n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
475210284Sjmallett      while (n < rl_end)
476210284Sjmallett	{
477210284Sjmallett	  cval = _rl_char_value (rl_line_buffer, n);
478210284Sjmallett	  if (_rl_walphabetic (cval) == 0)
479210284Sjmallett	    break;
480210284Sjmallett	  n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
481210284Sjmallett	}
482210284Sjmallett      wlen = n - wstart + 1;
483210284Sjmallett      if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
484210284Sjmallett	{
485210284Sjmallett	  cxt->search_string_size += wlen + 1;
486210284Sjmallett	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
487210284Sjmallett	}
488210284Sjmallett      for (; wstart < n; wstart++)
489210284Sjmallett	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
490210284Sjmallett      cxt->search_string[cxt->search_string_index] = '\0';
491210284Sjmallett      break;
492210284Sjmallett
493210284Sjmallett    case -6:	/* C-Y */
494210284Sjmallett      /* skip over portion of line we already matched and yank rest */
495210284Sjmallett      wstart = rl_point + cxt->search_string_index;
496210284Sjmallett      if (wstart >= rl_end)
497210284Sjmallett	{
498210284Sjmallett	  rl_ding ();
499210284Sjmallett	  break;
500210284Sjmallett	}
501210284Sjmallett      n = rl_end - wstart + 1;
502210284Sjmallett      if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
503210284Sjmallett	{
504210284Sjmallett	  cxt->search_string_size += n + 1;
505210284Sjmallett	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
506210284Sjmallett	}
507210284Sjmallett      for (n = wstart; n < rl_end; n++)
508210284Sjmallett	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
509210284Sjmallett      cxt->search_string[cxt->search_string_index] = '\0';
510210284Sjmallett      break;
511210284Sjmallett
512210284Sjmallett    /* Add character to search string and continue search. */
513210284Sjmallett    default:
514210284Sjmallett      if (cxt->search_string_index + 2 >= cxt->search_string_size)
515210284Sjmallett	{
516210284Sjmallett	  cxt->search_string_size += 128;
517210284Sjmallett	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
518210284Sjmallett	}
519210284Sjmallett#if defined (HANDLE_MULTIBYTE)
520210284Sjmallett      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
521210284Sjmallett	{
522210284Sjmallett	  int j, l;
523210284Sjmallett	  for (j = 0, l = strlen (cxt->mb); j < l; )
524210284Sjmallett	    cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
525210284Sjmallett	}
526210284Sjmallett      else
527210284Sjmallett#endif
528210284Sjmallett	cxt->search_string[cxt->search_string_index++] = c;
529210284Sjmallett      cxt->search_string[cxt->search_string_index] = '\0';
530210284Sjmallett      break;
531210284Sjmallett    }
532210284Sjmallett
533210284Sjmallett  for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
534210284Sjmallett    {
535210284Sjmallett      limit = cxt->sline_len - cxt->search_string_index + 1;
536210284Sjmallett
537210284Sjmallett      /* Search the current line. */
538210284Sjmallett      while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
539210284Sjmallett	{
540210284Sjmallett	  if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
541210284Sjmallett	    {
542210284Sjmallett	      cxt->sflags |= SF_FOUND;
543210284Sjmallett	      break;
544210284Sjmallett	    }
545210284Sjmallett	  else
546210284Sjmallett	    cxt->sline_index += cxt->direction;
547210284Sjmallett	}
548210284Sjmallett      if (cxt->sflags & SF_FOUND)
549210284Sjmallett	break;
550210284Sjmallett
551210284Sjmallett      /* Move to the next line, but skip new copies of the line
552210284Sjmallett	 we just found and lines shorter than the string we're
553210284Sjmallett	 searching for. */
554210284Sjmallett      do
555210284Sjmallett	{
556210284Sjmallett	  /* Move to the next line. */
557210284Sjmallett	  cxt->history_pos += cxt->direction;
558210284Sjmallett
559210284Sjmallett	  /* At limit for direction? */
560210284Sjmallett	  if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
561210284Sjmallett	    {
562210284Sjmallett	      cxt->sflags |= SF_FAILED;
563210284Sjmallett	      break;
564210284Sjmallett	    }
565210284Sjmallett
566210284Sjmallett	  /* We will need these later. */
567210284Sjmallett	  cxt->sline = cxt->lines[cxt->history_pos];
568210284Sjmallett	  cxt->sline_len = strlen (cxt->sline);
569210284Sjmallett	}
570210284Sjmallett      while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
571210284Sjmallett	     (cxt->search_string_index > cxt->sline_len));
572210284Sjmallett
573210284Sjmallett      if (cxt->sflags & SF_FAILED)
574210284Sjmallett	break;
575210284Sjmallett
576210284Sjmallett      /* Now set up the line for searching... */
577210284Sjmallett      cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
578210284Sjmallett    }
579210284Sjmallett
580210284Sjmallett  if (cxt->sflags & SF_FAILED)
581210284Sjmallett    {
582210284Sjmallett      /* We cannot find the search string.  Ding the bell. */
583210284Sjmallett      rl_ding ();
584210284Sjmallett      cxt->history_pos = cxt->last_found_line;
585210284Sjmallett      return 1;
586210284Sjmallett    }
587210284Sjmallett
588210284Sjmallett  /* We have found the search string.  Just display it.  But don't
589210284Sjmallett     actually move there in the history list until the user accepts
590210284Sjmallett     the location. */
591210284Sjmallett  if (cxt->sflags & SF_FOUND)
592210284Sjmallett    {
593210284Sjmallett      cxt->prev_line_found = cxt->lines[cxt->history_pos];
594210284Sjmallett      rl_replace_line (cxt->lines[cxt->history_pos], 0);
595210284Sjmallett      rl_point = cxt->sline_index;
596210284Sjmallett      cxt->last_found_line = cxt->history_pos;
597210284Sjmallett      rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
598210284Sjmallett    }
599210284Sjmallett
600210284Sjmallett  return 1;
601210284Sjmallett}
602210284Sjmallett
603210284Sjmallettstatic int
604210284Sjmallett_rl_isearch_cleanup (cxt, r)
605210284Sjmallett     _rl_search_cxt *cxt;
606210284Sjmallett     int r;
607210284Sjmallett{
608210284Sjmallett  if (r >= 0)
609210284Sjmallett    _rl_isearch_fini (cxt);
610210284Sjmallett  _rl_scxt_dispose (cxt, 0);
611210284Sjmallett  _rl_iscxt = 0;
612210284Sjmallett
613210284Sjmallett  RL_UNSETSTATE(RL_STATE_ISEARCH);
614210284Sjmallett
615210284Sjmallett  return (r != 0);
616210284Sjmallett}
617210284Sjmallett
618210284Sjmallett/* Search through the history looking for an interactively typed string.
619210284Sjmallett   This is analogous to i-search.  We start the search in the current line.
620210284Sjmallett   DIRECTION is which direction to search; >= 0 means forward, < 0 means
621210284Sjmallett   backwards. */
622210284Sjmallettstatic int
623210284Sjmallettrl_search_history (direction, invoking_key)
624210284Sjmallett     int direction, invoking_key;
625210284Sjmallett{
626210284Sjmallett  _rl_search_cxt *cxt;		/* local for now, but saved globally */
627210284Sjmallett  int c, r;
628210284Sjmallett
629210284Sjmallett  RL_SETSTATE(RL_STATE_ISEARCH);
630210284Sjmallett  cxt = _rl_isearch_init (direction);
631210284Sjmallett
632210284Sjmallett  rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1);
633210284Sjmallett
634210284Sjmallett  /* If we are using the callback interface, all we do is set up here and
635210284Sjmallett      return.  The key is that we leave RL_STATE_ISEARCH set. */
636210284Sjmallett  if (RL_ISSTATE (RL_STATE_CALLBACK))
637210284Sjmallett    return (0);
638210284Sjmallett
639210284Sjmallett  r = -1;
640210284Sjmallett  for (;;)
641210284Sjmallett    {
642210284Sjmallett      c = _rl_search_getchar (cxt);
643210284Sjmallett      /* We might want to handle EOF here (c == 0) */
644210284Sjmallett      r = _rl_isearch_dispatch (cxt, cxt->lastc);
645210284Sjmallett      if (r <= 0)
646210284Sjmallett        break;
647210284Sjmallett    }
648210284Sjmallett
649210284Sjmallett  /* The searching is over.  The user may have found the string that she
650210284Sjmallett     was looking for, or else she may have exited a failing search.  If
651210284Sjmallett     LINE_INDEX is -1, then that shows that the string searched for was
652210284Sjmallett     not found.  We use this to determine where to place rl_point. */
653210284Sjmallett  return (_rl_isearch_cleanup (cxt, r));
654210284Sjmallett}
655210284Sjmallett
656210284Sjmallett#if defined (READLINE_CALLBACKS)
657210284Sjmallett/* Called from the callback functions when we are ready to read a key.  The
658210284Sjmallett   callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
659210284Sjmallett   If _rl_isearch_dispatch finishes searching, this function is responsible
660210284Sjmallett   for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
661210284Sjmallettint
662210284Sjmallett_rl_isearch_callback (cxt)
663210284Sjmallett     _rl_search_cxt *cxt;
664210284Sjmallett{
665210284Sjmallett  int c, r;
666210284Sjmallett
667210284Sjmallett  c = _rl_search_getchar (cxt);
668210284Sjmallett  /* We might want to handle EOF here */
669210284Sjmallett  r = _rl_isearch_dispatch (cxt, cxt->lastc);
670210284Sjmallett
671210284Sjmallett  return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
672210284Sjmallett}
673210284Sjmallett#endif
674210284Sjmallett