[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] fix `shopt -u force_fignore' affecting unrelated parts
From: |
Koichi Murase |
Subject: |
[PATCH] fix `shopt -u force_fignore' affecting unrelated parts |
Date: |
Sun, 7 Jul 2024 19:55:41 +0900 |
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=native -O3
uname output: Linux chatoyancy 6.5.12-100.fc37.x86_64 #1 SMP
PREEMPT_DYNAMIC Mon Nov 20 22:28:44 UTC 2023 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 5.3
Patch Level: 0
Release Status: alpha
Description:
The filtering by `shopt -u force_fignore' is also applied to the
suppression of completons unrelated to FIGNORE, which results in
strange behaviors in command- and directory-name completions with
`shopt -u force_fignore'. This is because `_ignore_completion_names
()' (bashline.c) keeps the original completion list with `shopt -u
force_fignore' regardless of whether the current filtering is that
by FIGNORE. The `force_fignore == 0' should take effect only for
the filtering by FIGNORE.
Bash 3.0..devel are affected. I haven't confirmed it with the
actual binary, but I think Bash 2.02..2.05b are also affected when
the compiler option `-DNO_FORCE_FIGNORE' is specified.
The problem was identified after the report originally submitted by
Maƫlan <https://github.com/Maelan> to bash-completion:
https://github.com/scop/bash-completion/issues/1229 .
Repeat-By (case 1 - bash_progcomp_ignore_filenames):
$ bash --norc
$ rm -rf tmpdir && mkdir tmpdir && cd tmpdir
$ touch hello.txt
$ shopt -s force_fignore
$ compgen -d <-- Nothing is generated as expected
$ shopt -u force_fignore
$ compgen -d
hello.txt <-- This is unexpected.
In this case, `_ignore_completion_names ()' is called by
`bash_progcomp_ignore_filenames ()' (bashline.c) to remove all
non-directory filenames.
Repeat-By (case 2 - bash_ignore_filenames):
$ bash --norc
$ rm -rf tmpdir && mkdir tmpdir && cd tmpdir
$ touch nonexistent-command-name.txt
$ shopt -s force_fignore
$ nonexistent-command-name[TAB] <-- Nothing happens as expected
$ shopt -u force_fignore
$ nonexistent-command-name[TAB] <-- This completes the line as follows:
$ nonexistent-command-name.txt <-- This is unexpecdted.
In this case, `_ignore_completion_names ()' is called by
`bash_ignore_filenames ()' (bashline.c) to suppress non-directory
filenames in the current directory for the command-name completions.
Repeat-By (case 3 - bash_ignore_everything):
$ bash --norc
$ rm -rf tmpdir && mkdir tmpdir && cd tmpdir
$ touch hello.txt
$ shopt -s no_empty_cmd_completion
$ shopt -s force_fignore
$ [TAB] <-- Nothing happens as expected
$ shopt -u force_fignore
$ [TAB] <-- This completes the line as follows:
$ hello.txt <-- This is unexpected.
In this case, `_ignore_completion_names ()' is called by
`bash_ignore_everything ()' (bashline.c) to implement `shopt -s
no_empty_command_completion'.
Fix:
In this patch, `_ignore_completion_names ()' is changed to restore
the original completion list with `shopt -u force_fignore' only when
the completion list becomes empty by the FIGNORE filtering. This
patch was created and tested with the devel branch.
The function `_ignore_completion_names ()' (bashline.c) is called by
the four functions in bashline.c:
* filename_completion_ignore ()
* bash_progcomp_ignore_filenames ()
* bash_ignore_filenames ()
* bash_ignore_everything ()
The first one is the function that performs the filtering by
FIGNORE, and its behavior should be kept. The second to fourth
functions are the ones related to case 1..3 in Repeat-By section of
this report, respectively, so I think their behavior should not be
affecetd by `shopt -s force_fignore'. The function
`_ignore_completion_names ()' can detect whether the current
filtering is that by FIGNORE by checking its second argument,
`name_func'.
Change history:
The current strange behaviors seem to be present from Bash 3.0 where
`force_fignore' is first introduced, and are still present in the
devel branch. The filtering by force_fignore was introduced by
commit d3a24ed2 (2011-11-29, "Initial devel branch import from
bash-3.0-alpha"). This commit includes everything from the
3.0-alpha release, so a finer change history is unavailable. Before
that version, `force_fignore' was implemented as a C-macro `#define
NO_FORCE_FIGNORE', which was undefined (and hence effectively the
same as `shopt -s force_fignore') by default. The C-macro was
introduce in 2.02 (commit cce855bc, 1998-04-18, "Imported from
../bash-2.02.tar.gz."). Before that, the behavior was always like
`shopt -s force_fignore'.
---
bashline.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/bashline.c b/bashline.c
index 9cdd9bc4..174f5311 100644
--- a/bashline.c
+++ b/bashline.c
@@ -3072,6 +3072,8 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
size_t idx, nidx;
char **oldnames;
int oidx;
+ int allow_empty = 1;
+ if (name_func == name_is_acceptable) allow_empty = force_fignore;
/* If there is only one completion, see if it is acceptable. If it is
not, free it up. In any case, short-circuit and return. This is a
@@ -3079,7 +3081,7 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
if there is only one completion; it is the completion itself. */
if (names[1] == (char *)0)
{
- if (force_fignore)
+ if (allow_empty)
if ((*name_func) (names[0]) == 0)
{
free (names[0]);
@@ -3095,7 +3097,7 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
;
newnames = strvec_create (nidx + 1);
- if (force_fignore == 0)
+ if (allow_empty == 0)
{
oldnames = strvec_create (nidx - 1);
oidx = 0;
@@ -3106,7 +3108,7 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
{
if ((*name_func) (names[idx]))
newnames[nidx++] = names[idx];
- else if (force_fignore == 0)
+ else if (allow_empty == 0)
oldnames[oidx++] = names[idx];
else
free (names[idx]);
@@ -3117,7 +3119,7 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
/* If none are acceptable then let the completer handle it. */
if (nidx == 1)
{
- if (force_fignore)
+ if (allow_empty)
{
free (names[0]);
names[0] = (char *)NULL;
@@ -3129,7 +3131,7 @@ _ignore_completion_names (char **names, sh_ignore_func_t
*name_func)
return;
}
- if (force_fignore == 0)
+ if (allow_empty == 0)
{
while (oidx)
free (oldnames[--oidx]);
--
2.45.0
- [PATCH] fix `shopt -u force_fignore' affecting unrelated parts,
Koichi Murase <=