mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 03:32:24 +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 fromaad74597
with 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.
|
||||
|
||||
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:
|
||||
|
||||
- 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_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
|
||||
|
||||
/* 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))
|
||||
flags |= GLOB_DCASE;
|
||||
#endif
|
||||
if(sh_isstate(SH_COMPLETE))
|
||||
if(sh_isstate(SH_COMPLETE)) /* command completion */
|
||||
{
|
||||
extra += scantree(shp->alias_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_NOCHECK;
|
||||
}
|
||||
if(sh_isstate(SH_FCOMPLETE)) /* file name completion */
|
||||
flags |= GLOB_FCOMPLETE;
|
||||
gp->gl_fignore = nv_getval(sh_scoped(shp,FIGNORENOD));
|
||||
if(suflen)
|
||||
gp->gl_suffix = sufstr;
|
||||
|
|
|
@ -929,5 +929,24 @@ r > \)
|
|||
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))
|
||||
|
|
|
@ -113,7 +113,7 @@ struct _glob_
|
|||
#define GLOB_STARSTAR 0x0080 /* enable [/]**[/] expansion */
|
||||
#define GLOB_BRACE 0x0100 /* enable {...} expansion */
|
||||
#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_STACK 0x1000 /* allocate on current stack */
|
||||
#define GLOB_LIST 0x2000 /* just create gl_list */
|
||||
|
@ -121,6 +121,7 @@ struct _glob_
|
|||
#define GLOB_DISC 0x8000 /* discipline initialized */
|
||||
#define GLOB_GROUP 0x10000 /* REG_SHELL_GROUP */
|
||||
#define GLOB_DCASE 0x20000 /* detect FS case insensitivity */
|
||||
#define GLOB_FCOMPLETE 0x40000 /* shell file name completion */
|
||||
|
||||
/* gl_status */
|
||||
#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.
|
||||
*/
|
||||
#define GLOB_MAGIC 0xAAA80000 /* 10101010101010000000000000000000 */
|
||||
#define GLOB_FLAGMASK 0x0003FFFF /* 00000000000000111111111111111111 */
|
||||
#define GLOB_FLAGMASK 0x0007FFFF /* 00000000000001111111111111111111 */
|
||||
|
||||
#define MATCH_RAW 1
|
||||
#define MATCH_MAKE 2
|
||||
|
@ -543,9 +543,18 @@ skip:
|
|||
*restore2 = gp->gl_delim;
|
||||
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,'/')))
|
||||
&& name[0] == '.' && (!name[1] || name[1] == '.' && !name[2]))
|
||||
continue; /* never match '.' or '..' as final element unless specified literally */
|
||||
&& name[0] == '.' && (!name[1] || name[1] == '.' && !name[2])
|
||||
&& !(gp->gl_flags & GLOB_FCOMPLETE))
|
||||
continue;
|
||||
if (notdir = (gp->gl_status & GLOB_NOTDIR))
|
||||
gp->gl_status &= ~GLOB_NOTDIR;
|
||||
if (ire && !regexec(ire, name, 0, NiL, 0))
|
||||
|
|
Loading…
Reference in a new issue