Bash-5.3-alpha release

This commit is contained in:
Chet Ramey
2024-04-22 10:33:38 -04:00
parent f3b6bd1945
commit 622d318652
700 changed files with 136534 additions and 96420 deletions
+179 -170
View File
@@ -1,6 +1,6 @@
/* complete.c -- filename completion for readline. */
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
/* Copyright (C) 1987-2024 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.
@@ -77,11 +77,7 @@ extern int errno;
# include "colors.h"
#endif
#ifdef __STDC__
typedef int QSFUNC (const void *, const void *);
#else
typedef int QSFUNC ();
#endif
#ifdef HAVE_LSTAT
# define LSTAT lstat
@@ -250,11 +246,24 @@ rl_icppfunc_t *rl_filename_stat_hook = (rl_icppfunc_t *)NULL;
either return its first argument (if no conversion takes place) or
newly-allocated memory. This can, for instance, convert filenames
between character sets for comparison against what's typed at the
keyboard. The returned value is what is added to the list of
matches. The second argument is the length of the filename to be
converted. */
keyboard (after its potential modification by rl_completion_rewrite_hook).
The returned value is what is added to the list of matches.
The second argument is the length of the filename to be converted. */
rl_dequote_func_t *rl_filename_rewrite_hook = (rl_dequote_func_t *)NULL;
/* If non-zero, this is the address of a function to call before
comparing the filename portion of a word to be completed with directory
entries from the filesystem. This takes the address of the partial word
to be completed, after any rl_filename_dequoting_function has been applied.
The function should either return its first argument (if no conversion
takes place) or newly-allocated memory. This can, for instance, convert
the filename portion of the completion word to a character set suitable
for comparison against directory entries read from the filesystem (after
their potential modification by rl_filename_rewrite_hook).
The returned value is what is added to the list of matches.
The second argument is the length of the filename to be converted. */
rl_dequote_func_t *rl_completion_rewrite_hook = (rl_dequote_func_t *)NULL;
/* Non-zero means readline completion functions perform tilde expansion. */
int rl_complete_with_tilde_expansion = 0;
@@ -340,6 +349,15 @@ int rl_filename_completion_desired = 0;
entry finder function. */
int rl_filename_quoting_desired = 1;
/* Non-zero means we should apply filename-type quoting to all completions
even if we are not otherwise treating the matches as filenames. This is
ALWAYS zero on entry, and can only be changed within a completion entry
finder function. */
int rl_full_quoting_desired = 0;
#define QUOTING_DESIRED() \
(rl_full_quoting_desired || (rl_filename_completion_desired && rl_filename_quoting_desired))
/* This function, if defined, is called by the completer when real
filename completion is done, after all the matching names have been
generated. It is passed a (char**) known as matches in the code below.
@@ -455,6 +473,7 @@ rl_complete (int ignore, int invoking_key)
int
rl_possible_completions (int ignore, int invoking_key)
{
last_completion_failed = 0;
rl_completion_invoking_key = invoking_key;
return (rl_complete_internal ('?'));
}
@@ -484,6 +503,32 @@ rl_completion_mode (rl_command_func_t *cfunc)
return TAB;
}
/********************************************/
/* */
/* Completion signal handling and cleanup */
/* */
/********************************************/
/* State to clean up and free if completion is interrupted by a signal. */
typedef struct {
char **matches;
char *saved_line;
} complete_sigcleanarg_t;
static void
_rl_complete_sigcleanup (int sig, void *ptr)
{
complete_sigcleanarg_t *arg;
if (sig == SIGINT) /* XXX - for now */
{
arg = ptr;
_rl_free_match_list (arg->matches);
FREE (arg->saved_line);
_rl_complete_display_matches_interrupt = 1;
}
}
/************************************/
/* */
/* Completion utility functions */
@@ -498,16 +543,6 @@ _rl_reset_completion_state (void)
rl_completion_quote_character = 0;
}
static void
_rl_complete_sigcleanup (int sig, void *ptr)
{
if (sig == SIGINT) /* XXX - for now */
{
_rl_free_match_list ((char **)ptr);
_rl_complete_display_matches_interrupt = 1;
}
}
/* Set default values for readline word completion. These are the variables
that application completion functions can change or inspect. */
static void
@@ -516,6 +551,7 @@ set_completion_defaults (int what_to_do)
/* Only the completion entry function can change these. */
rl_filename_completion_desired = 0;
rl_filename_quoting_desired = 1;
rl_full_quoting_desired = 0;
rl_completion_type = what_to_do;
rl_completion_suppress_append = rl_completion_suppress_quote = 0;
rl_completion_append_character = ' ';
@@ -1319,6 +1355,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
int low; /* Count of max-matched characters. */
int lx;
char *dtext; /* dequoted TEXT, if needed */
size_t len1, len2;
#if defined (HANDLE_MULTIBYTE)
int v;
size_t v1, v2;
@@ -1345,6 +1382,9 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
memset (&ps2, 0, sizeof (mbstate_t));
}
#endif
len1 = strlen (match_list[i]);
len2 = strlen (match_list[i + 1]);
for (si = 0; (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++)
{
if (_rl_completion_case_fold)
@@ -1355,8 +1395,8 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
v1 = MBRTOWC (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1);
v2 = MBRTOWC (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2);
v1 = MBRTOWC (&wc1, match_list[i]+si, len1 - si, &ps1);
v2 = MBRTOWC (&wc2, match_list[i+1]+si, len2 - si, &ps2);
if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
{
if (c1 != c2) /* do byte comparison */
@@ -1412,10 +1452,8 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
check against the list of matches
FI */
dtext = (char *)NULL;
if (rl_filename_completion_desired &&
rl_filename_dequoting_function &&
rl_completion_found_quote &&
rl_filename_quoting_desired)
if (QUOTING_DESIRED() && rl_completion_found_quote &&
rl_filename_dequoting_function)
{
dtext = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
text = dtext;
@@ -1630,7 +1668,7 @@ rl_display_match_list (char **matches, int len, int max)
if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count)
{
lines = _rl_internal_pager (lines);
if (lines < 0)
if (lines < 0 || _rl_complete_display_matches_interrupt)
return;
}
}
@@ -1658,7 +1696,7 @@ rl_display_match_list (char **matches, int len, int max)
if (_rl_page_completions && lines >= _rl_screenheight - 1)
{
lines = _rl_internal_pager (lines);
if (lines < 0)
if (lines < 0 || _rl_complete_display_matches_interrupt)
return;
}
}
@@ -1745,7 +1783,9 @@ display_matches (char **matches)
}
}
rl_display_match_list (matches, len, max);
/* We rely on the caller to set MATCHES to 0 when this returns. */
if (_rl_complete_display_matches_interrupt == 0)
rl_display_match_list (matches, len, max);
rl_forced_update_display ();
rl_display_fixed = 1;
@@ -1768,9 +1808,7 @@ make_quoted_replacement (char *match, int mtype, char *qc)
matches don't require a quoted substring. */
replacement = match;
should_quote = match && rl_completer_quote_characters &&
rl_filename_completion_desired &&
rl_filename_quoting_desired;
should_quote = match && rl_completer_quote_characters && QUOTING_DESIRED();
if (should_quote)
should_quote = should_quote && (!qc || !*qc ||
@@ -1784,6 +1822,11 @@ make_quoted_replacement (char *match, int mtype, char *qc)
should_quote = rl_filename_quote_characters
? (_rl_strpbrk (match, rl_filename_quote_characters) != 0)
: 0;
/* If we saw a quote in the original word, but readline thinks the
match doesn't need to be quoted, and the application has a filename
quoting function, give the application a chance to quote it if
needed so we don't second-guess the user. */
should_quote |= *qc == 0 && rl_completion_found_quote && mtype != NO_MATCH && rl_filename_quoting_function;
do_replace = should_quote ? mtype : NO_MATCH;
/* Quote the replacement, since we found an embedded
@@ -1791,6 +1834,7 @@ make_quoted_replacement (char *match, int mtype, char *qc)
if (do_replace != NO_MATCH && rl_filename_quoting_function)
replacement = (*rl_filename_quoting_function) (match, do_replace, qc);
}
return (replacement);
}
@@ -1976,8 +2020,7 @@ compare_match (char *text, const char *match)
char *temp;
int r;
if (rl_filename_completion_desired && rl_filename_quoting_desired &&
rl_completion_found_quote && rl_filename_dequoting_function)
if (QUOTING_DESIRED() && rl_completion_found_quote && rl_filename_dequoting_function)
{
temp = (*rl_filename_dequoting_function) (text, rl_completion_quote_character);
r = strcmp (temp, match);
@@ -2001,10 +2044,11 @@ rl_complete_internal (int what_to_do)
{
char **matches;
rl_compentry_func_t *our_func;
int start, end, delimiter, found_quote, i, nontrivial_lcd;
int start, end, delimiter, found_quote, i, nontrivial_lcd, do_display;
char *text, *saved_line_buffer;
char quote_char;
int tlen, mlen, saved_last_completion_failed;
complete_sigcleanarg_t cleanarg; /* state to clean up on signal */
RL_SETSTATE(RL_STATE_COMPLETING);
@@ -2031,9 +2075,24 @@ rl_complete_internal (int what_to_do)
text = rl_copy_text (start, end);
matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char);
/* If TEXT contains quote characters, it will be dequoted as part of
generating the matches, and the matches will not contain any quote
characters. We need to dequote TEXT before performing the comparison.
Since compare_match performs the dequoting, and we only want to do it
once, we don't call compare_matches after dequoting TEXT; we call
strcmp directly. */
/* nontrivial_lcd is set if the common prefix adds something to the word
being completed. */
nontrivial_lcd = matches && compare_match (text, matches[0]) != 0;
if (QUOTING_DESIRED() && rl_completion_found_quote && rl_filename_dequoting_function)
{
char *t;
t = (*rl_filename_dequoting_function) (text, rl_completion_quote_character);
xfree (text);
text = t;
nontrivial_lcd = matches && strcmp (text, matches[0]) != 0;
}
else
nontrivial_lcd = matches && strcmp (text, matches[0]) != 0;
if (what_to_do == '!' || what_to_do == '@')
tlen = strlen (text);
xfree (text);
@@ -2068,6 +2127,8 @@ rl_complete_internal (int what_to_do)
if (matches && matches[0] && *matches[0])
last_completion_failed = 0;
do_display = 0;
switch (what_to_do)
{
case TAB:
@@ -2101,13 +2162,13 @@ rl_complete_internal (int what_to_do)
{
if (what_to_do == '!')
{
display_matches (matches);
do_display = 1;
break;
}
else if (what_to_do == '@')
{
if (nontrivial_lcd == 0)
display_matches (matches);
do_display = 1;
break;
}
else if (rl_editing_mode != vi_mode)
@@ -2131,23 +2192,11 @@ rl_complete_internal (int what_to_do)
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
break;
}
if (rl_completion_display_matches_hook == 0)
{
_rl_sigcleanup = _rl_complete_sigcleanup;
_rl_sigcleanarg = matches;
_rl_complete_display_matches_interrupt = 0;
}
display_matches (matches);
if (_rl_complete_display_matches_interrupt)
{
matches = 0; /* already freed by rl_complete_sigcleanup */
_rl_complete_display_matches_interrupt = 0;
if (rl_signal_event_hook)
(*rl_signal_event_hook) (); /* XXX */
}
_rl_sigcleanup = 0;
_rl_sigcleanarg = 0;
/*FALLTHROUGH*/
case '%': /* used by menu_complete */
case '|': /* add this for unconditional display */
do_display = 1;
break;
default:
@@ -2160,6 +2209,34 @@ rl_complete_internal (int what_to_do)
return 1;
}
/* If we need to display the match list, set up to clean it up on receipt of
a signal and do it here. If the application has registered a function to
display the matches, let it do the work. */
if (do_display)
{
if (rl_completion_display_matches_hook == 0)
{
_rl_sigcleanup = _rl_complete_sigcleanup;
cleanarg.matches = matches;
cleanarg.saved_line = saved_line_buffer;
_rl_sigcleanarg = &cleanarg;
_rl_complete_display_matches_interrupt = 0;
}
display_matches (matches);
if (_rl_complete_display_matches_interrupt)
{
matches = 0; /* Both already freed by _rl_complete_sigcleanup */
saved_line_buffer = 0;
_rl_complete_display_matches_interrupt = 0;
if (rl_signal_event_hook)
(*rl_signal_event_hook) ();
}
_rl_sigcleanup = 0;
_rl_sigcleanarg = 0;
}
_rl_free_match_list (matches);
/* Check to see if the line has changed through all of this manipulation. */
@@ -2200,7 +2277,7 @@ rl_completion_matches (const char *text, rl_compentry_func_t *entry_function)
register int i;
/* Number of slots in match_list. */
int match_list_size;
size_t match_list_size;
/* The list of matches. */
char **match_list;
@@ -2265,9 +2342,9 @@ rl_completion_matches (const char *text, rl_compentry_func_t *entry_function)
char *
rl_username_completion_function (const char *text, int state)
{
#if defined (__WIN32__) || defined (__OPENNT)
#if defined (_WIN32) || defined (__OPENNT) || !defined (HAVE_GETPWENT)
return (char *)NULL;
#else /* !__WIN32__ && !__OPENNT) */
#else /* !_WIN32 && !__OPENNT) && HAVE_GETPWENT */
static char *username = (char *)NULL;
static struct passwd *entry;
static int namelen, first_char, first_char_loc;
@@ -2282,25 +2359,19 @@ rl_username_completion_function (const char *text, int state)
username = savestring (&text[first_char_loc]);
namelen = strlen (username);
#if defined (HAVE_GETPWENT)
setpwent ();
#endif
}
#if defined (HAVE_GETPWENT)
while (entry = getpwent ())
{
/* Null usernames should result in all users as possible completions. */
if (namelen == 0 || (STREQN (username, entry->pw_name, namelen)))
break;
}
#endif
if (entry == 0)
{
#if defined (HAVE_GETPWENT)
endpwent ();
#endif
return ((char *)NULL);
}
else
@@ -2316,7 +2387,7 @@ rl_username_completion_function (const char *text, int state)
return (value);
}
#endif /* !__WIN32__ && !__OPENNT */
#endif /* !_WIN32 && !__OPENNT && HAVE_GETPWENT */
}
/* Return non-zero if CONVFN matches FILENAME up to the length of FILENAME
@@ -2327,18 +2398,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;
@@ -2346,100 +2406,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))
@@ -2461,7 +2447,8 @@ rl_filename_completion_function (const char *text, int state)
static char *users_dirname = (char *)NULL;
static int filename_len;
char *temp, *dentry, *convfn;
int dirlen, dentlen, convlen;
size_t dirlen;
int dentlen, convlen;
int tilde_dirname;
struct dirent *entry;
@@ -2526,7 +2513,8 @@ rl_filename_completion_function (const char *text, int state)
temp = tilde_expand (dirname);
xfree (dirname);
dirname = temp;
tilde_dirname = 1;
if (*dirname != '~')
tilde_dirname = 1; /* indicate successful tilde expansion */
}
/* We have saved the possibly-dequoted version of the directory name
@@ -2545,11 +2533,16 @@ rl_filename_completion_function (const char *text, int state)
xfree (users_dirname);
users_dirname = savestring (dirname);
}
else if (tilde_dirname == 0 && rl_completion_found_quote && rl_filename_dequoting_function)
else if (rl_completion_found_quote && rl_filename_dequoting_function)
{
/* delete single and double quotes */
/* We already ran users_dirname through the dequoting function.
If tilde_dirname == 1, we successfully performed tilde expansion
on dirname. Now we need to reconcile those results. We either
just copy the already-dequoted users_dirname or tilde expand it
if we tilde-expanded dirname. */
temp = tilde_dirname ? tilde_expand (users_dirname) : savestring (users_dirname);
xfree (dirname);
dirname = savestring (users_dirname);
dirname = temp;
}
directory = opendir (dirname);
@@ -2564,6 +2557,18 @@ rl_filename_completion_function (const char *text, int state)
}
filename_len = strlen (filename);
/* Normalize the filename if the application has set a rewrite hook. */
if (*filename && rl_completion_rewrite_hook)
{
temp = (*rl_completion_rewrite_hook) (filename, filename_len);
if (temp != filename)
{
xfree (filename);
filename = temp;
filename_len = strlen (filename);
}
}
rl_filename_completion_desired = 1;
}
@@ -2576,6 +2581,7 @@ rl_filename_completion_function (const char *text, int state)
/* Now that we have some state, we can read the directory. */
entry = (struct dirent *)NULL;
convfn = dentry = 0;
while (directory && (entry = readdir (directory)))
{
convfn = dentry = entry->d_name;
@@ -2593,17 +2599,20 @@ rl_filename_completion_function (const char *text, int state)
if (filename_len == 0)
{
if (_rl_match_hidden_files == 0 && HIDDEN_FILE (convfn))
continue;
{
if (convfn != dentry)
xfree (convfn);
continue;
}
if (convfn[0] != '.' ||
(convfn[1] && (convfn[1] != '.' || convfn[2])))
break;
}
else
{
if (complete_fncmp (convfn, convlen, filename, filename_len))
break;
}
else if (complete_fncmp (convfn, convlen, filename, filename_len))
break;
else if (convfn != dentry)
xfree (convfn);
}
if (entry == 0)
@@ -2825,7 +2834,7 @@ rl_menu_complete (int count, int ignore)
static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
static int orig_start, orig_end;
static char quote_char;
static int delimiter, cstate;
static int delimiter;
/* The first time through, we generate the list of matches and set things
up to insert them. */
@@ -2921,7 +2930,7 @@ rl_menu_complete (int count, int ignore)
if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
{
rl_ding ();
FREE (matches);
_rl_free_match_list (matches);
matches = (char **)0;
full_completion = 1;
return (0);