1: /* search.c - code for non-incremental searching in emacs and vi modes. */
2:
3: /* Copyright (C) 1992-2013 Free Software Foundation, Inc.
4:
5: This file is part of the GNU Readline Library (Readline), a library
6: for reading lines of text with interactive input and history editing.
7:
8: Readline is free software: you can redistribute it and/or modify
9: it under the terms of the GNU General Public License as published by
10: the Free Software Foundation, either version 3 of the License, or
11: (at your option) any later version.
12:
13: Readline is distributed in the hope that it will be useful,
14: but WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: GNU General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with Readline. If not, see <http://www.gnu.org/licenses/>.
20: */
21:
22: #define READLINE_LIBRARY
23:
24: #if defined (HAVE_CONFIG_H)
25: # include <config.h>
26: #endif
27:
28: #include <sys/types.h>
29: #include <stdio.h>
30:
31: #if defined (HAVE_UNISTD_H)
32: # include <unistd.h>
33: #endif
34:
35: #if defined (HAVE_STDLIB_H)
36: # include <stdlib.h>
37: #else
38: # include "ansi_stdlib.h"
39: #endif
40:
41: #include "rldefs.h"
42: #include "rlmbutil.h"
43:
44: #include "readline.h"
45: #include "history.h"
46: #include "histlib.h"
47:
48: #include "rlprivate.h"
49: #include "xmalloc.h"
50:
51: #ifdef abs
52: # undef abs
53: #endif
54: #define abs(x) (((x) >= 0) ? (x) : -(x))
55:
56: _rl_search_cxt *_rl_nscxt = 0;
57:
58: extern HIST_ENTRY *_rl_saved_line_for_history;
59:
60: /* Functions imported from the rest of the library. */
61: extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
62:
63: static char *noninc_search_string = (char *) NULL;
64: static int noninc_history_pos;
65:
66: static char *prev_line_found = (char *) NULL;
67:
68: static int rl_history_search_len;
69: static int rl_history_search_pos;
70: static int rl_history_search_flags;
71:
72: static char *history_search_string;
73: static int history_string_size;
74:
75: static void make_history_line_current PARAMS((HIST_ENTRY *));
76: static int noninc_search_from_pos PARAMS((char *, int, int));
77: static int noninc_dosearch PARAMS((char *, int));
78: static int noninc_search PARAMS((int, int));
79: static int rl_history_search_internal PARAMS((int, int));
80: static void rl_history_search_reinit PARAMS((int));
81:
82: static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
83: static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
84: static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
85: static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
86:
87: /* Make the data from the history entry ENTRY be the contents of the
88: current line. This doesn't do anything with rl_point; the caller
89: must set it. */
90: static void
91: make_history_line_current (entry)
92: HIST_ENTRY *entry;
93: {
94: _rl_replace_text (entry->line, 0, rl_end);
95: _rl_fix_point (1);
96: #if defined (VI_MODE)
97: if (rl_editing_mode == vi_mode)
98: /* POSIX.2 says that the `U' command doesn't affect the copy of any
99: command lines to the edit line. We're going to implement that by
100: making the undo list start after the matching line is copied to the
101: current editing buffer. */
102: rl_free_undo_list ();
103: #endif
104:
105: if (_rl_saved_line_for_history)
106: _rl_free_history_entry (_rl_saved_line_for_history);
107: _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
108: }
109:
110: /* Search the history list for STRING starting at absolute history position
111: POS. If STRING begins with `^', the search must match STRING at the
112: beginning of a history line, otherwise a full substring match is performed
113: for STRING. DIR < 0 means to search backwards through the history list,
114: DIR >= 0 means to search forward. */
115: static int
116: noninc_search_from_pos (string, pos, dir)
117: char *string;
118: int pos, dir;
119: {
120: int ret, old;
121:
122: if (pos < 0)
123: return -1;
124:
125: old = where_history ();
126: if (history_set_pos (pos) == 0)
127: return -1;
128:
129: RL_SETSTATE(RL_STATE_SEARCH);
130: if (*string == '^')
131: ret = history_search_prefix (string + 1, dir);
132: else
133: ret = history_search (string, dir);
134: RL_UNSETSTATE(RL_STATE_SEARCH);
135:
136: if (ret != -1)
137: ret = where_history ();
138:
139: history_set_pos (old);
140: return (ret);
141: }
142:
143: /* Search for a line in the history containing STRING. If DIR is < 0, the
144: search is backwards through previous entries, else through subsequent
145: entries. Returns 1 if the search was successful, 0 otherwise. */
146: static int
147: noninc_dosearch (string, dir)
148: char *string;
149: int dir;
150: {
151: int oldpos, pos;
152: HIST_ENTRY *entry;
153:
154: if (string == 0 || *string == '\0' || noninc_history_pos < 0)
155: {
156: rl_ding ();
157: return 0;
158: }
159:
160: pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
161: if (pos == -1)
162: {
163: /* Search failed, current history position unchanged. */
164: rl_maybe_unsave_line ();
165: rl_clear_message ();
166: rl_point = 0;
167: rl_ding ();
168: return 0;
169: }
170:
171: noninc_history_pos = pos;
172:
173: oldpos = where_history ();
174: history_set_pos (noninc_history_pos);
175: entry = current_history (); /* will never be NULL after successful search */
176:
177: #if defined (VI_MODE)
178: if (rl_editing_mode != vi_mode)
179: #endif
180: history_set_pos (oldpos);
181:
182: make_history_line_current (entry);
183:
184: rl_point = 0;
185: rl_mark = rl_end;
186:
187: rl_clear_message ();
188: return 1;
189: }
190:
191: static _rl_search_cxt *
192: _rl_nsearch_init (dir, pchar)
193: int dir, pchar;
194: {
195: _rl_search_cxt *cxt;
196: char *p;
197:
198: cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
199: if (dir < 0)
200: cxt->sflags |= SF_REVERSE; /* not strictly needed */
201:
202: cxt->direction = dir;
203: cxt->history_pos = cxt->save_line;
204:
205: rl_maybe_save_line ();
206:
207: /* Clear the undo list, since reading the search string should create its
208: own undo list, and the whole list will end up being freed when we
209: finish reading the search string. */
210: rl_undo_list = 0;
211:
212: /* Use the line buffer to read the search string. */
213: rl_line_buffer[0] = 0;
214: rl_end = rl_point = 0;
215:
216: p = _rl_make_prompt_for_search (pchar ? pchar : ':');
217: rl_message ("%s", p);
218: xfree (p);
219:
220: RL_SETSTATE(RL_STATE_NSEARCH);
221:
222: _rl_nscxt = cxt;
223:
224: return cxt;
225: }
226:
227: static int
228: _rl_nsearch_cleanup (cxt, r)
229: _rl_search_cxt *cxt;
230: int r;
231: {
232: _rl_scxt_dispose (cxt, 0);
233: _rl_nscxt = 0;
234:
235: RL_UNSETSTATE(RL_STATE_NSEARCH);
236:
237: return (r != 1);
238: }
239:
240: static void
241: _rl_nsearch_abort (cxt)
242: _rl_search_cxt *cxt;
243: {
244: rl_maybe_unsave_line ();
245: rl_clear_message ();
246: rl_point = cxt->save_point;
247: rl_mark = cxt->save_mark;
248: rl_restore_prompt ();
249:
250: RL_UNSETSTATE (RL_STATE_NSEARCH);
251: }
252:
253: /* Process just-read character C according to search context CXT. Return -1
254: if the caller should abort the search, 0 if we should break out of the
255: loop, and 1 if we should continue to read characters. */
256: static int
257: _rl_nsearch_dispatch (cxt, c)
258: _rl_search_cxt *cxt;
259: int c;
260: {
261: switch (c)
262: {
263: case CTRL('W'):
264: rl_unix_word_rubout (1, c);
265: break;
266:
267: case CTRL('U'):
268: rl_unix_line_discard (1, c);
269: break;
270:
271: case RETURN:
272: case NEWLINE:
273: return 0;
274:
275: case CTRL('H'):
276: case RUBOUT:
277: if (rl_point == 0)
278: {
279: _rl_nsearch_abort (cxt);
280: return -1;
281: }
282: _rl_rubout_char (1, c);
283: break;
284:
285: case CTRL('C'):
286: case CTRL('G'):
287: rl_ding ();
288: _rl_nsearch_abort (cxt);
289: return -1;
290:
291: default:
292: #if defined (HANDLE_MULTIBYTE)
293: if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
294: rl_insert_text (cxt->mb);
295: else
296: #endif
297: _rl_insert_char (1, c);
298: break;
299: }
300:
301: (*rl_redisplay_function) ();
302: return 1;
303: }
304:
305: /* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return
306: -1 if the search should be aborted, any other value means to clean up
307: using _rl_nsearch_cleanup (). Returns 1 if the search was successful,
308: 0 otherwise. */
309: static int
310: _rl_nsearch_dosearch (cxt)
311: _rl_search_cxt *cxt;
312: {
313: rl_mark = cxt->save_mark;
314:
315: /* If rl_point == 0, we want to re-use the previous search string and
316: start from the saved history position. If there's no previous search
317: string, punt. */
318: if (rl_point == 0)
319: {
320: if (noninc_search_string == 0)
321: {
322: rl_ding ();
323: rl_restore_prompt ();
324: RL_UNSETSTATE (RL_STATE_NSEARCH);
325: return -1;
326: }
327: }
328: else
329: {
330: /* We want to start the search from the current history position. */
331: noninc_history_pos = cxt->save_line;
332: FREE (noninc_search_string);
333: noninc_search_string = savestring (rl_line_buffer);
334:
335: /* If we don't want the subsequent undo list generated by the search
336: matching a history line to include the contents of the search string,
337: we need to clear rl_line_buffer here. For now, we just clear the
338: undo list generated by reading the search string. (If the search
339: fails, the old undo list will be restored by rl_maybe_unsave_line.) */
340: rl_free_undo_list ();
341: }
342:
343: rl_restore_prompt ();
344: return (noninc_dosearch (noninc_search_string, cxt->direction));
345: }
346:
347: /* Search non-interactively through the history list. DIR < 0 means to
348: search backwards through the history of previous commands; otherwise
349: the search is for commands subsequent to the current position in the
350: history list. PCHAR is the character to use for prompting when reading
351: the search string; if not specified (0), it defaults to `:'. */
352: static int
353: noninc_search (dir, pchar)
354: int dir;
355: int pchar;
356: {
357: _rl_search_cxt *cxt;
358: int c, r;
359:
360: cxt = _rl_nsearch_init (dir, pchar);
361:
362: if (RL_ISSTATE (RL_STATE_CALLBACK))
363: return (0);
364:
365: /* Read the search string. */
366: r = 0;
367: while (1)
368: {
369: c = _rl_search_getchar (cxt);
370:
371: if (c == 0)
372: break;
373:
374: r = _rl_nsearch_dispatch (cxt, c);
375: if (r < 0)
376: return 1;
377: else if (r == 0)
378: break;
379: }
380:
381: r = _rl_nsearch_dosearch (cxt);
382: return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
383: }
384:
385: /* Search forward through the history list for a string. If the vi-mode
386: code calls this, KEY will be `?'. */
387: int
388: rl_noninc_forward_search (count, key)
389: int count, key;
390: {
391: return noninc_search (1, (key == '?') ? '?' : 0);
392: }
393:
394: /* Reverse search the history list for a string. If the vi-mode code
395: calls this, KEY will be `/'. */
396: int
397: rl_noninc_reverse_search (count, key)
398: int count, key;
399: {
400: return noninc_search (-1, (key == '/') ? '/' : 0);
401: }
402:
403: /* Search forward through the history list for the last string searched
404: for. If there is no saved search string, abort. */
405: int
406: rl_noninc_forward_search_again (count, key)
407: int count, key;
408: {
409: int r;
410:
411: if (!noninc_search_string)
412: {
413: rl_ding ();
414: return (-1);
415: }
416: r = noninc_dosearch (noninc_search_string, 1);
417: return (r != 1);
418: }
419:
420: /* Reverse search in the history list for the last string searched
421: for. If there is no saved search string, abort. */
422: int
423: rl_noninc_reverse_search_again (count, key)
424: int count, key;
425: {
426: int r;
427:
428: if (!noninc_search_string)
429: {
430: rl_ding ();
431: return (-1);
432: }
433: r = noninc_dosearch (noninc_search_string, -1);
434: return (r != 1);
435: }
436:
437: #if defined (READLINE_CALLBACKS)
438: int
439: _rl_nsearch_callback (cxt)
440: _rl_search_cxt *cxt;
441: {
442: int c, r;
443:
444: c = _rl_search_getchar (cxt);
445: r = _rl_nsearch_dispatch (cxt, c);
446: if (r != 0)
447: return 1;
448:
449: r = _rl_nsearch_dosearch (cxt);
450: return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
451: }
452: #endif
453:
454: static int
455: rl_history_search_internal (count, dir)
456: int count, dir;
457: {
458: HIST_ENTRY *temp;
459: int ret, oldpos;
460: char *t;
461:
462: rl_maybe_save_line ();
463: temp = (HIST_ENTRY *)NULL;
464:
465: /* Search COUNT times through the history for a line matching
466: history_search_string. If history_search_string[0] == '^', the
467: line must match from the start; otherwise any substring can match.
468: When this loop finishes, TEMP, if non-null, is the history line to
469: copy into the line buffer. */
470: while (count)
471: {
472: RL_CHECK_SIGNALS ();
473: ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
474: if (ret == -1)
475: break;
476:
477: /* Get the history entry we found. */
478: rl_history_search_pos = ret;
479: oldpos = where_history ();
480: history_set_pos (rl_history_search_pos);
481: temp = current_history (); /* will never be NULL after successful search */
482: history_set_pos (oldpos);
483:
484: /* Don't find multiple instances of the same line. */
485: if (prev_line_found && STREQ (prev_line_found, temp->line))
486: continue;
487: prev_line_found = temp->line;
488: count--;
489: }
490:
491: /* If we didn't find anything at all, return. */
492: if (temp == 0)
493: {
494: rl_maybe_unsave_line ();
495: rl_ding ();
496: /* If you don't want the saved history line (last match) to show up
497: in the line buffer after the search fails, change the #if 0 to
498: #if 1 */
499: #if 0
500: if (rl_point > rl_history_search_len)
501: {
502: rl_point = rl_end = rl_history_search_len;
503: rl_line_buffer[rl_end] = '\0';
504: rl_mark = 0;
505: }
506: #else
507: rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
508: rl_mark = rl_end;
509: #endif
510: return 1;
511: }
512:
513: /* Copy the line we found into the current line buffer. */
514: make_history_line_current (temp);
515:
516: if (rl_history_search_flags & ANCHORED_SEARCH)
517: rl_point = rl_history_search_len; /* easy case */
518: else
519: {
520: t = strstr (rl_line_buffer, history_search_string);
521: rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
522: }
523: rl_mark = rl_end;
524:
525: return 0;
526: }
527:
528: static void
529: rl_history_search_reinit (flags)
530: int flags;
531: {
532: int sind;
533:
534: rl_history_search_pos = where_history ();
535: rl_history_search_len = rl_point;
536: rl_history_search_flags = flags;
537:
538: prev_line_found = (char *)NULL;
539: if (rl_point)
540: {
541: /* Allocate enough space for anchored and non-anchored searches */
542: if (rl_history_search_len >= history_string_size - 2)
543: {
544: history_string_size = rl_history_search_len + 2;
545: history_search_string = (char *)xrealloc (history_search_string, history_string_size);
546: }
547: sind = 0;
548: if (flags & ANCHORED_SEARCH)
549: history_search_string[sind++] = '^';
550: strncpy (history_search_string + sind, rl_line_buffer, rl_point);
551: history_search_string[rl_point + sind] = '\0';
552: }
553: _rl_free_saved_history_line ();
554: }
555:
556: /* Search forward in the history for the string of characters
557: from the start of the line to rl_point. This is a non-incremental
558: search. The search is anchored to the beginning of the history line. */
559: int
560: rl_history_search_forward (count, ignore)
561: int count, ignore;
562: {
563: if (count == 0)
564: return (0);
565:
566: if (rl_last_func != rl_history_search_forward &&
567: rl_last_func != rl_history_search_backward)
568: rl_history_search_reinit (ANCHORED_SEARCH);
569:
570: if (rl_history_search_len == 0)
571: return (rl_get_next_history (count, ignore));
572: return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
573: }
574:
575: /* Search backward through the history for the string of characters
576: from the start of the line to rl_point. This is a non-incremental
577: search. */
578: int
579: rl_history_search_backward (count, ignore)
580: int count, ignore;
581: {
582: if (count == 0)
583: return (0);
584:
585: if (rl_last_func != rl_history_search_forward &&
586: rl_last_func != rl_history_search_backward)
587: rl_history_search_reinit (ANCHORED_SEARCH);
588:
589: if (rl_history_search_len == 0)
590: return (rl_get_previous_history (count, ignore));
591: return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
592: }
593:
594: /* Search forward in the history for the string of characters
595: from the start of the line to rl_point. This is a non-incremental
596: search. The search succeeds if the search string is present anywhere
597: in the history line. */
598: int
599: rl_history_substr_search_forward (count, ignore)
600: int count, ignore;
601: {
602: if (count == 0)
603: return (0);
604:
605: if (rl_last_func != rl_history_substr_search_forward &&
606: rl_last_func != rl_history_substr_search_backward)
607: rl_history_search_reinit (NON_ANCHORED_SEARCH);
608:
609: if (rl_history_search_len == 0)
610: return (rl_get_next_history (count, ignore));
611: return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
612: }
613:
614: /* Search backward through the history for the string of characters
615: from the start of the line to rl_point. This is a non-incremental
616: search. */
617: int
618: rl_history_substr_search_backward (count, ignore)
619: int count, ignore;
620: {
621: if (count == 0)
622: return (0);
623:
624: if (rl_last_func != rl_history_substr_search_forward &&
625: rl_last_func != rl_history_substr_search_backward)
626: rl_history_search_reinit (NON_ANCHORED_SEARCH);
627:
628: if (rl_history_search_len == 0)
629: return (rl_get_previous_history (count, ignore));
630: return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
631: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>