mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-01 17:39:56 +02:00
add support for case-insensitive incremental and non-incremental history searches in readline; controlled by new bindable readline variable `search-ignore-case'
This commit is contained in:
@@ -5327,3 +5327,69 @@ parse.y
|
||||
bashline.c
|
||||
- set_up_new_line: add some more heuristics to try and usefully
|
||||
position rl_point
|
||||
|
||||
2/16
|
||||
----
|
||||
lib/readline/complete.c
|
||||
- complete_fncmp: fix for case mapping `-' and `_' if the bytes do not
|
||||
form a valid multibyte character
|
||||
|
||||
lib/readline/util.c
|
||||
- new functions: _rl_strcaseeqn, like strcasencmp but with a flag to
|
||||
handle character mapping (-_) like completion-map-case wants, and
|
||||
_rl_charcasecmp, to do the same thing for two characters.
|
||||
Inspired by a patch from Brennan Vincent <brennan@umanwizard.com>
|
||||
|
||||
lib/readline/mbutil.c
|
||||
- new functions: _rl_mb_strcaseeqn and _rl_mb_charcasecmp, multibyte
|
||||
versions of the above
|
||||
Inspired by a patch from Brennan Vincent <brennan@umanwizard.com>
|
||||
|
||||
lib/readline/{rlprivate.h,rlmbutil.h}
|
||||
- extern declarations for the above functions
|
||||
|
||||
lib/readline/complete.c
|
||||
- complete_fncmp: use _rl_mb_strcaseeqn and _rl_strcaseeqn as
|
||||
appropriate, remove duplicated inline code
|
||||
Inspired by a patch from Brennan Vincent <brennan@umanwizard.com>
|
||||
|
||||
lib/readline/{isearch.c,rlprivate.h}
|
||||
- _rl_search_case_fold: new variable, will be used to indicate case-
|
||||
insensitive incremental and non-incremental searches
|
||||
|
||||
lib/readline/bind.c
|
||||
- search-ignore-case: new bindable variable, tied to _rl_search_case_fold
|
||||
Inspired by a patch from Brennan Vincent <brennan@umanwizard.com>
|
||||
|
||||
lib/sh/mbsncmp.c
|
||||
- mbsncmp(3) replacement
|
||||
|
||||
lib/readline/isearch.c
|
||||
- _rl_isearch_dispatch: honor `search-ignore-case' variable and perform
|
||||
case-insensitive incremental searches if it's set
|
||||
Inspired by a patch from Brennan Vincent <brennan@umanwizard.com>
|
||||
|
||||
lib/readline/histlib.h
|
||||
- CASEFOLD_SEARCH: new flag for history searching, means to search
|
||||
strings case-insensitively
|
||||
|
||||
lib/readline/histsearch.c
|
||||
- history_search_internal: anchored searches honor CASEFOLD_SEARCH
|
||||
|
||||
2/17
|
||||
----
|
||||
lib/readline/histsearch.c
|
||||
- history_search_internal: searches now honor CASEFOLD_SEARCH
|
||||
- _hs_history_search: new function, just external interface to
|
||||
history_search_internal, allows the rest of the library to specify
|
||||
search flags
|
||||
|
||||
lib/readline/histlib.h
|
||||
- _hs_history_search: extern declaration
|
||||
|
||||
lib/readline/search.c
|
||||
- noninc_search_from_pos: use _hs_history_search, add CASEFOLD_SEARCH
|
||||
to flags if _rl_search_case_fold is non-zero
|
||||
|
||||
doc/bash.1,lib/readline/doc/{readline.3,rluser.texi}
|
||||
- search-ignore-case: document new bindable variable
|
||||
|
||||
@@ -419,6 +419,7 @@ lib/sh/makepath.c f
|
||||
lib/sh/mbscasecmp.c f
|
||||
lib/sh/mbschr.c f
|
||||
lib/sh/mbscmp.c f
|
||||
lib/sh/mbsncmp.c f
|
||||
lib/sh/memset.c f
|
||||
lib/sh/mktime.c f
|
||||
lib/sh/netconn.c f
|
||||
|
||||
@@ -236,6 +236,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
|
||||
${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \
|
||||
${SH_LIBSRC}/zmapfd.c ${SH_LIBSRC}/fpurge.c \
|
||||
${SH_LIBSRC}/zgetline.c ${SH_LIBSRC}/mbscmp.c \
|
||||
${SH_LIBSRC}/mbsncmp.c \
|
||||
${SH_LIBSRC}/casemod.c ${SH_LIBSRC}/uconvert.c \
|
||||
${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/dprintf.c \
|
||||
${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \
|
||||
|
||||
Vendored
+2
-1
@@ -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))
|
||||
|
||||
|
||||
@@ -738,6 +738,9 @@
|
||||
/* 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 mbsnrtowcs function. */
|
||||
#undef HAVE_MBSNRTOWCS
|
||||
|
||||
|
||||
@@ -16289,7 +16289,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
|
||||
|
||||
@@ -16300,6 +16300,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 :
|
||||
|
||||
@@ -6241,6 +6241,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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
+10
-95
@@ -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)
|
||||
if (_rl_completion_case_fold)
|
||||
{
|
||||
/* Case-insensitive comparison treating _ and - as equivalent */
|
||||
/* 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;
|
||||
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 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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
: ((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 *);
|
||||
|
||||
+81
-31
@@ -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)
|
||||
{
|
||||
if (fnmatch (string, line, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
found = fnmatch (string, line, 0) == 0;
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line, string_len))
|
||||
if (igncase)
|
||||
{
|
||||
#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
|
||||
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)
|
||||
{
|
||||
if (fnmatch (string, line + line_index, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (line_index);
|
||||
}
|
||||
}
|
||||
found = fnmatch (string, line + line_index, 0) == 0;
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line + line_index, string_len))
|
||||
if (igncase)
|
||||
{
|
||||
#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
|
||||
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)
|
||||
{
|
||||
if (fnmatch (string, line + line_index, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (line_index);
|
||||
}
|
||||
}
|
||||
found = fnmatch (string, line + line_index, 0) == 0;
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line + line_index, string_len))
|
||||
if (igncase)
|
||||
{
|
||||
#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
|
||||
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. */
|
||||
|
||||
+23
-1
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+15
-13
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
+9
-3
@@ -91,8 +91,8 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
|
||||
fmtulong.c fmtullong.c fmtumax.c shmatch.c strnlen.c \
|
||||
strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c strstr.c \
|
||||
mktime.c strftime.c mbschr.c zcatfd.c zmapfd.c winsize.c eaccess.c \
|
||||
wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \
|
||||
casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
|
||||
wcsdup.c fpurge.c zgetline.c mbscmp.c mbsncmp.c uconvert.c \
|
||||
ufuncs.c casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
|
||||
strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \
|
||||
strvis.c utf8.c random.c gettimeofday.c timers.c
|
||||
|
||||
@@ -107,7 +107,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
|
||||
pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \
|
||||
strtrans.o snprintf.o mailstat.o fmtulong.o \
|
||||
fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \
|
||||
fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \
|
||||
fpurge.o zgetline.o mbscmp.o mbsncmp.o uconvert.o ufuncs.o casemod.o \
|
||||
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o strvis.o \
|
||||
utf8.o random.o gettimeofday.o timers.o wcsnwidth.o ${LIBOBJS}
|
||||
|
||||
@@ -165,6 +165,7 @@ makepath.o: makepath.c
|
||||
mbscasecmp.o: mbscasecmp.c
|
||||
mbschr.o: mbschr.c
|
||||
mbscmp.o: mbscmp.c
|
||||
mbsncmp.o: mbsncmp.c
|
||||
memset.o: memset.c
|
||||
mktime.o: mktime.c
|
||||
netconn.o: netconn.c
|
||||
@@ -247,6 +248,7 @@ makepath.o: ${BUILD_DIR}/config.h
|
||||
mbscasecmp.o: ${BUILD_DIR}/config.h
|
||||
mbschr.o: ${BUILD_DIR}/config.h
|
||||
mbscmp.o: ${BUILD_DIR}/config.h
|
||||
mbsncmp.o: ${BUILD_DIR}/config.h
|
||||
memset.o: ${BUILD_DIR}/config.h
|
||||
mktime.o: ${BUILD_DIR}/config.h
|
||||
netconn.o: ${BUILD_DIR}/config.h
|
||||
@@ -607,6 +609,10 @@ mbscmp.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
mbscmp.o: ${BASHINCDIR}/stdc.h
|
||||
mbscmp.o: ${topdir}/xmalloc.h
|
||||
|
||||
mbsncmp.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
mbsncmp.o: ${BASHINCDIR}/stdc.h
|
||||
mbsncmp.o: ${topdir}/xmalloc.h
|
||||
|
||||
casemod.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
casemod.o: ${BASHINCDIR}/stdc.h
|
||||
casemod.o: ${topdir}/xmalloc.h
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
extern int locale_utf8locale;
|
||||
|
||||
extern int utf8_mbscmp (const char *, const char *);
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/* mbsncmp - multibyte string comparison. */
|
||||
|
||||
/* Copyright (C) 1995-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if !defined (HAVE_MBSNCMP) && defined (HANDLE_MULTIBYTE)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
extern int locale_utf8locale;
|
||||
|
||||
/* Compare MBS1 and MBS2 up to N multibyte characters. */
|
||||
int
|
||||
mbsncmp (const char *mbs1, const char *mbs2, size_t n)
|
||||
{
|
||||
int len1, len2, mb_cur_max;
|
||||
wchar_t c1, c2;
|
||||
mbstate_t state1 = { 0 }, state2 = { 0 };
|
||||
|
||||
len1 = len2 = 0;
|
||||
mb_cur_max = MB_CUR_MAX;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
len1 = mbrtowc (&c1, mbs1, mb_cur_max, &state1);
|
||||
len2 = mbrtowc (&c2, mbs2, mb_cur_max, &state2);
|
||||
|
||||
if (len1 == 0)
|
||||
return len2 == 0 ? 0 : -1;
|
||||
else if (len2 == 0)
|
||||
return 1;
|
||||
else if (len1 > 0 && len2 < 0)
|
||||
return -1;
|
||||
else if (len1 < 0 && len2 > 0)
|
||||
return 1;
|
||||
else if (len1 < 0 && len2 < 0)
|
||||
{
|
||||
len1 = strlen (mbs1);
|
||||
len2 = strlen (mbs2);
|
||||
return (len1 == len2 ? memcmp (mbs1, mbs2, len1)
|
||||
: ((len1 < len2) ? (memcmp (mbs1, mbs2, len1) > 0 ? 1 : -1)
|
||||
: (memcmp (mbs1, mbs2, len2) >= 0 ? 1 : -1)));
|
||||
}
|
||||
|
||||
mbs1 += len1;
|
||||
mbs2 += len2;
|
||||
n--;
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
while (n > 0);
|
||||
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user