Import readline 8.0
[deliverable/binutils-gdb.git] / readline / histsearch.c
index 7e98e950acb1495c982a6c346931b7b67ab3a9e3..7a426c96781429785f1b44ad3241da43e63df545 100644 (file)
@@ -1,24 +1,23 @@
 /* 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 1, 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,
-   675 Mass Ave, Cambridge, MA 02139, 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
 
 #else
 #  include "ansi_stdlib.h"
 #endif /* HAVE_STDLIB_H */
+
 #if defined (HAVE_UNISTD_H)
 #  ifdef _MINIX
 #    include <sys/types.h>
 #  endif
 #  include <unistd.h>
 #endif
-#if defined (HAVE_STRING_H)
-#  include <string.h>
-#else
-#  include <strings.h>
-#endif /* !HAVE_STRING_H */
+
+#if defined (HAVE_FNMATCH)
+#  include <fnmatch.h>
+#endif
 
 #include "history.h"
 #include "histlib.h"
-
-/* Variables imported from other history library files. */
-extern int history_offset;
+#include "xmalloc.h"
 
 /* The list of alternate characters that can delimit a history search
    string. */
 char *history_search_delimiter_chars = (char *)NULL;
 
+static int history_search_internal PARAMS((const char *, int, int));
+
 /* Search the history for STRING, starting at history_offset.
    If DIRECTION < 0, then the search is through previous entries, else
    through subsequent.  If ANCHORED is non-zero, the string must
@@ -65,28 +64,32 @@ char *history_search_delimiter_chars = (char *)NULL;
    returned. */
 
 static int
-history_search_internal (string, direction, anchored)
-     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)
 
@@ -104,7 +107,7 @@ history_search_internal (string, direction, anchored)
       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;
@@ -113,6 +116,17 @@ history_search_internal (string, direction, anchored)
       /* 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;
@@ -126,10 +140,21 @@ history_search_internal (string, direction, anchored)
       /* 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;
@@ -147,6 +172,17 @@ history_search_internal (string, direction, anchored)
 
          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;
@@ -159,20 +195,73 @@ history_search_internal (string, direction, anchored)
     }
 }
 
+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)
-     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)
-     char *string;
-     int direction;
+history_search_prefix (const char *string, int direction)
 {
   return (history_search_internal (string, direction, ANCHORED_SEARCH));
 }
@@ -181,9 +270,7 @@ history_search_prefix (string, direction)
    backwards.  POS is an absolute index into the history list at
    which point to begin searching. */
 int
-history_search_pos (string, dir, pos)
-     char *string;
-     int dir, pos;
+history_search_pos (const char *string, int dir, int pos)
 {
   int ret, old;
 
This page took 0.026114 seconds and 4 git commands to generate.