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

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