Tell the user more explicitly what port needs to be installed to get the
[dragonfly.git] / contrib / libreadline / search.c
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 2, 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    59 Temple Place, Suite 330, Boston, MA 02111 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 #include "rlprivate.h"
47 #include "xmalloc.h"
48
49 #ifdef abs
50 #  undef abs
51 #endif
52 #define abs(x)          (((x) >= 0) ? (x) : -(x))
53
54 extern HIST_ENTRY *saved_line_for_history;
55
56 /* Functions imported from the rest of the library. */
57 extern int _rl_free_history_entry __P((HIST_ENTRY *));
58
59 static char *noninc_search_string = (char *) NULL;
60 static int noninc_history_pos;
61
62 static char *prev_line_found = (char *) NULL;
63
64 static int rl_history_search_len;
65 static int rl_history_search_pos;
66 static char *history_search_string;
67 static int history_string_size;
68
69 /* Make the data from the history entry ENTRY be the contents of the
70    current line.  This doesn't do anything with rl_point; the caller
71    must set it. */
72 static void
73 make_history_line_current (entry)
74      HIST_ENTRY *entry;
75 {
76   int line_len;
77
78   line_len = strlen (entry->line);
79   if (line_len >= rl_line_buffer_len)
80     rl_extend_line_buffer (line_len);
81   strcpy (rl_line_buffer, entry->line);
82
83   rl_undo_list = (UNDO_LIST *)entry->data;
84   rl_end = line_len;
85
86   if (saved_line_for_history)
87     _rl_free_history_entry (saved_line_for_history);
88   saved_line_for_history = (HIST_ENTRY *)NULL;
89 }
90
91 /* Search the history list for STRING starting at absolute history position
92    POS.  If STRING begins with `^', the search must match STRING at the
93    beginning of a history line, otherwise a full substring match is performed
94    for STRING.  DIR < 0 means to search backwards through the history list,
95    DIR >= 0 means to search forward. */
96 static int
97 noninc_search_from_pos (string, pos, dir)
98      char *string;
99      int pos, dir;
100 {
101   int ret, old;
102
103   old = where_history ();
104   history_set_pos (pos);
105
106   if (*string == '^')
107     ret = history_search_prefix (string + 1, dir);
108   else
109     ret = history_search (string, dir);
110
111   if (ret != -1)
112     ret = where_history ();
113
114   history_set_pos (old);
115   return (ret);
116 }
117
118 /* Search for a line in the history containing STRING.  If DIR is < 0, the
119    search is backwards through previous entries, else through subsequent
120    entries. */
121 static void
122 noninc_dosearch (string, dir)
123      char *string;
124      int dir;
125 {
126   int oldpos, pos;
127   HIST_ENTRY *entry;
128
129   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
130     {
131       ding ();
132       return;
133     }
134
135   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
136   if (pos == -1)
137     {
138       /* Search failed, current history position unchanged. */
139       maybe_unsave_line ();
140       rl_clear_message ();
141       rl_point = 0;
142       ding ();
143       return;
144     }
145
146   noninc_history_pos = pos;
147
148   oldpos = where_history ();
149   history_set_pos (noninc_history_pos);
150   entry = current_history ();
151 #if defined (VI_MODE)
152   if (rl_editing_mode != vi_mode)
153 #endif
154   history_set_pos (oldpos);
155
156   make_history_line_current (entry);
157
158   rl_point = 0;
159   rl_clear_message ();
160 }
161
162 /* Search non-interactively through the history list.  DIR < 0 means to
163    search backwards through the history of previous commands; otherwise
164    the search is for commands subsequent to the current position in the
165    history list.  PCHAR is the character to use for prompting when reading
166    the search string; if not specified (0), it defaults to `:'. */
167 static void
168 noninc_search (dir, pchar)
169      int dir;
170      int pchar;
171 {
172   int saved_point, c;
173   char *p;
174
175   maybe_save_line ();
176   saved_point = rl_point;
177
178   /* Use the line buffer to read the search string. */
179   rl_line_buffer[0] = 0;
180   rl_end = rl_point = 0;
181
182   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
183   rl_message (p, 0, 0);
184   free (p);
185
186 #define SEARCH_RETURN rl_restore_prompt (); return
187
188   /* Read the search string. */
189   while (c = rl_read_key ())
190     {
191       switch (c)
192         {
193         case CTRL('H'):
194         case RUBOUT:
195           if (rl_point == 0)
196             {
197               maybe_unsave_line ();
198               rl_clear_message ();
199               rl_point = saved_point;
200               SEARCH_RETURN;
201             }
202           rl_rubout (1, c);
203           break;
204
205         case CTRL('W'):
206           rl_unix_word_rubout (1, c);
207           break;
208
209         case CTRL('U'):
210           rl_unix_line_discard (1, c);
211           break;
212
213         case RETURN:
214         case NEWLINE:
215           goto dosearch;
216           /* NOTREACHED */
217           break;
218
219         case CTRL('C'):
220         case CTRL('G'):
221           maybe_unsave_line ();
222           rl_clear_message ();
223           rl_point = saved_point;
224           ding ();
225           SEARCH_RETURN;
226
227         default:
228           rl_insert (1, c);
229           break;
230         }
231       (*rl_redisplay_function) ();
232     }
233
234  dosearch:
235   /* If rl_point == 0, we want to re-use the previous search string and
236      start from the saved history position.  If there's no previous search
237      string, punt. */
238   if (rl_point == 0)
239     {
240       if (!noninc_search_string)
241         {
242           ding ();
243           SEARCH_RETURN;
244         }
245     }
246   else
247     {
248       /* We want to start the search from the current history position. */
249       noninc_history_pos = where_history ();
250       FREE (noninc_search_string);
251       noninc_search_string = savestring (rl_line_buffer);
252     }
253
254   rl_restore_prompt ();
255   noninc_dosearch (noninc_search_string, dir);
256 }
257
258 /* Search forward through the history list for a string.  If the vi-mode
259    code calls this, KEY will be `?'. */
260 int
261 rl_noninc_forward_search (count, key)
262      int count, key;
263 {
264   noninc_search (1, (key == '?') ? '?' : 0);
265   return 0;
266 }
267
268 /* Reverse search the history list for a string.  If the vi-mode code
269    calls this, KEY will be `/'. */
270 int
271 rl_noninc_reverse_search (count, key)
272      int count, key;
273 {
274   noninc_search (-1, (key == '/') ? '/' : 0);
275   return 0;
276 }
277
278 /* Search forward through the history list for the last string searched
279    for.  If there is no saved search string, abort. */
280 int
281 rl_noninc_forward_search_again (count, key)
282      int count, key;
283 {
284   if (!noninc_search_string)
285     {
286       ding ();
287       return (-1);
288     }
289   noninc_dosearch (noninc_search_string, 1);
290   return 0;
291 }
292
293 /* Reverse search in the history list for the last string searched
294    for.  If there is no saved search string, abort. */
295 int
296 rl_noninc_reverse_search_again (count, key)
297      int count, key;
298 {
299   if (!noninc_search_string)
300     {
301       ding ();
302       return (-1);
303     }
304   noninc_dosearch (noninc_search_string, -1);
305   return 0;
306 }
307
308 static int
309 rl_history_search_internal (count, dir)
310      int count, dir;
311 {
312   HIST_ENTRY *temp;
313   int ret, oldpos;
314
315   maybe_save_line ();
316   temp = (HIST_ENTRY *)NULL;
317
318   /* Search COUNT times through the history for a line whose prefix
319      matches history_search_string.  When this loop finishes, TEMP,
320      if non-null, is the history line to copy into the line buffer. */
321   while (count)
322     {
323       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
324       if (ret == -1)
325         break;
326
327       /* Get the history entry we found. */
328       rl_history_search_pos = ret;
329       oldpos = where_history ();
330       history_set_pos (rl_history_search_pos);
331       temp = current_history ();
332       history_set_pos (oldpos);
333
334       /* Don't find multiple instances of the same line. */
335       if (prev_line_found && STREQ (prev_line_found, temp->line))
336         continue;
337       prev_line_found = temp->line;
338       count--;
339     }
340
341   /* If we didn't find anything at all, return. */
342   if (temp == 0)
343     {
344       maybe_unsave_line ();
345       ding ();
346       /* If you don't want the saved history line (last match) to show up
347          in the line buffer after the search fails, change the #if 0 to
348          #if 1 */
349 #if 0
350       if (rl_point > rl_history_search_len)
351         {
352           rl_point = rl_end = rl_history_search_len;
353           rl_line_buffer[rl_end] = '\0';
354         }
355 #else
356       rl_point = rl_history_search_len; /* maybe_unsave_line changes it */
357 #endif
358       return 1;
359     }
360
361   /* Copy the line we found into the current line buffer. */
362   make_history_line_current (temp);
363
364   rl_point = rl_history_search_len;
365   return 0;
366 }
367
368 static void
369 rl_history_search_reinit ()
370 {
371   rl_history_search_pos = where_history ();
372   rl_history_search_len = rl_point;
373   prev_line_found = (char *)NULL;
374   if (rl_point)
375     {
376       if (rl_history_search_len >= history_string_size - 2)
377         {
378           history_string_size = rl_history_search_len + 2;
379           history_search_string = xrealloc (history_search_string, history_string_size);
380         }
381       history_search_string[0] = '^';
382       strncpy (history_search_string + 1, rl_line_buffer, rl_point);
383       history_search_string[rl_point + 1] = '\0';
384     }
385 }
386
387 /* Search forward in the history for the string of characters
388    from the start of the line to rl_point.  This is a non-incremental
389    search. */
390 int
391 rl_history_search_forward (count, ignore)
392      int count, ignore;
393 {
394   if (count == 0)
395     return (0);
396
397   if (rl_last_func != rl_history_search_forward &&
398       rl_last_func != rl_history_search_backward)
399     rl_history_search_reinit ();
400
401   if (rl_history_search_len == 0)
402     return (rl_get_next_history (count, ignore));
403   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
404 }
405
406 /* Search backward through the history for the string of characters
407    from the start of the line to rl_point.  This is a non-incremental
408    search. */
409 int
410 rl_history_search_backward (count, ignore)
411      int count, ignore;
412 {
413   if (count == 0)
414     return (0);
415
416   if (rl_last_func != rl_history_search_forward &&
417       rl_last_func != rl_history_search_backward)
418     rl_history_search_reinit ();
419
420   if (rl_history_search_len == 0)
421     return (rl_get_previous_history (count, ignore));
422   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
423 }