/* histsearch.c -- searching the history list. */
-/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992-2009,2017 Free Software Foundation, Inc.
- This file contains the GNU History Library (the Library), a set of
+ This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
- The Library is free software; you can redistribute it and/or modify
+ History is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- The Library is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ History is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- The GNU General Public License is often shipped with GNU software, and
- is generally kept in a file called COPYING or LICENSE. If you do not
- have a copy of the license, write to the Free Software Foundation,
- 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+ You should have received a copy of the GNU General Public License
+ along with History. If not, see <http://www.gnu.org/licenses/>.
+*/
#define READLINE_LIBRARY
# include <unistd.h>
#endif
+#if defined (HAVE_FNMATCH)
+# include <fnmatch.h>
+#endif
+
#include "history.h"
#include "histlib.h"
+#include "xmalloc.h"
/* The list of alternate characters that can delimit a history search
string. */
returned. */
static int
-history_search_internal (string, direction, anchored)
- const char *string;
- int direction, anchored;
+history_search_internal (const char *string, int direction, int flags)
{
register int i, reverse;
register char *line;
register int line_index;
- int string_len;
+ int string_len, anchored, patsearch;
HIST_ENTRY **the_history; /* local */
i = history_offset;
reverse = (direction < 0);
+ anchored = (flags & ANCHORED_SEARCH);
+#if defined (HAVE_FNMATCH)
+ patsearch = (flags & PATTERN_SEARCH);
+#else
+ patsearch = 0;
+#endif
/* Take care of trivial cases first. */
if (string == 0 || *string == '\0')
return (-1);
- if (!history_length || ((i == history_length) && !reverse))
+ if (!history_length || ((i >= history_length) && !reverse))
return (-1);
- if (reverse && (i == history_length))
- i--;
+ if (reverse && (i >= history_length))
+ i = history_length - 1;
#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
line_index = strlen (line);
/* If STRING is longer than line, no match. */
- if (string_len > line_index)
+ if (patsearch == 0 && (string_len > line_index))
{
NEXT_LINE ();
continue;
/* Handle anchored searches first. */
if (anchored == ANCHORED_SEARCH)
{
+#if defined (HAVE_FNMATCH)
+ if (patsearch)
+ {
+ if (fnmatch (string, line, 0) == 0)
+ {
+ history_offset = i;
+ return (0);
+ }
+ }
+ else
+#endif
if (STREQN (string, line, string_len))
{
history_offset = i;
/* Do substring search. */
if (reverse)
{
- line_index -= string_len;
+ line_index -= (patsearch == 0) ? string_len : 1;
while (line_index >= 0)
{
+#if defined (HAVE_FNMATCH)
+ if (patsearch)
+ {
+ if (fnmatch (string, line + line_index, 0) == 0)
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ }
+ else
+#endif
if (STREQN (string, line + line_index, string_len))
{
history_offset = i;
while (line_index < limit)
{
+#if defined (HAVE_FNMATCH)
+ if (patsearch)
+ {
+ if (fnmatch (string, line + line_index, 0) == 0)
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ }
+ else
+#endif
if (STREQN (string, line + line_index, string_len))
{
history_offset = i;
}
}
+int
+_hs_history_patsearch (const char *string, int direction, int flags)
+{
+ char *pat;
+ size_t len, start;
+ int ret, unescaped_backslash;
+
+#if defined (HAVE_FNMATCH)
+ /* Assume that the string passed does not have a leading `^' and any
+ anchored search request is captured in FLAGS */
+ len = strlen (string);
+ ret = len - 1;
+ /* fnmatch is required to reject a pattern that ends with an unescaped
+ backslash */
+ if (unescaped_backslash = (string[ret] == '\\'))
+ {
+ while (ret > 0 && string[--ret] == '\\')
+ unescaped_backslash = 1 - unescaped_backslash;
+ }
+ if (unescaped_backslash)
+ return -1;
+ pat = (char *)xmalloc (len + 3);
+ /* If the search string is not anchored, we'll be calling fnmatch (assuming
+ we have it). Prefix a `*' to the front of the search string so we search
+ anywhere in the line. */
+ if ((flags & ANCHORED_SEARCH) == 0 && string[0] != '*')
+ {
+ pat[0] = '*';
+ start = 1;
+ len++;
+ }
+ else
+ {
+ start = 0;
+ }
+
+ /* Attempt to reduce the number of searches by tacking a `*' onto the end
+ of a pattern that doesn't have one. Assume a pattern that ends in a
+ backslash contains an even number of trailing backslashes; we check
+ above */
+ strcpy (pat + start, string);
+ if (pat[len - 1] != '*')
+ {
+ pat[len] = '*'; /* XXX */
+ pat[len+1] = '\0';
+ }
+#else
+ pat = string;
+#endif
+
+ ret = history_search_internal (pat, direction, flags|PATTERN_SEARCH);
+
+ if (pat != string)
+ free (pat);
+ return ret;
+}
+
/* Do a non-anchored search for STRING through the history in DIRECTION. */
int
-history_search (string, direction)
- const char *string;
- int direction;
+history_search (const char *string, int direction)
{
return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
}
/* Do an anchored search for string through the history in DIRECTION. */
int
-history_search_prefix (string, direction)
- const char *string;
- int direction;
+history_search_prefix (const char *string, int direction)
{
return (history_search_internal (string, direction, ANCHORED_SEARCH));
}
backwards. POS is an absolute index into the history list at
which point to begin searching. */
int
-history_search_pos (string, dir, pos)
- const char *string;
- int dir, pos;
+history_search_pos (const char *string, int dir, int pos)
{
int ret, old;