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