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

Revision 12992, 9.0 KB checked in by kcr, 25 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/* search.c - code for non-incremental searching in emacs and vi modes. */
2
3/* Copyright (C) 1992 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 1, 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   675 Mass Ave, Cambridge, MA 02139, 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 "readline.h"
44#include "history.h"
45
46#ifdef abs
47#  undef abs
48#endif
49#define abs(x)          (((x) >= 0) ? (x) : -(x))
50
51extern char *xmalloc (), *xrealloc ();
52
53/* Variables imported from readline.c */
54extern int rl_point, rl_end, rl_line_buffer_len;
55extern int rl_editing_mode;
56extern char *rl_prompt;
57extern char *rl_line_buffer;
58extern HIST_ENTRY *saved_line_for_history;
59extern Function *rl_last_func;
60
61/* Functions imported from the rest of the library. */
62extern int _rl_free_history_entry ();
63extern char *_rl_make_prompt_for_search ();
64extern void rl_extend_line_buffer ();
65
66static char *noninc_search_string = (char *) NULL;
67static int noninc_history_pos;
68static char *prev_line_found = (char *) NULL;
69
70/* Search the history list for STRING starting at absolute history position
71   POS.  If STRING begins with `^', the search must match STRING at the
72   beginning of a history line, otherwise a full substring match is performed
73   for STRING.  DIR < 0 means to search backwards through the history list,
74   DIR >= 0 means to search forward. */
75static int
76noninc_search_from_pos (string, pos, dir)
77     char *string;
78     int pos, dir;
79{
80  int ret, old;
81
82  old = where_history ();
83  history_set_pos (pos);
84
85  if (*string == '^')
86    ret = history_search_prefix (string + 1, dir);
87  else
88    ret = history_search (string, dir);
89
90  if (ret != -1)
91    ret = where_history ();
92
93  history_set_pos (old);
94  return (ret);
95}
96
97/* Search for a line in the history containing STRING.  If DIR is < 0, the
98   search is backwards through previous entries, else through subsequent
99   entries. */
100static void
101noninc_dosearch (string, dir)
102     char *string;
103     int dir;
104{
105  int oldpos, pos, line_len;
106  HIST_ENTRY *entry;
107
108  if (string == 0 || *string == '\0' || noninc_history_pos < 0)
109    {
110      ding ();
111      return;
112    }
113
114  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
115  if (pos == -1)
116    {
117      /* Search failed, current history position unchanged. */
118      maybe_unsave_line ();
119      rl_clear_message ();
120      rl_point = 0;
121      ding ();
122      return;
123    }
124
125  noninc_history_pos = pos;
126
127  oldpos = where_history ();
128  history_set_pos (noninc_history_pos);
129  entry = current_history ();
130#if defined (VI_MODE)
131  if (rl_editing_mode != vi_mode)
132#endif
133  history_set_pos (oldpos);
134
135  line_len = strlen (entry->line);
136  if (line_len >= rl_line_buffer_len)
137    rl_extend_line_buffer (line_len);
138  strcpy (rl_line_buffer, entry->line);
139
140  rl_undo_list = (UNDO_LIST *)entry->data;
141  rl_end = strlen (rl_line_buffer);
142  rl_point = 0;
143  rl_clear_message ();
144
145  if (saved_line_for_history)
146    _rl_free_history_entry (saved_line_for_history);
147  saved_line_for_history = (HIST_ENTRY *)NULL;
148}
149
150/* Search non-interactively through the history list.  DIR < 0 means to
151   search backwards through the history of previous commands; otherwise
152   the search is for commands subsequent to the current position in the
153   history list.  PCHAR is the character to use for prompting when reading
154   the search string; if not specified (0), it defaults to `:'. */
155static void
156noninc_search (dir, pchar)
157     int dir;
158     int pchar;
159{
160  int saved_point, c;
161  char *p;
162
163  maybe_save_line ();
164  saved_point = rl_point;
165
166  /* Use the line buffer to read the search string. */
167  rl_line_buffer[0] = 0;
168  rl_end = rl_point = 0;
169
170  p = _rl_make_prompt_for_search (pchar ? pchar : ':');
171  rl_message (p, 0, 0);
172  free (p);
173
174#define SEARCH_RETURN rl_restore_prompt (); return
175
176  /* Read the search string. */
177  while (c = rl_read_key ())
178    {
179      switch (c)
180        {
181        case CTRL('H'):
182        case RUBOUT:
183          if (rl_point == 0)
184            {
185              maybe_unsave_line ();
186              rl_clear_message ();
187              rl_point = saved_point;
188              SEARCH_RETURN;
189            }
190          rl_rubout (1, c);
191          break;
192
193        case CTRL('W'):
194          rl_unix_word_rubout (1, c);
195          break;
196
197        case CTRL('U'):
198          rl_unix_line_discard (1, c);
199          break;
200
201        case RETURN:
202        case NEWLINE:
203          goto dosearch;
204          /* NOTREACHED */
205          break;
206
207        case CTRL('C'):
208        case CTRL('G'):
209          maybe_unsave_line ();
210          rl_clear_message ();
211          rl_point = saved_point;
212          ding ();
213          SEARCH_RETURN;
214
215        default:
216          rl_insert (1, c);
217          break;
218        }
219      (*rl_redisplay_function) ();
220    }
221
222 dosearch:
223  /* If rl_point == 0, we want to re-use the previous search string and
224     start from the saved history position.  If there's no previous search
225     string, punt. */
226  if (rl_point == 0)
227    {
228      if (!noninc_search_string)
229        {
230          ding ();
231          SEARCH_RETURN;
232        }
233    }
234  else
235    {
236      /* We want to start the search from the current history position. */
237      noninc_history_pos = where_history ();
238      if (noninc_search_string)
239        free (noninc_search_string);
240      noninc_search_string = savestring (rl_line_buffer);
241    }
242
243  rl_restore_prompt ();
244  noninc_dosearch (noninc_search_string, dir);
245}
246
247/* Search forward through the history list for a string.  If the vi-mode
248   code calls this, KEY will be `?'. */
249int
250rl_noninc_forward_search (count, key)
251     int count, key;
252{
253  noninc_search (1, (key == '?') ? '?' : 0);
254  return 0;
255}
256
257/* Reverse search the history list for a string.  If the vi-mode code
258   calls this, KEY will be `/'. */
259int
260rl_noninc_reverse_search (count, key)
261     int count, key;
262{
263  noninc_search (-1, (key == '/') ? '/' : 0);
264  return 0;
265}
266
267/* Search forward through the history list for the last string searched
268   for.  If there is no saved search string, abort. */
269int
270rl_noninc_forward_search_again (count, key)
271     int count, key;
272{
273  if (!noninc_search_string)
274    {
275      ding ();
276      return (-1);
277    }
278  noninc_dosearch (noninc_search_string, 1);
279  return 0;
280}
281
282/* Reverse search in the history list for the last string searched
283   for.  If there is no saved search string, abort. */
284int
285rl_noninc_reverse_search_again (count, key)
286     int count, key;
287{
288  if (!noninc_search_string)
289    {
290      ding ();
291      return (-1);
292    }
293  noninc_dosearch (noninc_search_string, -1);
294  return 0;
295}
296
297static int
298rl_history_search_internal (count, direction)
299     int count, direction;
300{
301  HIST_ENTRY *temp, *old_temp;
302  int line_len;
303
304  maybe_save_line ();
305
306  temp = old_temp = (HIST_ENTRY *)NULL;
307  while (count)
308    {
309      temp = (direction < 0) ? previous_history () : next_history ();
310      if (temp == 0)
311        break;
312      /* On an empty prefix, make this the same as previous-history. */
313      if (rl_point == 0)
314        {
315          count--;
316          continue;
317        }
318      if (STREQN (rl_line_buffer, temp->line, rl_point))
319        {
320          /* Don't find multiple instances of the same line. */
321          if (prev_line_found && STREQ (prev_line_found, temp->line))
322            continue;
323          if (direction < 0)
324            old_temp = temp;
325          prev_line_found = temp->line;
326          count--;
327        }
328    }
329
330  if (temp == 0)
331    {
332      if (direction < 0 && old_temp)
333        temp = old_temp;
334      else
335        {
336          maybe_unsave_line ();
337          ding ();
338          return 1;
339        }
340    }
341
342  line_len = strlen (temp->line);
343  if (line_len >= rl_line_buffer_len)
344    rl_extend_line_buffer (line_len);
345  strcpy (rl_line_buffer, temp->line);
346  rl_undo_list = (UNDO_LIST *)temp->data;
347  rl_end = line_len;
348  return 0;
349}
350
351/* Search forward in the history for the string of characters
352   from the start of the line to rl_point.  This is a non-incremental
353   search. */
354int
355rl_history_search_forward (count, ignore)
356     int count, ignore;
357{
358  if (count == 0)
359    return (0);
360  if (rl_last_func != rl_history_search_forward)
361    prev_line_found = (char *)NULL;
362  return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
363}
364
365/* Search backward through the history for the string of characters
366   from the start of the line to rl_point.  This is a non-incremental
367   search. */
368int
369rl_history_search_backward (count, ignore)
370     int count, ignore;
371{
372  if (count == 0)
373    return (0);
374  if (rl_last_func != rl_history_search_backward)
375    prev_line_found = (char *)NULL;
376  return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
377}
Note: See TracBrowser for help on using the repository browser.