mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Turns out there is a bona fide, honest-to-goodness use case for matching '.' and '..' in globbing after all. It's when globbing is used as the backend mechanism for file name completion in interactive shell editors. A tab invisibly adds a * at the end of the word to the left of your cursor and the resulting pattern is expanded. In5312a59d, this broke for '.' and '..'. Typing '.' followed by two tabs should result in a menu that includes './' and '../'. Typing '..' followed by a tab should result in '../', (or a menu that includes it if there are files with names starting with '..'). This is the behaviour in 93u+ and we should maintain this. To restore this functionality without reintroducing the harmful behaviour fixed in the referenced commits, we should special-case this, allowing '.' and '..' to match only for file name completion. src/lib/libast/include/glob.h: - Fix an inaccurate comment: the GLOB_COMPLETE flag is used for command completion, not file name completion. This is very clear from reading the path_expand() function in sh/expand.c. - Add new GLOB_FCOMPLETE flag for file name completion. src/lib/libast/misc/glob.c: - Adapt flags mask to fit the new flag. - glob_dir(): If GLOB_FCOMPLETE is passed, allow '.' and '..' to match even if expanded from a pattern. - Clarify the fix fromaad74597with an extended comment based on <https://github.com/ksh93/ksh/issues/146#issuecomment-790991990>. src/cmd/ksh93/sh/expand.c: path_expand(): - If we're in the SH_FCOMPLETE (file name completion) state, then pass the new GLOB_FCOMPLETE flag to AST glob(3). Fixes: https://github.com/ksh93/ksh/issues/372 Thanks to @fbrau for the bug report.
This commit is contained in:
parent
e54001d58b
commit
fc752b574a
6 changed files with 42 additions and 6 deletions
5
NEWS
5
NEWS
|
|
@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh
|
||||||
|
|
||||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
|
|
||||||
|
2021-12-13:
|
||||||
|
|
||||||
|
- Fixed a bug introduced on 2020-08-09 that prevented '.' and '..' from
|
||||||
|
being completed when using file name tab completion.
|
||||||
|
|
||||||
2021-12-11:
|
2021-12-11:
|
||||||
|
|
||||||
- Fixed two more crashing bugs that occurred if ksh received a signal (such
|
- Fixed two more crashing bugs that occurred if ksh received a signal (such
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
||||||
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
|
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
|
||||||
#define SH_RELEASE_DATE "2021-12-11" /* must be in this format for $((.sh.version)) */
|
#define SH_RELEASE_DATE "2021-12-13" /* must be in this format for $((.sh.version)) */
|
||||||
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
||||||
|
|
||||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ int path_expand(Shell_t *shp,const char *pattern, struct argnod **arghead)
|
||||||
if(sh_isoption(SH_GLOBCASEDET))
|
if(sh_isoption(SH_GLOBCASEDET))
|
||||||
flags |= GLOB_DCASE;
|
flags |= GLOB_DCASE;
|
||||||
#endif
|
#endif
|
||||||
if(sh_isstate(SH_COMPLETE))
|
if(sh_isstate(SH_COMPLETE)) /* command completion */
|
||||||
{
|
{
|
||||||
extra += scantree(shp->alias_tree,pattern,arghead);
|
extra += scantree(shp->alias_tree,pattern,arghead);
|
||||||
extra += scantree(shp->fun_tree,pattern,arghead);
|
extra += scantree(shp->fun_tree,pattern,arghead);
|
||||||
|
|
@ -92,6 +92,8 @@ int path_expand(Shell_t *shp,const char *pattern, struct argnod **arghead)
|
||||||
flags |= GLOB_COMPLETE;
|
flags |= GLOB_COMPLETE;
|
||||||
flags &= ~GLOB_NOCHECK;
|
flags &= ~GLOB_NOCHECK;
|
||||||
}
|
}
|
||||||
|
if(sh_isstate(SH_FCOMPLETE)) /* file name completion */
|
||||||
|
flags |= GLOB_FCOMPLETE;
|
||||||
gp->gl_fignore = nv_getval(sh_scoped(shp,FIGNORENOD));
|
gp->gl_fignore = nv_getval(sh_scoped(shp,FIGNORENOD));
|
||||||
if(suflen)
|
if(suflen)
|
||||||
gp->gl_suffix = sufstr;
|
gp->gl_suffix = sufstr;
|
||||||
|
|
|
||||||
|
|
@ -929,5 +929,24 @@ r > \)
|
||||||
r one two three end
|
r one two three end
|
||||||
!
|
!
|
||||||
|
|
||||||
|
# err_exit #
|
||||||
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
|
L tab completion of '.' and '..'
|
||||||
|
# https://github.com/ksh93/ksh/issues/372
|
||||||
|
|
||||||
|
d 15
|
||||||
|
|
||||||
|
# typing '.' followed by two tabs should show a menu that includes "number) ../"
|
||||||
|
p :test-1:
|
||||||
|
w : .\t\t
|
||||||
|
u ) \.\./\r\n$
|
||||||
|
|
||||||
|
# typing '..' followed by a tab should complete to '../' (as it is
|
||||||
|
# known that there are no files starting with '..' in the test PWD)
|
||||||
|
p :test-2:
|
||||||
|
w : ..\t
|
||||||
|
r : \.\./\r\n$
|
||||||
|
!
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ struct _glob_
|
||||||
#define GLOB_STARSTAR 0x0080 /* enable [/]**[/] expansion */
|
#define GLOB_STARSTAR 0x0080 /* enable [/]**[/] expansion */
|
||||||
#define GLOB_BRACE 0x0100 /* enable {...} expansion */
|
#define GLOB_BRACE 0x0100 /* enable {...} expansion */
|
||||||
#define GLOB_ICASE 0x0200 /* ignore case on match */
|
#define GLOB_ICASE 0x0200 /* ignore case on match */
|
||||||
#define GLOB_COMPLETE 0x0400 /* shell file completion */
|
#define GLOB_COMPLETE 0x0400 /* shell command completion */
|
||||||
#define GLOB_AUGMENTED 0x0800 /* augmented shell patterns */
|
#define GLOB_AUGMENTED 0x0800 /* augmented shell patterns */
|
||||||
#define GLOB_STACK 0x1000 /* allocate on current stack */
|
#define GLOB_STACK 0x1000 /* allocate on current stack */
|
||||||
#define GLOB_LIST 0x2000 /* just create gl_list */
|
#define GLOB_LIST 0x2000 /* just create gl_list */
|
||||||
|
|
@ -121,6 +121,7 @@ struct _glob_
|
||||||
#define GLOB_DISC 0x8000 /* discipline initialized */
|
#define GLOB_DISC 0x8000 /* discipline initialized */
|
||||||
#define GLOB_GROUP 0x10000 /* REG_SHELL_GROUP */
|
#define GLOB_GROUP 0x10000 /* REG_SHELL_GROUP */
|
||||||
#define GLOB_DCASE 0x20000 /* detect FS case insensitivity */
|
#define GLOB_DCASE 0x20000 /* detect FS case insensitivity */
|
||||||
|
#define GLOB_FCOMPLETE 0x40000 /* shell file name completion */
|
||||||
|
|
||||||
/* gl_status */
|
/* gl_status */
|
||||||
#define GLOB_NOTDIR 0x0001 /* last gl_dirnext() not a dir */
|
#define GLOB_NOTDIR 0x0001 /* last gl_dirnext() not a dir */
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
* for flags. If a new GLOB_* flag bit is added to glob.h, these must be adapted accordingly.
|
* for flags. If a new GLOB_* flag bit is added to glob.h, these must be adapted accordingly.
|
||||||
*/
|
*/
|
||||||
#define GLOB_MAGIC 0xAAA80000 /* 10101010101010000000000000000000 */
|
#define GLOB_MAGIC 0xAAA80000 /* 10101010101010000000000000000000 */
|
||||||
#define GLOB_FLAGMASK 0x0003FFFF /* 00000000000000111111111111111111 */
|
#define GLOB_FLAGMASK 0x0007FFFF /* 00000000000001111111111111111111 */
|
||||||
|
|
||||||
#define MATCH_RAW 1
|
#define MATCH_RAW 1
|
||||||
#define MATCH_MAKE 2
|
#define MATCH_MAKE 2
|
||||||
|
|
@ -543,9 +543,18 @@ skip:
|
||||||
*restore2 = gp->gl_delim;
|
*restore2 = gp->gl_delim;
|
||||||
while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
|
while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* For security and usability, only match '..' or '.' as the final element if:
|
||||||
|
* - its' specified literally, or
|
||||||
|
* - we're in file name completion mode.
|
||||||
|
* To avoid breaking globstar, make sure that '.' or '..' is skipped if, and only if, it is the
|
||||||
|
* final element in the pattern (i.e., if 'pat' does not contain a slash) and is not specified
|
||||||
|
* literally as '.' or '..', i.e. only if '.' or '..' was actually resolved from a glob pattern.
|
||||||
|
*/
|
||||||
if (!(matchdir && (pat[0] == '.' && (!pat[1] || pat[1] == '.' && !pat[2]) || strchr(pat,'/')))
|
if (!(matchdir && (pat[0] == '.' && (!pat[1] || pat[1] == '.' && !pat[2]) || strchr(pat,'/')))
|
||||||
&& name[0] == '.' && (!name[1] || name[1] == '.' && !name[2]))
|
&& name[0] == '.' && (!name[1] || name[1] == '.' && !name[2])
|
||||||
continue; /* never match '.' or '..' as final element unless specified literally */
|
&& !(gp->gl_flags & GLOB_FCOMPLETE))
|
||||||
|
continue;
|
||||||
if (notdir = (gp->gl_status & GLOB_NOTDIR))
|
if (notdir = (gp->gl_status & GLOB_NOTDIR))
|
||||||
gp->gl_status &= ~GLOB_NOTDIR;
|
gp->gl_status &= ~GLOB_NOTDIR;
|
||||||
if (ire && !regexec(ire, name, 0, NiL, 0))
|
if (ire && !regexec(ire, name, 0, NiL, 0))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue