Release 2.33.1
[external/binutils.git] / readline / isearch.c
1 /* isearch.c - incremental searching */
2
3 /* **************************************************************** */
4 /*                                                                  */
5 /*                      I-Search and Searching                      */
6 /*                                                                  */
7 /* **************************************************************** */
8
9 /* Copyright (C) 1987-2017 Free Software Foundation, Inc.
10
11    This file is part of the GNU Readline Library (Readline), a library
12    for reading lines of text with interactive input and history editing.      
13
14    Readline is free software: you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation, either version 3 of the License, or
17    (at your option) any later version.
18
19    Readline is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
23
24    You should have received a copy of the GNU General Public License
25    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #define READLINE_LIBRARY
29
30 #if defined (HAVE_CONFIG_H)
31 #  include <config.h>
32 #endif
33
34 #include <sys/types.h>
35
36 #include <stdio.h>
37
38 #if defined (HAVE_UNISTD_H)
39 #  include <unistd.h>
40 #endif
41
42 #if defined (HAVE_STDLIB_H)
43 #  include <stdlib.h>
44 #else
45 #  include "ansi_stdlib.h"
46 #endif
47
48 #include "rldefs.h"
49 #include "rlmbutil.h"
50
51 #include "readline.h"
52 #include "history.h"
53
54 #include "rlprivate.h"
55 #include "xmalloc.h"
56
57 /* Variables exported to other files in the readline library. */
58 char *_rl_isearch_terminators = (char *)NULL;
59
60 _rl_search_cxt *_rl_iscxt = 0;
61
62 /* Variables imported from other files in the readline library. */
63 extern HIST_ENTRY *_rl_saved_line_for_history;
64
65 static int rl_search_history PARAMS((int, int));
66
67 static _rl_search_cxt *_rl_isearch_init PARAMS((int));
68 static void _rl_isearch_fini PARAMS((_rl_search_cxt *));
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. */
75 static char *last_isearch_string;
76 static int last_isearch_string_len;
77
78 static char * const default_isearch_terminators = "\033\012";
79
80 _rl_search_cxt *
81 _rl_scxt_alloc (int type, int flags)
82 {
83   _rl_search_cxt *cxt;
84
85   cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt));
86
87   cxt->type = type;
88   cxt->sflags = flags;
89
90   cxt->search_string = 0;
91   cxt->search_string_size = cxt->search_string_index = 0;
92
93   cxt->lines = 0;
94   cxt->allocated_line = 0;
95   cxt->hlen = cxt->hindex = 0;
96
97   cxt->save_point = rl_point;
98   cxt->save_mark = rl_mark;
99   cxt->save_line = where_history ();
100   cxt->last_found_line = cxt->save_line;
101   cxt->prev_line_found = 0;
102
103   cxt->save_undo_list = 0;
104
105   cxt->keymap = _rl_keymap;
106   cxt->okeymap = _rl_keymap;
107
108   cxt->history_pos = 0;
109   cxt->direction = 0;
110
111   cxt->prevc = cxt->lastc = 0;
112
113   cxt->sline = 0;
114   cxt->sline_len = cxt->sline_index = 0;
115
116   cxt->search_terminators = 0;
117
118   return cxt;
119 }
120
121 void
122 _rl_scxt_dispose (_rl_search_cxt *cxt, int flags)
123 {
124   FREE (cxt->search_string);
125   FREE (cxt->allocated_line);
126   FREE (cxt->lines);
127
128   xfree (cxt);
129 }
130
131 /* Search backwards through the history looking for a string which is typed
132    interactively.  Start with the current line. */
133 int
134 rl_reverse_search_history (int sign, int key)
135 {
136   return (rl_search_history (-sign, key));
137 }
138
139 /* Search forwards through the history looking for a string which is typed
140    interactively.  Start with the current line. */
141 int
142 rl_forward_search_history (int sign, int key)
143 {
144   return (rl_search_history (sign, key));
145 }
146
147 /* Display the current state of the search in the echo-area.
148    SEARCH_STRING contains the string that is being searched for,
149    DIRECTION is zero for forward, or non-zero for reverse,
150    WHERE is the history list number of the current line.  If it is
151    -1, then this line is the starting one. */
152 static void
153 rl_display_search (char *search_string, int flags, int where)
154 {
155   char *message;
156   int msglen, searchlen;
157
158   searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
159
160   message = (char *)xmalloc (searchlen + 64);
161   msglen = 0;
162
163 #if defined (NOTDEF)
164   if (where != -1)
165     {
166       sprintf (message, "[%d]", where + history_base);
167       msglen = strlen (message);
168     }
169 #endif /* NOTDEF */
170
171   message[msglen++] = '(';
172
173   if (flags & SF_FAILED)
174     {
175       strcpy (message + msglen, "failed ");
176       msglen += 7;
177     }
178
179   if (flags & SF_REVERSE)
180     {
181       strcpy (message + msglen, "reverse-");
182       msglen += 8;
183     }
184
185   strcpy (message + msglen, "i-search)`");
186   msglen += 10;
187
188   if (search_string)
189     {
190       strcpy (message + msglen, search_string);
191       msglen += searchlen;
192     }
193
194   strcpy (message + msglen, "': ");
195
196   rl_message ("%s", message);
197   xfree (message);
198   (*rl_redisplay_function) ();
199 }
200
201 static _rl_search_cxt *
202 _rl_isearch_init (int direction)
203 {
204   _rl_search_cxt *cxt;
205   register int i;
206   HIST_ENTRY **hlist;
207
208   cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0);
209   if (direction < 0)
210     cxt->sflags |= SF_REVERSE;
211
212   cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
213                                                 : default_isearch_terminators;
214
215   /* Create an array of pointers to the lines that we want to search. */
216   hlist = history_list ();
217   rl_maybe_replace_line ();
218   i = 0;
219   if (hlist)
220     for (i = 0; hlist[i]; i++);
221
222   /* Allocate space for this many lines, +1 for the current input line,
223      and remember those lines. */
224   cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *));
225   for (i = 0; i < cxt->hlen; i++)
226     cxt->lines[i] = hlist[i]->line;
227
228   if (_rl_saved_line_for_history)
229     cxt->lines[i] = _rl_saved_line_for_history->line;
230   else
231     {
232       /* Keep track of this so we can free it. */
233       cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
234       strcpy (cxt->allocated_line, &rl_line_buffer[0]);
235       cxt->lines[i] = cxt->allocated_line;
236     }
237
238   cxt->hlen++;
239
240   /* The line where we start the search. */
241   cxt->history_pos = cxt->save_line;
242
243   rl_save_prompt ();
244
245   /* Initialize search parameters. */
246   cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128);
247   cxt->search_string[cxt->search_string_index = 0] = '\0';
248
249   /* Normalize DIRECTION into 1 or -1. */
250   cxt->direction = (direction >= 0) ? 1 : -1;
251
252   cxt->sline = rl_line_buffer;
253   cxt->sline_len = strlen (cxt->sline);
254   cxt->sline_index = rl_point;
255
256   _rl_iscxt = cxt;              /* save globally */
257
258   return cxt;
259 }
260
261 static void
262 _rl_isearch_fini (_rl_search_cxt *cxt)
263 {
264   /* First put back the original state. */
265   rl_replace_line (cxt->lines[cxt->save_line], 0);
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   _rl_fix_point (0);
296
297   rl_clear_message ();
298 }
299
300 int
301 _rl_search_getchar (_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   /* This ends up with C (and LASTC) being set to the last byte of the
312      multibyte character.  In most cases c == lastc == mb[0] */
313   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
314     c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
315 #endif
316
317   RL_CHECK_SIGNALS ();
318   return c;
319 }
320
321 #define ENDSRCH_CHAR(c) \
322   ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
323
324 /* Process just-read character C according to isearch context CXT.  Return
325    -1 if the caller should just free the context and return, 0 if we should
326    break out of the loop, and 1 if we should continue to read characters. */
327 int
328 _rl_isearch_dispatch (_rl_search_cxt *cxt, int c)
329 {
330   int n, wstart, wlen, limit, cval, incr;
331   char *paste;
332   size_t pastelen;
333   int j;
334   rl_command_func_t *f;
335
336   f = (rl_command_func_t *)NULL;
337
338   if (c < 0)
339     {
340       cxt->sflags |= SF_FAILED;
341       cxt->history_pos = cxt->last_found_line;
342       return -1;
343     }
344
345   /* If we are moving into a new keymap, modify cxt->keymap and go on.
346      This can be a problem if c == ESC and we want to terminate the
347      incremental search, so we check */
348   if (c >= 0 && cxt->keymap[c].type == ISKMAP && strchr (cxt->search_terminators, cxt->lastc) == 0)
349     {
350       /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued
351          takes microseconds, so multiply by 1000.  If we don't get any
352          additional input and this keymap shadows another function, process
353          that key as if it was all we read. */
354       if (_rl_keyseq_timeout > 0 &&
355             RL_ISSTATE (RL_STATE_CALLBACK) == 0 &&
356             RL_ISSTATE (RL_STATE_INPUTPENDING) == 0 &&
357             _rl_pushed_input_available () == 0 &&
358             ((Keymap)(cxt->keymap[c].function))[ANYOTHERKEY].function &&
359             _rl_input_queued (_rl_keyseq_timeout*1000) == 0)
360         goto add_character;
361
362       cxt->okeymap = cxt->keymap;
363       cxt->keymap = FUNCTION_TO_KEYMAP (cxt->keymap, c);
364       cxt->sflags |= SF_CHGKMAP;
365       /* XXX - we should probably save this sequence, so we can do
366          something useful if this doesn't end up mapping to a command we
367          interpret here.  Right now we just save the most recent character
368          that caused the index into a new keymap. */
369       cxt->prevc = c;
370 #if defined (HANDLE_MULTIBYTE)
371       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
372         {
373           if (cxt->mb[1] == 0)
374             {
375               cxt->pmb[0] = c;          /* XXX should be == cxt->mb[0] */
376               cxt->pmb[1] = '\0';
377             }
378           else
379             memcpy (cxt->pmb, cxt->mb, sizeof (cxt->pmb));
380         }
381 #endif
382       return 1;
383     }
384
385 add_character:
386
387   /* Translate the keys we do something with to opcodes. */
388   if (c >= 0 && cxt->keymap[c].type == ISFUNC)
389     {
390       f = cxt->keymap[c].function;
391
392       if (f == rl_reverse_search_history)
393         cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
394       else if (f == rl_forward_search_history)
395         cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
396       else if (f == rl_rubout)
397         cxt->lastc = -3;
398       else if (c == CTRL ('G') || f == rl_abort)
399         cxt->lastc = -4;
400       else if (c == CTRL ('W') || f == rl_unix_word_rubout)     /* XXX */
401         cxt->lastc = -5;
402       else if (c == CTRL ('Y') || f == rl_yank) /* XXX */
403         cxt->lastc = -6;
404       else if (f == rl_bracketed_paste_begin)
405         cxt->lastc = -7;
406     }
407
408   /* If we changed the keymap earlier while translating a key sequence into
409      a command, restore it now that we've succeeded. */
410   if (cxt->sflags & SF_CHGKMAP)
411     {
412       cxt->keymap = cxt->okeymap;
413       cxt->sflags &= ~SF_CHGKMAP;
414       /* If we indexed into a new keymap, but didn't map to a command that
415          affects the search (lastc > 0), and the character that mapped to a
416          new keymap would have ended the search (ENDSRCH_CHAR(cxt->prevc)),
417          handle that now as if the previous char would have ended the search
418          and we would have read the current character. */
419       /* XXX - should we check cxt->mb? */
420       if (cxt->lastc > 0 && ENDSRCH_CHAR (cxt->prevc))
421         {
422           rl_stuff_char (cxt->lastc);
423           rl_execute_next (cxt->prevc);
424           /* XXX - do we insert everything in cxt->pmb? */
425           return (0);
426         }
427       /* Otherwise, if the current character is mapped to self-insert or
428          nothing (i.e., not an editing command), and the previous character
429          was a keymap index, then we need to insert both the previous
430          character and the current character into the search string. */
431       else if (cxt->lastc > 0 && cxt->prevc > 0 &&
432                cxt->keymap[cxt->prevc].type == ISKMAP &&
433                (f == 0 || f == rl_insert))
434         {
435           /* Make lastc be the next character read */
436           /* XXX - do we insert everything in cxt->mb? */
437           rl_execute_next (cxt->lastc);
438           /* Dispatch on the previous character (insert into search string) */
439           cxt->lastc = cxt->prevc;
440 #if defined (HANDLE_MULTIBYTE)
441           /* Have to overwrite cxt->mb here because dispatch uses it below */
442           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
443             {  
444               if (cxt->pmb[1] == 0)       
445                 {
446                   cxt->mb[0] = cxt->lastc;      /* == cxt->prevc */
447                   cxt->mb[1] = '\0';
448                 }
449               else
450                 memcpy (cxt->mb, cxt->pmb, sizeof (cxt->mb));
451             }
452 #endif
453           cxt->prevc = 0;         
454         }
455       else if (cxt->lastc > 0 && cxt->prevc > 0 && f && f != rl_insert)
456         {
457           rl_stuff_char (cxt->lastc);
458           rl_execute_next (cxt->prevc);
459           /* XXX - do we insert everything in cxt->pmb? */
460           return (0);
461         }
462     }
463
464   /* The characters in isearch_terminators (set from the user-settable
465      variable isearch-terminators) are used to terminate the search but
466      not subsequently execute the character as a command.  The default
467      value is "\033\012" (ESC and C-J). */
468   if (cxt->lastc > 0 && strchr (cxt->search_terminators, cxt->lastc))
469     {
470       /* ESC still terminates the search, but if there is pending
471          input or if input arrives within 0.1 seconds (on systems
472          with select(2)) it is used as a prefix character
473          with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
474          to allow the arrow keys to be used like ^F and ^B are used
475          to terminate the search and execute the movement command.
476          XXX - since _rl_input_available depends on the application-
477          settable keyboard timeout value, this could alternatively
478          use _rl_input_queued(100000) */
479       if (cxt->lastc == ESC && (_rl_pushed_input_available () || _rl_input_available ()))
480         rl_execute_next (ESC);
481       return (0);
482     }
483
484 #if defined (HANDLE_MULTIBYTE)
485   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
486     {
487       if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
488         {
489           /* This sets rl_pending_input to LASTC; it will be picked up the next
490              time rl_read_key is called. */
491           rl_execute_next (cxt->lastc);
492           return (0);
493         }
494     }
495   else
496 #endif
497     if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
498       {
499         /* This sets rl_pending_input to LASTC; it will be picked up the next
500            time rl_read_key is called. */
501         rl_execute_next (cxt->lastc);
502         return (0);
503       }
504
505   /* Now dispatch on the character.  `Opcodes' affect the search string or
506      state.  Other characters are added to the string.  */
507   switch (cxt->lastc)
508     {
509     /* search again */
510     case -1:
511       if (cxt->search_string_index == 0)
512         {
513           if (last_isearch_string)
514             {
515               cxt->search_string_size = 64 + last_isearch_string_len;
516               cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
517               strcpy (cxt->search_string, last_isearch_string);
518               cxt->search_string_index = last_isearch_string_len;
519               rl_display_search (cxt->search_string, cxt->sflags, -1);
520               break;
521             }
522           return (1);
523         }
524       else if ((cxt->sflags & SF_REVERSE) && cxt->sline_index >= 0)
525         cxt->sline_index--;
526       else if (cxt->sline_index != cxt->sline_len)
527         cxt->sline_index++;
528       else
529         rl_ding ();
530       break;
531
532     /* switch directions */
533     case -2:
534       cxt->direction = -cxt->direction;
535       if (cxt->direction < 0)
536         cxt->sflags |= SF_REVERSE;
537       else
538         cxt->sflags &= ~SF_REVERSE;
539       break;
540
541     /* delete character from search string. */
542     case -3:    /* C-H, DEL */
543       /* This is tricky.  To do this right, we need to keep a
544          stack of search positions for the current search, with
545          sentinels marking the beginning and end.  But this will
546          do until we have a real isearch-undo. */
547       if (cxt->search_string_index == 0)
548         rl_ding ();
549       else if (MB_CUR_MAX == 1 || rl_byte_oriented)
550         cxt->search_string[--cxt->search_string_index] = '\0';
551       else
552         {
553           wstart = _rl_find_prev_mbchar (cxt->search_string, cxt->search_string_index, MB_FIND_NONZERO);
554           if (wstart >= 0)
555             cxt->search_string[cxt->search_string_index = wstart] = '\0';
556           else
557             cxt->search_string[cxt->search_string_index = 0] = '\0';
558         }
559
560       if (cxt->search_string_index == 0)
561         rl_ding ();
562
563       break;
564
565     case -4:    /* C-G, abort */
566       rl_replace_line (cxt->lines[cxt->save_line], 0);
567       rl_point = cxt->save_point;
568       rl_mark = cxt->save_mark;
569       rl_restore_prompt();
570       rl_clear_message ();
571
572       return -1;
573
574     case -5:    /* C-W */
575       /* skip over portion of line we already matched and yank word */
576       wstart = rl_point + cxt->search_string_index;
577       if (wstart >= rl_end)
578         {
579           rl_ding ();
580           break;
581         }
582
583       /* if not in a word, move to one. */
584       cval = _rl_char_value (rl_line_buffer, wstart);
585       if (_rl_walphabetic (cval) == 0)
586         {
587           rl_ding ();
588           break;
589         }
590       n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
591       while (n < rl_end)
592         {
593           cval = _rl_char_value (rl_line_buffer, n);
594           if (_rl_walphabetic (cval) == 0)
595             break;
596           n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
597         }
598       wlen = n - wstart + 1;
599       if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
600         {
601           cxt->search_string_size += wlen + 1;
602           cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
603         }
604       for (; wstart < n; wstart++)
605         cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
606       cxt->search_string[cxt->search_string_index] = '\0';
607       break;
608
609     case -6:    /* C-Y */
610       /* skip over portion of line we already matched and yank rest */
611       wstart = rl_point + cxt->search_string_index;
612       if (wstart >= rl_end)
613         {
614           rl_ding ();
615           break;
616         }
617       n = rl_end - wstart + 1;
618       if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
619         {
620           cxt->search_string_size += n + 1;
621           cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
622         }
623       for (n = wstart; n < rl_end; n++)
624         cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
625       cxt->search_string[cxt->search_string_index] = '\0';
626       break;
627
628     case -7:    /* bracketed paste */
629       paste = _rl_bracketed_text (&pastelen);
630       if (paste == 0 || *paste == 0)
631         {
632           free (paste);
633           break;
634         }
635       if (cxt->search_string_index + pastelen + 1 >= cxt->search_string_size)
636         {
637           cxt->search_string_size += pastelen + 2;
638           cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
639         }
640       strcpy (cxt->search_string + cxt->search_string_index, paste);
641       cxt->search_string_index += pastelen;
642       free (paste);
643       break;
644
645     /* Add character to search string and continue search. */
646     default:
647 #if defined (HANDLE_MULTIBYTE)
648       wlen = (cxt->mb[0] == 0 || cxt->mb[1] == 0) ? 1 : RL_STRLEN (cxt->mb);
649 #else
650       wlen = 1;
651 #endif
652       if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
653         {
654           cxt->search_string_size += 128;       /* 128 much greater than MB_CUR_MAX */
655           cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
656         }
657 #if defined (HANDLE_MULTIBYTE)
658       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
659         {
660           int j;
661
662           if (cxt->mb[0] == 0 || cxt->mb[1] == 0)
663             cxt->search_string[cxt->search_string_index++] = cxt->mb[0];
664           else
665             for (j = 0; j < wlen; )
666               cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
667         }
668       else
669 #endif
670         cxt->search_string[cxt->search_string_index++] = cxt->lastc;    /* XXX - was c instead of lastc */
671       cxt->search_string[cxt->search_string_index] = '\0';
672       break;
673     }
674
675   for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
676     {
677       if (cxt->search_string_index == 0)
678         {
679           cxt->sflags |= SF_FAILED;
680           break;
681         }
682
683       limit = cxt->sline_len - cxt->search_string_index + 1;
684
685       /* Search the current line. */
686       while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
687         {
688           if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
689             {
690               cxt->sflags |= SF_FOUND;
691               break;
692             }
693           else
694             cxt->sline_index += cxt->direction;
695
696           if (cxt->sline_index < 0)
697             {
698               cxt->sline_index = 0;
699               break;
700             }
701         }
702       if (cxt->sflags & SF_FOUND)
703         break;
704
705       /* Move to the next line, but skip new copies of the line
706          we just found and lines shorter than the string we're
707          searching for. */
708       do
709         {
710           /* Move to the next line. */
711           cxt->history_pos += cxt->direction;
712
713           /* At limit for direction? */
714           if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
715             {
716               cxt->sflags |= SF_FAILED;
717               break;
718             }
719
720           /* We will need these later. */
721           cxt->sline = cxt->lines[cxt->history_pos];
722           cxt->sline_len = strlen (cxt->sline);
723         }
724       while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
725              (cxt->search_string_index > cxt->sline_len));
726
727       if (cxt->sflags & SF_FAILED)
728         {
729           /* XXX - reset sline_index if < 0 */
730           if (cxt->sline_index < 0)
731             cxt->sline_index = 0;
732           break;
733         }
734
735       /* Now set up the line for searching... */
736       cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
737     }
738
739   if (cxt->sflags & SF_FAILED)
740     {
741       /* We cannot find the search string.  Ding the bell. */
742       rl_ding ();
743       cxt->history_pos = cxt->last_found_line;
744       rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
745       return 1;
746     }
747
748   /* We have found the search string.  Just display it.  But don't
749      actually move there in the history list until the user accepts
750      the location. */
751   if (cxt->sflags & SF_FOUND)
752     {
753       cxt->prev_line_found = cxt->lines[cxt->history_pos];
754       rl_replace_line (cxt->lines[cxt->history_pos], 0);
755       rl_point = cxt->sline_index;
756       cxt->last_found_line = cxt->history_pos;
757       rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
758     }
759
760   return 1;
761 }
762
763 int
764 _rl_isearch_cleanup (_rl_search_cxt *cxt, int r)
765 {
766   if (r >= 0)
767     _rl_isearch_fini (cxt);
768   _rl_scxt_dispose (cxt, 0);
769   _rl_iscxt = 0;
770
771   RL_UNSETSTATE(RL_STATE_ISEARCH);
772
773   return (r != 0);
774 }
775
776 /* Search through the history looking for an interactively typed string.
777    This is analogous to i-search.  We start the search in the current line.
778    DIRECTION is which direction to search; >= 0 means forward, < 0 means
779    backwards. */
780 static int
781 rl_search_history (int direction, int invoking_key)
782 {
783   _rl_search_cxt *cxt;          /* local for now, but saved globally */
784   int c, r;
785
786   RL_SETSTATE(RL_STATE_ISEARCH);
787   cxt = _rl_isearch_init (direction);
788
789   rl_display_search (cxt->search_string, cxt->sflags, -1);
790
791   /* If we are using the callback interface, all we do is set up here and
792       return.  The key is that we leave RL_STATE_ISEARCH set. */
793   if (RL_ISSTATE (RL_STATE_CALLBACK))
794     return (0);
795
796   r = -1;
797   for (;;)
798     {
799       c = _rl_search_getchar (cxt);
800       /* We might want to handle EOF here (c == 0) */
801       r = _rl_isearch_dispatch (cxt, cxt->lastc);
802       if (r <= 0)
803         break;
804     }
805
806   /* The searching is over.  The user may have found the string that she
807      was looking for, or else she may have exited a failing search.  If
808      LINE_INDEX is -1, then that shows that the string searched for was
809      not found.  We use this to determine where to place rl_point. */
810   return (_rl_isearch_cleanup (cxt, r));
811 }
812
813 #if defined (READLINE_CALLBACKS)
814 /* Called from the callback functions when we are ready to read a key.  The
815    callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
816    If _rl_isearch_dispatch finishes searching, this function is responsible
817    for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
818 int
819 _rl_isearch_callback (_rl_search_cxt *cxt)
820 {
821   int c, r;
822
823   c = _rl_search_getchar (cxt);
824   /* We might want to handle EOF here */
825   r = _rl_isearch_dispatch (cxt, cxt->lastc);
826
827   return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
828 }
829 #endif