]> git.ipfire.org Git - thirdparty/readline.git/commitdiff
add support for case-insensitive incremental and non-incremental history searches...
authorChet Ramey <chet.ramey@case.edu>
Fri, 17 Feb 2023 22:19:55 +0000 (17:19 -0500)
committerChet Ramey <chet.ramey@case.edu>
Fri, 17 Feb 2023 22:19:55 +0000 (17:19 -0500)
18 files changed:
aclocal.m4
bind.c
complete.c
config.h.in
configure
doc/readline.3
doc/rluser.texi
doc/version.texi
histfile.c
histlib.h
histsearch.c
isearch.c
mbutil.c
rlmbutil.h
rlprivate.h
search.c
tcap.h
util.c

index cc97bd4b8461528958dbd009c7c563aa97945527..37546c6c6454a3bb4cb3c44feb6fe37175d5c3c9 100644 (file)
@@ -1758,8 +1758,9 @@ AC_CHECK_HEADERS(langinfo.h)
 AC_CHECK_HEADERS(mbstr.h)
 
 AC_CHECK_FUNC(mbrlen, AC_DEFINE(HAVE_MBRLEN))
-AC_CHECK_FUNC(mbscasecmp, AC_DEFINE(HAVE_MBSCMP))
+AC_CHECK_FUNC(mbscasecmp, AC_DEFINE(HAVE_MBSCASECMP))
 AC_CHECK_FUNC(mbscmp, AC_DEFINE(HAVE_MBSCMP))
+AC_CHECK_FUNC(mbsncmp, AC_DEFINE(HAVE_MBSNCMP))
 AC_CHECK_FUNC(mbsnrtowcs, AC_DEFINE(HAVE_MBSNRTOWCS))
 AC_CHECK_FUNC(mbsrtowcs, AC_DEFINE(HAVE_MBSRTOWCS))
 
@@ -1770,6 +1771,7 @@ AC_CHECK_FUNC(wcscoll, AC_DEFINE(HAVE_WCSCOLL))
 AC_CHECK_FUNC(wcsdup, AC_DEFINE(HAVE_WCSDUP))
 AC_CHECK_FUNC(wcwidth, AC_DEFINE(HAVE_WCWIDTH))
 AC_CHECK_FUNC(wctype, AC_DEFINE(HAVE_WCTYPE))
+AC_CHECK_FUNC(wcsnrtombs, AC_DEFINE(HAVE_WCSNRTOMBS))
 
 AC_REPLACE_FUNCS(wcswidth)
 
diff --git a/bind.c b/bind.c
index 967789381f27e6051fdc0e5018d9e6725f166afb..54ee5cde328608af52f6a921ad69b515b7c17cb4 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -1916,6 +1916,7 @@ static const struct {
   { "prefer-visible-bell",     &_rl_prefer_visible_bell,       V_SPECIAL },
   { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 },
   { "revert-all-at-newline",   &_rl_revert_all_at_newline,     0 },
+  { "search-ignore-case",      &_rl_search_case_fold,          0 },
   { "show-all-if-ambiguous",   &_rl_complete_show_all,         0 },
   { "show-all-if-unmodified",  &_rl_complete_show_unmodified,  0 },
   { "show-mode-in-prompt",     &_rl_show_mode_in_prompt,       0 },
index fe0b8798fd24c618a0ff912da86b587c6247a3c6..2016d393c67ecb37de84f9c92c157c4752bce7df 100644 (file)
@@ -1,6 +1,6 @@
 /* complete.c -- filename completion for readline. */
 
-/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2022,2023 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library (Readline), a library
    for reading lines of text with interactive input and history editing.
@@ -2349,18 +2349,7 @@ rl_username_completion_function (const char *text, int state)
 static int
 complete_fncmp (const char *convfn, int convlen, const char *filename, int filename_len)
 {
-  register char *s1, *s2;
-  int d, len;
-#if defined (HANDLE_MULTIBYTE)
-  size_t v1, v2;
-  mbstate_t ps1, ps2;
-  WCHAR_T wc1, wc2;
-#endif
-
-#if defined (HANDLE_MULTIBYTE)
-  memset (&ps1, 0, sizeof (mbstate_t));
-  memset (&ps2, 0, sizeof (mbstate_t));
-#endif
+  size_t len;
 
   if (filename_len == 0)
     return 1;
@@ -2368,100 +2357,26 @@ complete_fncmp (const char *convfn, int convlen, const char *filename, int filen
     return 0;
 
   len = filename_len;
-  s1 = (char *)convfn;
-  s2 = (char *)filename;
 
   /* Otherwise, if these match up to the length of filename, then
      it is a match. */
-  if (_rl_completion_case_fold && _rl_completion_case_map)
-    {
-      /* Case-insensitive comparison treating _ and - as equivalent */
-#if defined (HANDLE_MULTIBYTE)
-      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-       {
-         do
-           {
-             v1 = MBRTOWC (&wc1, s1, convlen, &ps1);
-             v2 = MBRTOWC (&wc2, s2, filename_len, &ps2);
-             if (v1 == 0 && v2 == 0)
-               return 1;
-             else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
-               {
-                 if (*s1 != *s2)               /* do byte comparison */
-                   return 0;
-                 else if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
-                   return 0;
-                 s1++; s2++; len--;
-                 continue;
-               }
-             wc1 = towlower (wc1);
-             wc2 = towlower (wc2);
-             s1 += v1;
-             s2 += v1;
-             len -= v1;
-             if ((wc1 == L'-' || wc1 == L'_') && (wc2 == L'-' || wc2 == L'_'))
-               continue;
-             if (wc1 != wc2)
-               return 0;
-           }
-         while (len != 0);
-       }
-      else
-#endif
-       {
-       do
-         {
-           d = _rl_to_lower (*s1) - _rl_to_lower (*s2);
-           /* *s1 == [-_] && *s2 == [-_] */
-           if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
-             d = 0;
-           if (d != 0)
-             return 0;
-           s1++; s2++; /* already checked convlen >= filename_len */
-         }
-       while (--len != 0);
-       }
-
-      return 1;
-    }
-  else if (_rl_completion_case_fold)
+  if (_rl_completion_case_fold)
     {
+      /* Case-insensitive comparison treating _ and - as equivalent if
+        _rl_completion_case_map is non-zero */
 #if defined (HANDLE_MULTIBYTE)
       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
-       {
-         do
-           {
-             v1 = MBRTOWC (&wc1, s1, convlen, &ps1);
-             v2 = MBRTOWC (&wc2, s2, filename_len, &ps2);
-             if (v1 == 0 && v2 == 0)
-               return 1;
-             else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
-               {
-                 if (*s1 != *s2)               /* do byte comparison */
-                   return 0;
-                 s1++; s2++; len--;
-                 continue;
-               }
-             wc1 = towlower (wc1);
-             wc2 = towlower (wc2);
-             if (wc1 != wc2)
-               return 0;
-             s1 += v1;
-             s2 += v1;
-             len -= v1;
-           }
-         while (len != 0);
-         return 1;
-       }
+       return (_rl_mb_strcaseeqn (convfn, convlen, filename, filename_len, len, _rl_completion_case_map));
       else
 #endif
       if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) &&
-         (convlen >= filename_len) &&
-         (_rl_strnicmp (filename, convfn, filename_len) == 0))
-       return 1;
+         (convlen >= filename_len))
+       return (_rl_strcaseeqn (convfn, filename, len, _rl_completion_case_map));
     }
   else
     {
+      /* XXX - add new _rl_mb_streqn function (like mbsncmp) instead of
+        relying on byte equivalence? */
       if ((convfn[0] == filename[0]) &&
          (convlen >= filename_len) &&
          (strncmp (filename, convfn, filename_len) == 0))
index 521e7789ba79d1c11200824a1c15bd80c78557fc..ede3722496423a51075e4e01055634037964a96c 100644 (file)
 /* Define if you have the mbrtowc function. */
 #undef HAVE_MBRTOWC
 
+/* Define if you have the mbscmp function. */
+#undef HAVE_MBSCMP
+
+/* Define if you have the mbsncmp function. */
+#undef HAVE_MBSNCMP
+
 /* Define if you have the mbsrtowcs function. */
 #undef HAVE_MBSRTOWCS
 
index cb4e07a0004384c3167c63f3d21593f1ffd63299..72ec5390bdc590d1d27c4751182e3ce68420afcd 100755 (executable)
--- a/configure
+++ b/configure
@@ -7421,7 +7421,7 @@ fi
 ac_fn_c_check_func "$LINENO" "mbscasecmp" "ac_cv_func_mbscasecmp"
 if test "x$ac_cv_func_mbscasecmp" = xyes
 then :
-  printf "%s\n" "#define HAVE_MBSCMP 1" >>confdefs.h
+  printf "%s\n" "#define HAVE_MBSCASECMP 1" >>confdefs.h
 
 fi
 
@@ -7432,6 +7432,13 @@ then :
 
 fi
 
+ac_fn_c_check_func "$LINENO" "mbsncmp" "ac_cv_func_mbsncmp"
+if test "x$ac_cv_func_mbsncmp" = xyes
+then :
+  printf "%s\n" "#define HAVE_MBSNCMP 1" >>confdefs.h
+
+fi
+
 ac_fn_c_check_func "$LINENO" "mbsnrtowcs" "ac_cv_func_mbsnrtowcs"
 if test "x$ac_cv_func_mbsnrtowcs" = xyes
 then :
@@ -7497,6 +7504,13 @@ then :
 
 fi
 
+ac_fn_c_check_func "$LINENO" "wcsnrtombs" "ac_cv_func_wcsnrtombs"
+if test "x$ac_cv_func_wcsnrtombs" = xyes
+then :
+  printf "%s\n" "#define HAVE_WCSNRTOMBS 1" >>confdefs.h
+
+fi
+
 
 ac_fn_c_check_func "$LINENO" "wcswidth" "ac_cv_func_wcswidth"
 if test "x$ac_cv_func_wcswidth" = xyes
index 77ef02a6a9f8b70f829543cd9b97a421a07c90ab..9a63e09e42a1479d0c4af6866c468cccf10f411c 100644 (file)
@@ -6,9 +6,9 @@
 .\"    Case Western Reserve University
 .\"    chet.ramey@case.edu
 .\"
-.\"    Last Change: Mon Sep 19 11:11:22 EDT 2022
+.\"    Last Change: Fri Feb 17 10:59:58 EST 2023
 .\"
-.TH READLINE 3 "2022 September 19" "GNU Readline 8.2"
+.TH READLINE 3 "2023 February 17" "GNU Readline 8.2"
 .\"
 .\" File Name macro.  This used to be `.PN', for Path Name,
 .\" but Sun doesn't seem to like that very much.
@@ -34,8 +34,8 @@ readline \- get a line from a user with editing
 \fBreadline\fP (\fIconst char *prompt\fP);
 .fi
 .SH COPYRIGHT
-.if n Readline is Copyright (C) 1989\-2020 Free Software Foundation,  Inc.
-.if t Readline is Copyright \(co 1989\-2020 Free Software Foundation, Inc.
+.if n Readline is Copyright (C) 1989\-2023 Free Software Foundation,  Inc.
+.if t Readline is Copyright \(co 1989\-2023 Free Software Foundation, Inc.
 .SH DESCRIPTION
 .LP
 .B readline
@@ -622,6 +622,10 @@ before returning when \fBaccept\-line\fP is executed.  By default,
 history lines may be modified and retain individual undo lists across
 calls to \fBreadline\fP.
 .TP
+.B search\-ignore\-case (Off)
+If set to \fBOn\fP, readline performs incremental and non-incremental
+history list searches in a case\-insensitive fashion.
+.TP
 .B show\-all\-if\-ambiguous (Off)
 This alters the default behavior of the completion functions.  If
 set to
index cbcbb45cf4c033aeac748bf44debb78ce392e2a2..f68a4d70ae7219095c7049bfe231ddb863a16973 100644 (file)
@@ -9,7 +9,7 @@ use these features.  There is a document entitled "readline.texinfo"
 which contains both end-user and programmer documentation for the
 GNU Readline Library.
 
-Copyright (C) 1988--2022 Free Software Foundation, Inc.
+Copyright (C) 1988--2023 Free Software Foundation, Inc.
 
 Authored by Brian Fox and Chet Ramey.
 
@@ -757,6 +757,12 @@ before returning when @code{accept-line} is executed.  By default,
 history lines may be modified and retain individual undo lists across
 calls to @code{readline()}.  The default is @samp{off}.
 
+@item search-ignore-case
+@vindex search-ignore-case
+If set to @samp{on}, Readline performs incremental and non-incremental
+history list searches in a case-insensitive fashion.
+The default value is @samp{off}.
+
 @item show-all-if-ambiguous
 @vindex show-all-if-ambiguous
 This alters the default behavior of the completion functions.  If
index 2b80d343b9b9d4e9dfdeeafe2d115031289201c7..a72ee26421a66e10a23ce73088e07afaea40e6c2 100644 (file)
@@ -5,7 +5,7 @@ Copyright (C) 1988-2023 Free Software Foundation, Inc.
 @set EDITION 8.2
 @set VERSION 8.2
 
-@set UPDATED 21 January 2023
-@set UPDATED-MONTH January 2023
+@set UPDATED 17 February 2023
+@set UPDATED-MONTH February 2023
 
-@set LASTCHANGE Sat Jan 21 17:10:44 EST 2023
+@set LASTCHANGE Fri Feb 17 11:03:17 EST 2023
index d299b5e0f0998d4679d990a1d295f5ceed6cb40b..a3c8d9bff43928110ff63ebcaee337843a25fec3 100644 (file)
@@ -630,10 +630,10 @@ history_truncate_file (const char *fname, int lines)
       if (write (file, bp, chars_read - (bp - buffer)) < 0)
        rv = errno;
 
-      if (fstat (file, &nfinfo) < 0 && rv == 0)
+      if (rv == 0 && fstat (file, &nfinfo) < 0)
        rv = errno;
 
-      if (close (file) < 0 && rv == 0)
+      if (rv == 0 && close (file) < 0)
        rv = errno;
     }
   else
@@ -670,6 +670,38 @@ history_truncate_file (const char *fname, int lines)
   return rv;
 }
 
+/* Use stdio to write the history file after mmap or malloc fails, on the
+   assumption that the stdio library can allocate the smaller buffers it uses. */
+static int
+history_write_slow (int fd, HIST_ENTRY **the_history, int nelements, int overwrite)
+{
+  FILE *fp;
+  int i, j, e;
+
+  fp = fdopen (fd, overwrite ? "w" : "a");
+  if (fp == 0)
+    return -1;
+
+  for (j = 0, i = history_length - nelements; i < history_length; i++)
+    {
+      if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
+       fprintf (fp, "%s\n", the_history[i]->timestamp);
+      if (fprintf (fp, "%s\n", the_history[i]->line) < 0)
+       goto slow_write_error;
+    }
+  if (fflush (fp) < 0)
+    {
+slow_write_error:
+      e = errno;
+      fclose (fp);
+      errno = e;
+      return -1;
+    }
+  if (fclose (fp) < 0)
+    return -1;
+  return 0;
+}
+
 /* Workhorse function for writing history.  Writes the last NELEMENT entries
    from the history list to FILENAME.  OVERWRITE is non-zero if you
    wish to replace FILENAME with the entries. */
@@ -738,6 +770,8 @@ history_do_write (const char *filename, int nelements, int overwrite)
     if ((void *)buffer == MAP_FAILED)
       {
 mmap_error:
+       if ((rv = history_write_slow (file, the_history, nelements, overwrite)) == 0)
+         goto write_success;
        rv = errno;
        close (file);
        if (tempname)
@@ -750,6 +784,8 @@ mmap_error:
     buffer = (char *)malloc (buffer_size);
     if (buffer == 0)
       {
+       if ((rv = history_write_slow (file, the_history, nelements, overwrite)) == 0)
+         goto write_success;
        rv = errno;
        close (file);
        if (tempname)
@@ -788,6 +824,7 @@ mmap_error:
   if (close (file) < 0 && rv == 0)
     rv = errno;
 
+write_success:
   if (rv == 0 && histname && tempname)
     rv = histfile_restore (tempname, histname);
 
index 29fc4d2e5781dc24d6885f6317f2604695799002..ca698aca2702b95a9c9d0080197bbe31e96f35e8 100644 (file)
--- a/histlib.h
+++ b/histlib.h
                                    : ((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
 #endif
 
+#if !defined (HAVE_STRCASECMP)
+#define strcasecmp(a,b)        strcmp ((a), (b))
+#define strncasecmp(a, b, n)   strncmp ((a), (b), (n))
+#endif
+
 #ifndef savestring
 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
 #endif
@@ -72,6 +77,7 @@ extern char *strchr ();
 #define NON_ANCHORED_SEARCH    0
 #define ANCHORED_SEARCH                0x01
 #define PATTERN_SEARCH         0x02
+#define CASEFOLD_SEARCH                0x04
 
 /* Possible definitions for what style of writing the history file we want. */
 #define HISTORY_APPEND 0
@@ -81,6 +87,7 @@ extern char *strchr ();
 
 /* histsearch.c */
 extern int _hs_history_patsearch (const char *, int, int);
+extern int _hs_history_search (const char *, int, int);
 
 /* history.c */
 extern void _hs_replace_history_data (int, histdata_t *, histdata_t *);
index 7e5b2501755fbef075daa6d0cc9b23a8836675d2..b43ead1ffea461311419d8666b78fe0a4c904827 100644 (file)
@@ -1,6 +1,6 @@
 /* histsearch.c -- searching the history list. */
 
-/* Copyright (C) 1989, 1992-2009,2017,2021 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992-2009,2017,2021,2023 Free Software Foundation, Inc.
 
    This file contains the GNU History Library (History), a set of
    routines for managing the text of previously typed lines.
@@ -47,6 +47,8 @@
 #include "histlib.h"
 #include "xmalloc.h"
 
+#include "rlmbutil.h"
+
 /* The list of alternate characters that can delimit a history search
    string. */
 char *history_search_delimiter_chars = (char *)NULL;
@@ -57,7 +59,10 @@ static int history_search_internal (const char *, int, int);
    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
+   may appear anywhere in the line.  If PATSEARCH is non-zero, and fnmatch(3)
+   is available, fnmatch is used to match the string instead of a simple
+   string comparison. If IGNORECASE is set, the string comparison is
+   performed case-insensitively. 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
@@ -68,9 +73,10 @@ history_search_internal (const char *string, int direction, int flags)
 {
   int i, reverse;
   char *line;
-  int line_index;
-  size_t string_len;
-  int anchored, patsearch;
+  size_t string_len, line_len;
+  int line_index;              /* can't be unsigned */
+  int anchored, patsearch, igncase;
+  int found, mb_cur_max;
   HIST_ENTRY **the_history;    /* local */
 
   i = history_offset;
@@ -81,6 +87,7 @@ history_search_internal (const char *string, int direction, int flags)
 #else
   patsearch = 0;
 #endif
+  igncase = (flags & CASEFOLD_SEARCH);
 
   /* Take care of trivial cases first. */
   if (string == 0 || *string == '\0')
@@ -92,6 +99,8 @@ history_search_internal (const char *string, int direction, int flags)
   if (reverse && (i >= history_length))
     i = history_length - 1;
 
+  mb_cur_max = MB_CUR_MAX;
+
 #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
 
   the_history = history_list ();
@@ -105,7 +114,7 @@ history_search_internal (const char *string, int direction, int flags)
        return (-1);
 
       line = the_history[i]->line;
-      line_index = strlen (line);
+      line_len = line_index = strlen (line);
 
       /* If STRING is longer than line, no match. */
       if (patsearch == 0 && (string_len > line_index))
@@ -117,18 +126,27 @@ history_search_internal (const char *string, int direction, int flags)
       /* Handle anchored searches first. */
       if (anchored == ANCHORED_SEARCH)
        {
+         found = 0;
 #if defined (HAVE_FNMATCH)
          if (patsearch)
+           found = fnmatch (string, line, 0) == 0;
+         else
+#endif
+         if (igncase)
            {
-             if (fnmatch (string, line, 0) == 0)
-               {
-                 history_offset = i;
-                 return (0);
-               }
+#if defined (HANDLE_MULTIBYTE)
+             if (mb_cur_max > 1)       /* no rl_byte_oriented equivalent */
+               found = _rl_mb_strcaseeqn (string, string_len,
+                                          line, line_len,
+                                          string_len, 0);
+             else
+#endif
+               found = strncasecmp (string, line, string_len) == 0;
            }
          else
-#endif
-         if (STREQN (string, line, string_len))
+           found = STREQN (string, line, string_len);
+
+         if (found)
            {
              history_offset = i;
              return (0);
@@ -141,55 +159,80 @@ history_search_internal (const char *string, int direction, int flags)
       /* Do substring search. */
       if (reverse)
        {
-         line_index -= (patsearch == 0) ? string_len : 1;
+         size_t ll;
+
+         ll = (patsearch == 0) ? string_len : 1;
+         line_index -= ll;
+         found = 0;
 
          while (line_index >= 0)
            {
 #if defined (HAVE_FNMATCH)
              if (patsearch)
+               found = fnmatch (string, line + line_index, 0) == 0;
+             else
+#endif
+             if (igncase)
                {
-                 if (fnmatch (string, line + line_index, 0) == 0)
-                   {
-                     history_offset = i;
-                     return (line_index);
-                   }
+#if defined (HANDLE_MULTIBYTE)
+                 if (mb_cur_max > 1)   /* no rl_byte_oriented equivalent */
+                   found = _rl_mb_strcaseeqn (string, string_len,
+                                              line + line_index, ll,
+                                              string_len, 0);
+                 else
+#endif
+                 found = strncasecmp (string, line + line_index, string_len) == 0;
                }
              else
-#endif
-             if (STREQN (string, line + line_index, string_len))
+               found = STREQN (string, line + line_index, string_len);
+
+             if (found)
                {
                  history_offset = i;
                  return (line_index);
                }
              line_index--;
+             ll++;
            }
        }
       else
        {
          register int limit;
+         size_t ll;
 
+         ll = line_len;
          limit = line_index - string_len + 1;
          line_index = 0;
+         found = 0;
 
          while (line_index < limit)
            {
 #if defined (HAVE_FNMATCH)
              if (patsearch)
+               found = fnmatch (string, line + line_index, 0) == 0;
+             else
+#endif
+             if (igncase)
                {
-                 if (fnmatch (string, line + line_index, 0) == 0)
-                   {
-                     history_offset = i;
-                     return (line_index);
-                   }
+#if defined (HANDLE_MULTIBYTE)
+                 if (mb_cur_max > 1)   /* no rl_byte_oriented equivalent */
+                   found = _rl_mb_strcaseeqn (string, string_len,
+                                              line + line_index, ll,
+                                              string_len, 0);
+                 else
+#endif
+                 found = strncasecmp (string, line + line_index, string_len) == 0;
                }
              else
-#endif
-             if (STREQN (string, line + line_index, string_len))
+               found = STREQN (string, line + line_index, string_len);
+
+             if (found)
                {
                  history_offset = i;
                  return (line_index);
                }
              line_index++;
+             ll--;
            }
        }
       NEXT_LINE ();
@@ -267,6 +310,13 @@ history_search_prefix (const char *string, int direction)
   return (history_search_internal (string, direction, ANCHORED_SEARCH));
 }
 
+/* At some point, make this public for users of the history library. */
+int
+_hs_history_search (const char *string, int direction, int flags)
+{
+  return (history_search_internal (string, direction, flags));
+}
+
 /* 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. */
index 375618174f958bb5dbbc08f9efc00836138a2284..89c933863a4ebcde69c7678acfd38a4f7bc9c5d8 100644 (file)
--- a/isearch.c
+++ b/isearch.c
@@ -59,6 +59,8 @@ char *_rl_isearch_terminators = (char *)NULL;
 
 _rl_search_cxt *_rl_iscxt = 0;
 
+int _rl_search_case_fold = 0;
+
 static int rl_search_history (int, int);
 
 static _rl_search_cxt *_rl_isearch_init (int);
@@ -753,7 +755,27 @@ opcode_dispatch:
       /* Search the current line. */
       while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
        {
-         if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
+         int found;
+
+         if (_rl_search_case_fold)
+           {
+#if defined (HANDLE_MULTIBYTE)
+             if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
+               found = _rl_mb_strcaseeqn (cxt->search_string,
+                                          cxt->search_string_index,
+                                          cxt->sline + cxt->sline_index,
+                                          limit,
+                                          cxt->search_string_index, 0);
+             else
+               found = _rl_strnicmp (cxt->search_string,
+                                     cxt->sline + cxt->sline_index,
+                                     cxt->search_string_index) == 0;
+#endif
+           }
+         else
+           found = STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index);
+
+         if (found)
            {
              cxt->sflags |= SF_FOUND;
              break;
index 11cf2293b198343a5d93e59e4d72b79d99f52d8e..0844e28618939dcdb3242b21ccd6853b0ea4ef31 100644 (file)
--- a/mbutil.c
+++ b/mbutil.c
@@ -521,3 +521,78 @@ _rl_find_prev_mbchar (const char *string, int seed, int flags)
   return ((seed == 0) ? seed : seed - 1);
 #endif
 }
+
+/* Compare the first N characters of S1 and S2 without regard to case. If
+   FLAGS&1, apply the mapping specified by completion-map-case and make
+   `-' and `_' equivalent. Returns 1 if the strings are equal. */
+int
+_rl_mb_strcaseeqn (const char *s1, size_t l1, const char *s2, size_t l2, size_t n, int flags)
+{
+  size_t v1, v2;
+  mbstate_t ps1, ps2;
+  WCHAR_T wc1, wc2;
+
+  memset (&ps1, 0, sizeof (mbstate_t));
+  memset (&ps2, 0, sizeof (mbstate_t));
+
+  do
+    {
+      v1 = MBRTOWC(&wc1, s1, l1, &ps1);
+      v2 = MBRTOWC(&wc2, s2, l2, &ps2);
+      if (v1 == 0 && v2 == 0)
+       return 1;
+      else if (MB_INVALIDCH(v1) || MB_INVALIDCH(v2))
+       {
+         int d;
+         d = _rl_to_lower (*s1) - _rl_to_lower (*s2);  /* do byte comparison */
+         if ((flags & 1) && (*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
+           d = 0;              /* case insensitive character mapping */
+         if (d != 0)
+           return 0;
+         s1++;
+         s2++;
+         n--;
+         continue;
+       }
+      wc1 = towlower(wc1);
+      wc2 = towlower(wc2);
+      s1 += v1;
+      s2 += v1;
+      n -= v1;
+      if ((flags & 1) && (wc1 == L'-' || wc1 == L'_') && (wc2 == L'-' || wc2 == L'_'))
+        continue;
+      if (wc1 != wc2)
+       return 0;
+    }
+  while (n != 0);
+
+  return 1;
+}
+
+/* Return 1 if the multibyte characters pointed to by S1 and S2 are equal
+   without regard to case. If FLAGS&1, apply the mapping specified by
+   completion-map-case and make `-' and `_' equivalent. */
+int
+_rl_mb_charcasecmp (const char *s1, mbstate_t *ps1, const char *s2, mbstate_t *ps2, int flags)
+{
+  int d;
+  size_t v1, v2;
+  wchar_t wc1, wc2;
+
+  d = MB_CUR_MAX;
+  v1 = MBRTOWC(&wc1, s1, d, ps1);
+  v2 = MBRTOWC(&wc2, s2, d, ps2);
+  if (v1 == 0 && v2 == 0)
+    return 1;
+  else if (MB_INVALIDCH(v1) || MB_INVALIDCH(v2))
+    {
+      if ((flags & 1) && (*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
+       return 1;
+      return (_rl_to_lower (*s1) == _rl_to_lower (*s2));
+    }
+  wc1 = towlower(wc1);
+  wc2 = towlower(wc2);
+  if ((flags & 1) && (wc1 == L'-' || wc1 == L'_') && (wc2 == L'-' || wc2 == L'_'))
+    return 1;
+  return (wc1 == wc2);
+}
index 42d47c3d382f384af5c6ca588b9814b4ad7aec10..92ce05bd2ddc900c76b25981bd70ecac4b5dadb7 100644 (file)
@@ -1,6 +1,6 @@
 /* rlmbutil.h -- utility functions for multibyte characters. */
 
-/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2021,2023 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library (Readline), a library
    for reading lines of text with interactive input and history editing.      
@@ -121,6 +121,9 @@ extern int _rl_is_mbchar_matched (const char *, int, int, char *, int);
 extern WCHAR_T _rl_char_value (const char *, int);
 extern int _rl_walphabetic (WCHAR_T);
 
+extern int _rl_mb_strcaseeqn (const char *, size_t, const char *, size_t, size_t, int);
+extern int _rl_mb_charcasecmp (const char *, mbstate_t *, const char *, mbstate_t *, int);
+
 #define _rl_to_wupper(wc)      (iswlower (wc) ? towupper (wc) : (wc))
 #define _rl_to_wlower(wc)      (iswupper (wc) ? towlower (wc) : (wc))
 
index 77a4d8c6ca8ca80a58daa01d86f16fca576dee1c..e97ea90e8ded739085994dfa24b451c0f9024053 100644 (file)
@@ -475,6 +475,8 @@ extern int _rl_tropen (void);
 extern int _rl_abort_internal (void);
 extern int _rl_null_function (int, int);
 extern char *_rl_strindex (const char *, const char *);
+extern int _rl_strcaseeqn (const char *, const char *, size_t, int);
+extern int _rl_charcasecmp (int, int, int);
 extern int _rl_qsort_string_compare (char **, char **);
 extern int (_rl_uppercase_p) (int);
 extern int (_rl_lowercase_p) (int);
@@ -544,6 +546,7 @@ extern int _rl_vi_cmd_modestr_len;
 extern char *_rl_isearch_terminators;
 
 extern _rl_search_cxt *_rl_iscxt;
+extern int _rl_search_case_fold;
 
 /* macro.c */
 extern char *_rl_executing_macro;
index 43c66b1bc1d68593e6a0971687228a2e375f7343..b7be876fe26b6bd8920e583a8ea373269386346f 100644 (file)
--- a/search.c
+++ b/search.c
@@ -135,21 +135,23 @@ noninc_search_from_pos (char *string, int pos, int dir, int flags, int *ncp)
   RL_SETSTATE(RL_STATE_SEARCH);
   /* These functions return the match offset in the line; history_offset gives
      the matching line in the history list */
-  if (flags & SF_PATTERN)
+
+  sflags = 0;          /* Non-anchored search */
+  s = string;
+  if (*s == '^')
     {
-      s = string;
-      sflags = 0;              /* Non-anchored search */
-      if (*s == '^')
-       {
-         sflags |= ANCHORED_SEARCH;
-         s++;
-       }
-      ret = _hs_history_patsearch (s, dir, sflags);
+      sflags |= ANCHORED_SEARCH;
+      s++;
     }
-  else if (*string == '^')
-    ret = history_search_prefix (string + 1, dir);
+
+  if (flags & SF_PATTERN)
+    ret = _hs_history_patsearch (s, dir, sflags);
   else
-    ret = history_search (string, dir);
+    {
+      if (_rl_search_case_fold)
+       sflags |= CASEFOLD_SEARCH;
+      ret = _hs_history_search (s, dir, sflags);
+    }
   RL_UNSETSTATE(RL_STATE_SEARCH);
 
   if (ncp)
@@ -201,7 +203,7 @@ noninc_dosearch (char *string, int dir, int flags)
 
   make_history_line_current (entry);
 
-  if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind > 0 && ind < rl_end)
+  if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind >= 0 && ind < rl_end)
     {
       rl_point = ind;
       rl_mark = ind + strlen (string);
diff --git a/tcap.h b/tcap.h
index 1121061b8ecef23ff4847f2611cccd27ffbc8563..467ea60e90391fe84e2cf4276438f183a211524b 100644 (file)
--- a/tcap.h
+++ b/tcap.h
@@ -1,6 +1,6 @@
 /* tcap.h -- termcap library functions and variables. */
 
-/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015,2023 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library (Readline), a library
    for reading lines of text with interactive input and history editing.      
@@ -46,14 +46,14 @@ extern char *UP, *BC;
 
 extern short ospeed;
 
-extern int tgetent PARAMS((char *, const char *));
-extern int tgetflag PARAMS((const char *));
-extern int tgetnum PARAMS((const char *));
-extern char *tgetstr PARAMS((const char *, char **));
+extern int tgetent (char *, const char *);
+extern int tgetflag (const char *);
+extern int tgetnum (const char *);
+extern char *tgetstr (const char *, char **);
 
-extern int tputs PARAMS((const char *, int, int (*)(int));
+extern int tputs (const char *, int, int (*)(int));
 
-extern char *tgoto PARAMS((const char *, int, int));
+extern char *tgoto (const char *, int, int);
 
 #endif /* HAVE_TERMCAP_H */
 
diff --git a/util.c b/util.c
index d481b8561eff7e44cc24b3caa23aa601978db4cb..b68abdc6844a68a30ccb56700dae33ea29a856f0 100644 (file)
--- a/util.c
+++ b/util.c
@@ -418,6 +418,48 @@ _rl_stricmp (const char *string1, const char *string2)
 }
 #endif /* !HAVE_STRCASECMP */
 
+/* Compare the first N characters of S1 and S2 without regard to case. If
+   FLAGS&1, apply the mapping specified by completion-map-case and make
+   `-' and `_' equivalent. Returns 1 if the strings are equal. */
+int
+_rl_strcaseeqn(const char *s1, const char *s2, size_t n, int flags)
+{
+  int c1, c2;
+  int d;
+
+  if ((flags & 1) == 0)
+    return (_rl_strnicmp (s1, s2, n) == 0);
+
+  do
+    {
+      c1 = _rl_to_lower (*s1);
+      c2 = _rl_to_lower (*s2);
+
+      d = c1 - c2;
+      if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
+       d = 0;          /* case insensitive character mapping */
+      if (d != 0)
+       return 0;
+      s1++;
+      s2++;
+      n--;
+    }
+  while (n != 0);
+
+  return 1;
+}
+
+/* Return 1 if the characters C1 and C2 are equal without regard to case.
+   If FLAGS&1, apply the mapping specified by completion-map-case and make
+   `-' and `_' equivalent. */
+int
+_rl_charcasecmp (int c1, int c2, int flags)
+{
+  if ((flags & 1) && (c1 == '-' || c1 == '_') && (c2 == '-' || c2 == '_'))
+    return 1;
+  return ( _rl_to_lower (c1) == _rl_to_lower (c2));
+}
+
 /* Stupid comparison routine for qsort () ing strings. */
 int
 _rl_qsort_string_compare (char **s1, char **s2)