1 /* search.c - code for non-incremental searching in emacs and vi modes. */
3 /* Copyright (C) 1992 Free Software Foundation, Inc.
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
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)
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.
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
25 #include <sys/types.h>
28 #if defined (HAVE_UNISTD_H)
36 #define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
37 #define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
39 #define abs(x) (((x) > 0) ? (x) : -(x))
41 extern char *xmalloc (), *xrealloc ();
43 /* Variables imported from readline.c */
44 extern int rl_point, rl_end, rl_line_buffer_len;
45 extern Keymap _rl_keymap;
46 extern int rl_editing_mode;
47 extern char *rl_prompt;
48 extern char *rl_line_buffer;
49 extern HIST_ENTRY *saved_line_for_history;
50 extern Function *rl_last_func;
52 /* Functions imported from the rest of the library. */
53 extern int _rl_free_history_entry ();
55 static char *noninc_search_string = (char *) NULL;
56 static int noninc_history_pos = 0;
57 static char *prev_line_found = (char *) NULL;
59 /* Search the history list for STRING starting at absolute history position
60 POS. If STRING begins with `^', the search must match STRING at the
61 beginning of a history line, otherwise a full substring match is performed
62 for STRING. DIR < 0 means to search backwards through the history list,
63 DIR >= 0 means to search forward. */
65 noninc_search_from_pos (string, pos, dir)
71 old = where_history ();
72 history_set_pos (pos);
75 ret = history_search_prefix (string + 1, dir);
77 ret = history_search (string, dir);
80 ret = where_history ();
82 history_set_pos (old);
86 /* Search for a line in the history containing STRING. If DIR is < 0, the
87 search is backwards through previous entries, else through subsequent
90 noninc_dosearch (string, dir)
97 if (string == 0 || *string == '\0' || noninc_history_pos < 0)
103 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
106 /* Search failed, current history position unchanged. */
107 maybe_unsave_line ();
114 noninc_history_pos = pos;
116 oldpos = where_history ();
117 history_set_pos (noninc_history_pos);
118 entry = current_history ();
119 #if defined (VI_MODE)
120 if (rl_editing_mode != vi_mode)
122 history_set_pos (oldpos);
127 line_len = strlen (entry->line);
128 if (line_len >= rl_line_buffer_len)
129 rl_extend_line_buffer (line_len);
130 strcpy (rl_line_buffer, entry->line);
133 rl_undo_list = (UNDO_LIST *)entry->data;
134 rl_end = strlen (rl_line_buffer);
138 if (saved_line_for_history)
139 _rl_free_history_entry (saved_line_for_history);
140 saved_line_for_history = (HIST_ENTRY *)NULL;
143 /* Search non-interactively through the history list. DIR < 0 means to
144 search backwards through the history of previous commands; otherwise
145 the search is for commands subsequent to the current position in the
146 history list. PCHAR is the character to use for prompting when reading
147 the search string; if not specified (0), it defaults to `:'. */
149 noninc_search (dir, pchar)
153 int saved_point, c, pmtlen;
157 saved_point = rl_point;
159 /* Use the line buffer to read the search string. */
160 rl_line_buffer[0] = 0;
161 rl_end = rl_point = 0;
163 /* XXX - this needs fixing to work with the prompt expansion stuff - XXX */
164 pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
165 p = xmalloc (2 + pmtlen);
167 strcpy (p, rl_prompt);
168 p[pmtlen] = pchar ? pchar : ':';
169 p[pmtlen + 1] = '\0';
171 rl_message (p, 0, 0);
174 /* Read the search string. */
175 while (c = rl_read_key ())
183 maybe_unsave_line ();
185 rl_point = saved_point;
192 rl_unix_word_rubout (1, c);
196 rl_unix_line_discard (1, c);
207 maybe_unsave_line ();
209 rl_point = saved_point;
221 /* If rl_point == 0, we want to re-use the previous search string and
222 start from the saved history position. If there's no previous search
226 if (!noninc_search_string)
234 /* We want to start the search from the current history position. */
235 noninc_history_pos = where_history ();
236 if (noninc_search_string)
237 free (noninc_search_string);
238 noninc_search_string = savestring (rl_line_buffer);
241 noninc_dosearch (noninc_search_string, dir);
244 /* Search forward through the history list for a string. If the vi-mode
245 code calls this, KEY will be `?'. */
246 rl_noninc_forward_search (count, key)
250 noninc_search (1, '?');
252 noninc_search (1, 0);
256 /* Reverse search the history list for a string. If the vi-mode code
257 calls this, KEY will be `/'. */
258 rl_noninc_reverse_search (count, key)
262 noninc_search (-1, '/');
264 noninc_search (-1, 0);
268 /* Search forward through the history list for the last string searched
269 for. If there is no saved search string, abort. */
270 rl_noninc_forward_search_again (count, key)
273 if (!noninc_search_string)
278 noninc_dosearch (noninc_search_string, 1);
282 /* Reverse search in the history list for the last string searched
283 for. If there is no saved search string, abort. */
284 rl_noninc_reverse_search_again (count, key)
287 if (!noninc_search_string)
292 noninc_dosearch (noninc_search_string, -1);
297 rl_history_search_internal (count, direction)
298 int count, direction;
300 HIST_ENTRY *temp, *old_temp;
305 temp = old_temp = (HIST_ENTRY *)NULL;
308 temp = (direction < 0) ? previous_history () : next_history ();
311 if (STREQN (rl_line_buffer, temp->line, rl_point))
313 /* Don't find multiple instances of the same line. */
314 if (prev_line_found && STREQ (prev_line_found, temp->line))
318 prev_line_found = temp->line;
325 if (direction < 0 && old_temp)
329 maybe_unsave_line ();
335 line_len = strlen (temp->line);
336 if (line_len >= rl_line_buffer_len)
337 rl_extend_line_buffer (line_len);
338 strcpy (rl_line_buffer, temp->line);
339 rl_undo_list = (UNDO_LIST *)temp->data;
344 /* Search forward in the history for the string of characters
345 from the start of the line to rl_point. This is a non-incremental
348 rl_history_search_forward (count, ignore)
353 if (rl_last_func != rl_history_search_forward)
354 prev_line_found = (char *)NULL;
355 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
358 /* Search backward through the history for the string of characters
359 from the start of the line to rl_point. This is a non-incremental
362 rl_history_search_backward (count, ignore)
367 if (rl_last_func != rl_history_search_backward)
368 prev_line_found = (char *)NULL;
369 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));