Default kdump's data limit to 64 bytes and document how it can be disabled.
[dragonfly.git] / contrib / readline-5.0 / isearch.c
1 /* **************************************************************** */
2 /*                                                                  */
3 /*                      I-Search and Searching                      */
4 /*                                                                  */
5 /* **************************************************************** */
6
7 /* Copyright (C) 1987-2002 Free Software Foundation, Inc.
8
9    This file contains the Readline Library (the Library), a set of
10    routines for providing Emacs style line input to programs that ask
11    for it.
12
13    The Library is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 2, or (at your option)
16    any later version.
17
18    The Library is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22
23    The GNU General Public License is often shipped with GNU software, and
24    is generally kept in a file called COPYING or LICENSE.  If you do not
25    have a copy of the license, write to the Free Software Foundation,
26    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
27 #define READLINE_LIBRARY
28
29 #if defined (HAVE_CONFIG_H)
30 #  include <config.h>
31 #endif
32
33 #include <sys/types.h>
34
35 #include <stdio.h>
36
37 #if defined (HAVE_UNISTD_H)
38 #  include <unistd.h>
39 #endif
40
41 #if defined (HAVE_STDLIB_H)
42 #  include <stdlib.h>
43 #else
44 #  include "ansi_stdlib.h"
45 #endif
46
47 #include "rldefs.h"
48 #include "rlmbutil.h"
49
50 #include "readline.h"
51 #include "history.h"
52
53 #include "rlprivate.h"
54 #include "xmalloc.h"
55
56 /* Variables exported to other files in the readline library. */
57 char *_rl_isearch_terminators = (char *)NULL;
58
59 /* Variables imported from other files in the readline library. */
60 extern HIST_ENTRY *_rl_saved_line_for_history;
61
62 /* Forward declarations */
63 static int rl_search_history PARAMS((int, int));
64
65 /* Last line found by the current incremental search, so we don't `find'
66    identical lines many times in a row. */
67 static char *prev_line_found;
68
69 /* Last search string and its length. */
70 static char *last_isearch_string;
71 static int last_isearch_string_len;
72
73 static char *default_isearch_terminators = "\033\012";
74
75 /* Search backwards through the history looking for a string which is typed
76    interactively.  Start with the current line. */
77 int
78 rl_reverse_search_history (sign, key)
79      int sign, key;
80 {
81   return (rl_search_history (-sign, key));
82 }
83
84 /* Search forwards through the history looking for a string which is typed
85    interactively.  Start with the current line. */
86 int
87 rl_forward_search_history (sign, key)
88      int sign, key;
89 {
90   return (rl_search_history (sign, key));
91 }
92
93 /* Display the current state of the search in the echo-area.
94    SEARCH_STRING contains the string that is being searched for,
95    DIRECTION is zero for forward, or 1 for reverse,
96    WHERE is the history list number of the current line.  If it is
97    -1, then this line is the starting one. */
98 static void
99 rl_display_search (search_string, reverse_p, where)
100      char *search_string;
101      int reverse_p, where;
102 {
103   char *message;
104   int msglen, searchlen;
105
106   searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
107
108   message = (char *)xmalloc (searchlen + 33);
109   msglen = 0;
110
111 #if defined (NOTDEF)
112   if (where != -1)
113     {
114       sprintf (message, "[%d]", where + history_base);
115       msglen = strlen (message);
116     }
117 #endif /* NOTDEF */
118
119   message[msglen++] = '(';
120
121   if (reverse_p)
122     {
123       strcpy (message + msglen, "reverse-");
124       msglen += 8;
125     }
126
127   strcpy (message + msglen, "i-search)`");
128   msglen += 10;
129
130   if (search_string)
131     {
132       strcpy (message + msglen, search_string);
133       msglen += searchlen;
134     }
135
136   strcpy (message + msglen, "': ");
137
138   rl_message ("%s", message);
139   free (message);
140   (*rl_redisplay_function) ();
141 }
142
143 /* Search through the history looking for an interactively typed string.
144    This is analogous to i-search.  We start the search in the current line.
145    DIRECTION is which direction to search; >= 0 means forward, < 0 means
146    backwards. */
147 static int
148 rl_search_history (direction, invoking_key)
149      int direction, invoking_key;
150 {
151   /* The string that the user types in to search for. */
152   char *search_string;
153
154   /* The current length of SEARCH_STRING. */
155   int search_string_index;
156
157   /* The amount of space that SEARCH_STRING has allocated to it. */
158   int search_string_size;
159
160   /* The list of lines to search through. */
161   char **lines, *allocated_line;
162
163   /* The length of LINES. */
164   int hlen;
165
166   /* Where we get LINES from. */
167   HIST_ENTRY **hlist;
168
169   register int i;
170   int orig_point, orig_mark, orig_line, last_found_line;
171   int c, found, failed, sline_len;
172   int n, wstart, wlen;
173 #if defined (HANDLE_MULTIBYTE)
174   char mb[MB_LEN_MAX];
175 #endif
176
177   /* The line currently being searched. */
178   char *sline;
179
180   /* Offset in that line. */
181   int line_index;
182
183   /* Non-zero if we are doing a reverse search. */
184   int reverse;
185
186   /* The list of characters which terminate the search, but are not
187      subsequently executed.  If the variable isearch-terminators has
188      been set, we use that value, otherwise we use ESC and C-J. */
189   char *isearch_terminators;
190
191   RL_SETSTATE(RL_STATE_ISEARCH);
192   orig_point = rl_point;
193   orig_mark = rl_mark;
194   last_found_line = orig_line = where_history ();
195   reverse = direction < 0;
196   hlist = history_list ();
197   allocated_line = (char *)NULL;
198
199   isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
200                                                 : default_isearch_terminators;
201
202   /* Create an arrary of pointers to the lines that we want to search. */
203   rl_maybe_replace_line ();
204   i = 0;
205   if (hlist)
206     for (i = 0; hlist[i]; i++);
207
208   /* Allocate space for this many lines, +1 for the current input line,
209      and remember those lines. */
210   lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *));
211   for (i = 0; i < hlen; i++)
212     lines[i] = hlist[i]->line;
213
214   if (_rl_saved_line_for_history)
215     lines[i] = _rl_saved_line_for_history->line;
216   else
217     {
218       /* Keep track of this so we can free it. */
219       allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
220       strcpy (allocated_line, &rl_line_buffer[0]);
221       lines[i] = allocated_line;
222     }
223
224   hlen++;
225
226   /* The line where we start the search. */
227   i = orig_line;
228
229   rl_save_prompt ();
230
231   /* Initialize search parameters. */
232   search_string = (char *)xmalloc (search_string_size = 128);
233   *search_string = '\0';
234   search_string_index = 0;
235   prev_line_found = (char *)0;          /* XXX */
236
237   /* Normalize DIRECTION into 1 or -1. */
238   direction = (direction >= 0) ? 1 : -1;
239
240   rl_display_search (search_string, reverse, -1);
241
242   sline = rl_line_buffer;
243   sline_len = strlen (sline);
244   line_index = rl_point;
245
246   found = failed = 0;
247   for (;;)
248     {
249       rl_command_func_t *f = (rl_command_func_t *)NULL;
250
251       /* Read a key and decide how to proceed. */
252       RL_SETSTATE(RL_STATE_MOREINPUT);
253       c = rl_read_key ();
254       RL_UNSETSTATE(RL_STATE_MOREINPUT);
255
256 #if defined (HANDLE_MULTIBYTE)
257       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
258         c = _rl_read_mbstring (c, mb, MB_LEN_MAX);
259 #endif
260
261       /* Translate the keys we do something with to opcodes. */
262       if (c >= 0 && _rl_keymap[c].type == ISFUNC)
263         {
264           f = _rl_keymap[c].function;
265
266           if (f == rl_reverse_search_history)
267             c = reverse ? -1 : -2;
268           else if (f == rl_forward_search_history)
269             c =  !reverse ? -1 : -2;
270           else if (f == rl_rubout)
271             c = -3;
272           else if (c == CTRL ('G'))
273             c = -4;
274           else if (c == CTRL ('W'))     /* XXX */
275             c = -5;
276           else if (c == CTRL ('Y'))     /* XXX */
277             c = -6;
278         }
279
280       /* The characters in isearch_terminators (set from the user-settable
281          variable isearch-terminators) are used to terminate the search but
282          not subsequently execute the character as a command.  The default
283          value is "\033\012" (ESC and C-J). */
284       if (strchr (isearch_terminators, c))
285         {
286           /* ESC still terminates the search, but if there is pending
287              input or if input arrives within 0.1 seconds (on systems
288              with select(2)) it is used as a prefix character
289              with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
290              to allow the arrow keys to be used like ^F and ^B are used
291              to terminate the search and execute the movement command.
292              XXX - since _rl_input_available depends on the application-
293              settable keyboard timeout value, this could alternatively
294              use _rl_input_queued(100000) */
295           if (c == ESC && _rl_input_available ())
296             rl_execute_next (ESC);
297           break;
298         }
299
300 #define ENDSRCH_CHAR(c) \
301   ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
302
303 #if defined (HANDLE_MULTIBYTE)
304       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
305         {
306           if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c))
307             {
308               /* This sets rl_pending_input to c; it will be picked up the next
309                  time rl_read_key is called. */
310               rl_execute_next (c);
311               break;
312             }
313         }
314       else
315 #endif
316       if (c >= 0 && ENDSRCH_CHAR (c))
317         {
318           /* This sets rl_pending_input to c; it will be picked up the next
319              time rl_read_key is called. */
320           rl_execute_next (c);
321           break;
322         }
323
324       switch (c)
325         {
326         case -1:
327           if (search_string_index == 0)
328             {
329               if (last_isearch_string)
330                 {
331                   search_string_size = 64 + last_isearch_string_len;
332                   search_string = (char *)xrealloc (search_string, search_string_size);
333                   strcpy (search_string, last_isearch_string);
334                   search_string_index = last_isearch_string_len;
335                   rl_display_search (search_string, reverse, -1);
336                   break;
337                 }
338               continue;
339             }
340           else if (reverse)
341             --line_index;
342           else if (line_index != sline_len)
343             ++line_index;
344           else
345             rl_ding ();
346           break;
347
348           /* switch directions */
349         case -2:
350           direction = -direction;
351           reverse = direction < 0;
352           break;
353
354         /* delete character from search string. */
355         case -3:        /* C-H, DEL */
356           /* This is tricky.  To do this right, we need to keep a
357              stack of search positions for the current search, with
358              sentinels marking the beginning and end.  But this will
359              do until we have a real isearch-undo. */
360           if (search_string_index == 0)
361             rl_ding ();
362           else
363             search_string[--search_string_index] = '\0';
364
365           break;
366
367         case -4:        /* C-G */
368           rl_replace_line (lines[orig_line], 0);
369           rl_point = orig_point;
370           rl_mark = orig_mark;
371           rl_restore_prompt();
372           rl_clear_message ();
373           if (allocated_line)
374             free (allocated_line);
375           free (lines);
376           RL_UNSETSTATE(RL_STATE_ISEARCH);
377           return 0;
378
379         case -5:        /* C-W */
380           /* skip over portion of line we already matched */
381           wstart = rl_point + search_string_index;
382           if (wstart >= rl_end)
383             {
384               rl_ding ();
385               break;
386             }
387
388           /* if not in a word, move to one. */
389           if (rl_alphabetic(rl_line_buffer[wstart]) == 0)
390             {
391               rl_ding ();
392               break;
393             }
394           n = wstart;
395           while (n < rl_end && rl_alphabetic(rl_line_buffer[n]))
396             n++;
397           wlen = n - wstart + 1;
398           if (search_string_index + wlen + 1 >= search_string_size)
399             {
400               search_string_size += wlen + 1;
401               search_string = (char *)xrealloc (search_string, search_string_size);
402             }
403           for (; wstart < n; wstart++)
404             search_string[search_string_index++] = rl_line_buffer[wstart];
405           search_string[search_string_index] = '\0';
406           break;
407
408         case -6:        /* C-Y */
409           /* skip over portion of line we already matched */
410           wstart = rl_point + search_string_index;
411           if (wstart >= rl_end)
412             {
413               rl_ding ();
414               break;
415             }
416           n = rl_end - wstart + 1;
417           if (search_string_index + n + 1 >= search_string_size)
418             {
419               search_string_size += n + 1;
420               search_string = (char *)xrealloc (search_string, search_string_size);
421             }
422           for (n = wstart; n < rl_end; n++)
423             search_string[search_string_index++] = rl_line_buffer[n];
424           search_string[search_string_index] = '\0';
425           break;
426
427         default:
428           /* Add character to search string and continue search. */
429           if (search_string_index + 2 >= search_string_size)
430             {
431               search_string_size += 128;
432               search_string = (char *)xrealloc (search_string, search_string_size);
433             }
434 #if defined (HANDLE_MULTIBYTE)
435           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
436             {
437               int j, l;
438               for (j = 0, l = strlen (mb); j < l; )
439                 search_string[search_string_index++] = mb[j++];
440             }
441           else
442 #endif
443             search_string[search_string_index++] = c;
444           search_string[search_string_index] = '\0';
445           break;
446         }
447
448       for (found = failed = 0;;)
449         {
450           int limit = sline_len - search_string_index + 1;
451
452           /* Search the current line. */
453           while (reverse ? (line_index >= 0) : (line_index < limit))
454             {
455               if (STREQN (search_string, sline + line_index, search_string_index))
456                 {
457                   found++;
458                   break;
459                 }
460               else
461                 line_index += direction;
462             }
463           if (found)
464             break;
465
466           /* Move to the next line, but skip new copies of the line
467              we just found and lines shorter than the string we're
468              searching for. */
469           do
470             {
471               /* Move to the next line. */
472               i += direction;
473
474               /* At limit for direction? */
475               if (reverse ? (i < 0) : (i == hlen))
476                 {
477                   failed++;
478                   break;
479                 }
480
481               /* We will need these later. */
482               sline = lines[i];
483               sline_len = strlen (sline);
484             }
485           while ((prev_line_found && STREQ (prev_line_found, lines[i])) ||
486                  (search_string_index > sline_len));
487
488           if (failed)
489             break;
490
491           /* Now set up the line for searching... */
492           line_index = reverse ? sline_len - search_string_index : 0;
493         }
494
495       if (failed)
496         {
497           /* We cannot find the search string.  Ding the bell. */
498           rl_ding ();
499           i = last_found_line;
500           continue;             /* XXX - was break */
501         }
502
503       /* We have found the search string.  Just display it.  But don't
504          actually move there in the history list until the user accepts
505          the location. */
506       if (found)
507         {
508           prev_line_found = lines[i];
509           rl_replace_line (lines[i], 0);
510           rl_point = line_index;
511           last_found_line = i;
512           rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
513         }
514     }
515
516   /* The searching is over.  The user may have found the string that she
517      was looking for, or else she may have exited a failing search.  If
518      LINE_INDEX is -1, then that shows that the string searched for was
519      not found.  We use this to determine where to place rl_point. */
520
521   /* First put back the original state. */
522   strcpy (rl_line_buffer, lines[orig_line]);
523
524   rl_restore_prompt ();
525
526   /* Save the search string for possible later use. */
527   FREE (last_isearch_string);
528   last_isearch_string = search_string;
529   last_isearch_string_len = search_string_index;
530
531   if (last_found_line < orig_line)
532     rl_get_previous_history (orig_line - last_found_line, 0);
533   else
534     rl_get_next_history (last_found_line - orig_line, 0);
535
536   /* If the string was not found, put point at the end of the last matching
537      line.  If last_found_line == orig_line, we didn't find any matching
538      history lines at all, so put point back in its original position. */
539   if (line_index < 0)
540     {
541       if (last_found_line == orig_line)
542         line_index = orig_point;
543       else
544         line_index = strlen (rl_line_buffer);
545       rl_mark = orig_mark;
546     }
547
548   rl_point = line_index;
549   /* Don't worry about where to put the mark here; rl_get_previous_history
550      and rl_get_next_history take care of it. */
551
552   rl_clear_message ();
553
554   FREE (allocated_line);
555   free (lines);
556
557   RL_UNSETSTATE(RL_STATE_ISEARCH);
558
559   return 0;
560 }