]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - readline/isearch.c
[gdb/exp] Fix cast handling for indirection
[thirdparty/binutils-gdb.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