source: trunk/third/readline/isearch.c @ 12992

Revision 12992, 11.7 KB checked in by kcr, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12991, which included commits to RCS files with non-trunk default branches.
Line 
1/* **************************************************************** */
2/*                                                                  */
3/*                      I-Search and Searching                      */
4/*                                                                  */
5/* **************************************************************** */
6
7/* Copyright (C) 1987,1989 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 1, 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   675 Mass Ave, Cambridge, MA 02139, 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 "readline.h"
49#include "history.h"
50
51/* Variables exported to other files in the readline library. */
52unsigned char *_rl_isearch_terminators = (unsigned char *)NULL;
53
54/* Variables imported from other files in the readline library. */
55extern Keymap _rl_keymap;
56extern HIST_ENTRY *saved_line_for_history;
57extern int rl_line_buffer_len;
58extern int rl_point, rl_end;
59extern char *rl_line_buffer;
60
61extern int rl_execute_next ();
62extern void rl_extend_line_buffer ();
63
64extern int _rl_input_available ();
65
66extern char *xmalloc (), *xrealloc ();
67
68static int rl_search_history ();
69
70/* Last line found by the current incremental search, so we don't `find'
71   identical lines many times in a row. */
72static char *prev_line_found;
73
74/* Search backwards through the history looking for a string which is typed
75   interactively.  Start with the current line. */
76int
77rl_reverse_search_history (sign, key)
78     int sign, key;
79{
80  return (rl_search_history (-sign, key));
81}
82
83/* Search forwards through the history looking for a string which is typed
84   interactively.  Start with the current line. */
85int
86rl_forward_search_history (sign, key)
87     int sign, key;
88{
89  return (rl_search_history (sign, key));
90}
91
92/* Display the current state of the search in the echo-area.
93   SEARCH_STRING contains the string that is being searched for,
94   DIRECTION is zero for forward, or 1 for reverse,
95   WHERE is the history list number of the current line.  If it is
96   -1, then this line is the starting one. */
97static void
98rl_display_search (search_string, reverse_p, where)
99     char *search_string;
100     int reverse_p, where;
101{
102  char *message;
103  int msglen, searchlen;
104
105  searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
106
107  message = xmalloc (searchlen + 33);
108  msglen = 0;
109
110#if defined (NOTDEF)
111  if (where != -1)
112    {
113      sprintf (message, "[%d]", where + history_base);
114      msglen = strlen (message);
115    }
116#endif /* NOTDEF */
117
118  message[msglen++] = '(';
119
120  if (reverse_p)
121    {
122      strcpy (message + msglen, "reverse-");
123      msglen += 8;
124    }
125
126  strcpy (message + msglen, "i-search)`");
127  msglen += 10;
128
129  if (search_string)
130    {
131      strcpy (message + msglen, search_string);
132      msglen += searchlen;
133    }
134
135  strcpy (message + msglen, "': ");
136
137  rl_message ("%s", message, 0);
138  free (message);
139  (*rl_redisplay_function) ();
140}
141
142/* Search through the history looking for an interactively typed string.
143   This is analogous to i-search.  We start the search in the current line.
144   DIRECTION is which direction to search; >= 0 means forward, < 0 means
145   backwards. */
146static int
147rl_search_history (direction, invoking_key)
148     int direction, invoking_key;
149{
150  /* The string that the user types in to search for. */
151  char *search_string;
152
153  /* The current length of SEARCH_STRING. */
154  int search_string_index;
155
156  /* The amount of space that SEARCH_STRING has allocated to it. */
157  int search_string_size;
158
159  /* The list of lines to search through. */
160  char **lines, *allocated_line;
161
162  /* The length of LINES. */
163  int hlen;
164
165  /* Where we get LINES from. */
166  HIST_ENTRY **hlist;
167
168  register int i;
169  int orig_point, orig_line, last_found_line;
170  int c, found, failed, sline_len;
171
172  /* The line currently being searched. */
173  char *sline;
174
175  /* Offset in that line. */
176  int line_index;
177
178  /* Non-zero if we are doing a reverse search. */
179  int reverse;
180
181  /* The list of characters which terminate the search, but are not
182     subsequently executed.  If the variable isearch-terminators has
183     been set, we use that value, otherwise we use ESC and C-J. */
184  unsigned char *isearch_terminators;
185
186  orig_point = rl_point;
187  last_found_line = orig_line = where_history ();
188  reverse = direction < 0;
189  hlist = history_list ();
190  allocated_line = (char *)NULL;
191
192  isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
193                                                : (unsigned char *)"\033\012";
194
195  /* Create an arrary of pointers to the lines that we want to search. */
196  maybe_replace_line ();
197  i = 0;
198  if (hlist)
199    for (i = 0; hlist[i]; i++);
200
201  /* Allocate space for this many lines, +1 for the current input line,
202     and remember those lines. */
203  lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *));
204  for (i = 0; i < hlen; i++)
205    lines[i] = hlist[i]->line;
206
207  if (saved_line_for_history)
208    lines[i] = saved_line_for_history->line;
209  else
210    {
211      /* Keep track of this so we can free it. */
212      allocated_line = xmalloc (1 + strlen (rl_line_buffer));
213      strcpy (allocated_line, &rl_line_buffer[0]);
214      lines[i] = allocated_line;
215    }
216
217  hlen++;
218
219  /* The line where we start the search. */
220  i = orig_line;
221
222  rl_save_prompt ();
223
224  /* Initialize search parameters. */
225  search_string = xmalloc (search_string_size = 128);
226  *search_string = '\0';
227  search_string_index = 0;
228  prev_line_found = (char *)0;          /* XXX */
229
230  /* Normalize DIRECTION into 1 or -1. */
231  direction = (direction >= 0) ? 1 : -1;
232
233  rl_display_search (search_string, reverse, -1);
234
235  sline = rl_line_buffer;
236  sline_len = strlen (sline);
237  line_index = rl_point;
238
239  found = failed = 0;
240  for (;;)
241    {
242      Function *f = (Function *)NULL;
243
244      /* Read a key and decide how to proceed. */
245      c = rl_read_key ();
246
247      if (_rl_keymap[c].type == ISFUNC)
248        {
249          f = _rl_keymap[c].function;
250
251          if (f == rl_reverse_search_history)
252            c = reverse ? -1 : -2;
253          else if (f == rl_forward_search_history)
254            c =  !reverse ? -1 : -2;
255        }
256
257#if 0
258      /* Let NEWLINE (^J) terminate the search for people who don't like
259         using ESC.  ^M can still be used to terminate the search and
260         immediately execute the command. */
261      if (c == ESC || c == NEWLINE)
262#else
263      /* The characters in isearch_terminators (set from the user-settable
264         variable isearch-terminators) are used to terminate the search but
265         not subsequently execute the character as a command.  The default
266         value is "\033\012" (ESC and C-J). */
267      if (strchr (isearch_terminators, c))
268#endif
269        {
270          /* ESC still terminates the search, but if there is pending
271             input or if input arrives within 0.1 seconds (on systems
272             with select(2)) it is used as a prefix character
273             with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
274             to allow the arrow keys to be used like ^F and ^B are used
275             to terminate the search and execute the movement command. */
276          if (c == ESC && _rl_input_available ())       /* XXX */
277            rl_execute_next (ESC);
278          break;
279        }
280
281      if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G'))
282        {
283          rl_execute_next (c);
284          break;
285        }
286
287      switch (c)
288        {
289        case -1:
290          if (search_string_index == 0)
291            continue;
292          else if (reverse)
293            --line_index;
294          else if (line_index != sline_len)
295            ++line_index;
296          else
297            ding ();
298          break;
299
300          /* switch directions */
301        case -2:
302          direction = -direction;
303          reverse = direction < 0;
304          break;
305
306        case CTRL ('G'):
307          strcpy (rl_line_buffer, lines[orig_line]);
308          rl_point = orig_point;
309          rl_end = strlen (rl_line_buffer);
310          rl_restore_prompt();
311          rl_clear_message ();
312          if (allocated_line)
313            free (allocated_line);
314          free (lines);
315          return 0;
316
317#if 0
318        /* delete character from search string. */
319        case -3:
320          if (search_string_index == 0)
321            ding ();
322          else
323            {
324              search_string[--search_string_index] = '\0';
325              /* This is tricky.  To do this right, we need to keep a
326                 stack of search positions for the current search, with
327                 sentinels marking the beginning and end. */
328            }
329          break;
330#endif
331
332        default:
333          /* Add character to search string and continue search. */
334          if (search_string_index + 2 >= search_string_size)
335            {
336              search_string_size += 128;
337              search_string = xrealloc (search_string, search_string_size);
338            }
339          search_string[search_string_index++] = c;
340          search_string[search_string_index] = '\0';
341          break;
342        }
343
344      for (found = failed = 0;;)
345        {
346          int limit = sline_len - search_string_index + 1;
347
348          /* Search the current line. */
349          while (reverse ? (line_index >= 0) : (line_index < limit))
350            {
351              if (STREQN (search_string, sline + line_index, search_string_index))
352                {
353                  found++;
354                  break;
355                }
356              else
357                line_index += direction;
358            }
359          if (found)
360            break;
361
362          /* Move to the next line, but skip new copies of the line
363             we just found and lines shorter than the string we're
364             searching for. */
365          do
366            {
367              /* Move to the next line. */
368              i += direction;
369
370              /* At limit for direction? */
371              if (reverse ? (i < 0) : (i == hlen))
372                {
373                  failed++;
374                  break;
375                }
376
377              /* We will need these later. */
378              sline = lines[i];
379              sline_len = strlen (sline);
380            }
381          while ((prev_line_found && STREQ (prev_line_found, lines[i])) ||
382                 (search_string_index > sline_len));
383
384          if (failed)
385            break;
386
387          /* Now set up the line for searching... */
388          line_index = reverse ? sline_len - search_string_index : 0;
389        }
390
391      if (failed)
392        {
393          /* We cannot find the search string.  Ding the bell. */
394          ding ();
395          i = last_found_line;
396          continue;             /* XXX - was break */
397        }
398
399      /* We have found the search string.  Just display it.  But don't
400         actually move there in the history list until the user accepts
401         the location. */
402      if (found)
403        {
404          int line_len;
405
406          prev_line_found = lines[i];
407          line_len = strlen (lines[i]);
408
409          if (line_len >= rl_line_buffer_len)
410            rl_extend_line_buffer (line_len);
411
412          strcpy (rl_line_buffer, lines[i]);
413          rl_point = line_index;
414          rl_end = line_len;
415          last_found_line = i;
416          rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
417        }
418    }
419
420  /* The searching is over.  The user may have found the string that she
421     was looking for, or else she may have exited a failing search.  If
422     LINE_INDEX is -1, then that shows that the string searched for was
423     not found.  We use this to determine where to place rl_point. */
424
425  /* First put back the original state. */
426  strcpy (rl_line_buffer, lines[orig_line]);
427
428  rl_restore_prompt ();
429
430  /* Free the search string. */
431  free (search_string);
432
433  if (last_found_line < orig_line)
434    rl_get_previous_history (orig_line - last_found_line, 0);
435  else
436    rl_get_next_history (last_found_line - orig_line, 0);
437
438  /* If the string was not found, put point at the end of the line. */
439  if (line_index < 0)
440    line_index = strlen (rl_line_buffer);
441  rl_point = line_index;
442  rl_clear_message ();
443
444  if (allocated_line)
445    free (allocated_line);
446  free (lines);
447
448  return 0;
449}
Note: See TracBrowser for help on using the repository browser.