Move readline to the readline/readline subdirectory
[deliverable/binutils-gdb.git] / readline / readline / histsearch.c
diff --git a/readline/readline/histsearch.c b/readline/readline/histsearch.c
new file mode 100644 (file)
index 0000000..7a426c9
--- /dev/null
@@ -0,0 +1,287 @@
+/* histsearch.c -- searching the history list. */
+
+/* Copyright (C) 1989, 1992-2009,2017 Free Software Foundation, Inc.
+
+   This file contains the GNU History Library (History), a set of
+   routines for managing the text of previously typed lines.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   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.
+
+   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
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#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_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. */
+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
+   appear at the beginning of a history line, otherwise, the string
+   may appear anywhere in the line.  If the string is found, then
+   current_history () is the history entry, and the value of this
+   function is the offset in the line of that history entry that the
+   string was found in.  Otherwise, nothing is changed, and a -1 is
+   returned. */
+
+static int
+history_search_internal (const char *string, int direction, int flags)
+{
+  register int i, reverse;
+  register char *line;
+  register int line_index;
+  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))
+    return (-1);
+
+  if (reverse && (i >= history_length))
+    i = history_length - 1;
+
+#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
+
+  the_history = history_list ();
+  string_len = strlen (string);
+  while (1)
+    {
+      /* Search each line in the history list for STRING. */
+
+      /* At limit for direction? */
+      if ((reverse && i < 0) || (!reverse && i == history_length))
+       return (-1);
+
+      line = the_history[i]->line;
+      line_index = strlen (line);
+
+      /* If STRING is longer than line, no match. */
+      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;
+             return (0);
+           }
+
+         NEXT_LINE ();
+         continue;
+       }
+
+      /* Do substring search. */
+      if (reverse)
+       {
+         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;
+                 return (line_index);
+               }
+             line_index--;
+           }
+       }
+      else
+       {
+         register int limit;
+
+         limit = line_index - string_len + 1;
+         line_index = 0;
+
+         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;
+                 return (line_index);
+               }
+             line_index++;
+           }
+       }
+      NEXT_LINE ();
+    }
+}
+
+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 (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 (const char *string, int direction)
+{
+  return (history_search_internal (string, direction, ANCHORED_SEARCH));
+}
+
+/* Search for STRING in the history list.  DIR is < 0 for searching
+   backwards.  POS is an absolute index into the history list at
+   which point to begin searching. */
+int
+history_search_pos (const char *string, int dir, int pos)
+{
+  int ret, old;
+
+  old = where_history ();
+  history_set_pos (pos);
+  if (history_search (string, dir) == -1)
+    {
+      history_set_pos (old);
+      return (-1);
+    }
+  ret = where_history ();
+  history_set_pos (old);
+  return ret;
+}
This page took 0.042711 seconds and 4 git commands to generate.