mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Make wildcards beginning with dots not match . and ..
https://github.com/fish-shell/fish-shell/issues/270
This commit is contained in:
parent
3d5a3f03fa
commit
833abc27cc
5 changed files with 59 additions and 26 deletions
|
@ -512,7 +512,7 @@ bool contains_internal( const wchar_t *a, ... )
|
||||||
{
|
{
|
||||||
const wchar_t *arg;
|
const wchar_t *arg;
|
||||||
va_list va;
|
va_list va;
|
||||||
int res = 0;
|
bool res = false;
|
||||||
|
|
||||||
CHECK( a, 0 );
|
CHECK( a, 0 );
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ bool contains_internal( const wchar_t *a, ... )
|
||||||
{
|
{
|
||||||
if( wcscmp( a,arg) == 0 )
|
if( wcscmp( a,arg) == 0 )
|
||||||
{
|
{
|
||||||
res=1;
|
res = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
common.h
2
common.h
|
@ -175,7 +175,7 @@ extern const wchar_t *program_name;
|
||||||
#define N_(wstr) wstr
|
#define N_(wstr) wstr
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check if the specified stringelement is a part of the specified string list
|
Check if the specified string element is a part of the specified string list
|
||||||
*/
|
*/
|
||||||
#define contains( str,... ) contains_internal( str, __VA_ARGS__, NULL )
|
#define contains( str,... ) contains_internal( str, __VA_ARGS__, NULL )
|
||||||
|
|
||||||
|
|
|
@ -527,6 +527,12 @@ static int expand_test( const wchar_t *in, int flags, ... )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (size_t idx=0; idx < output.size(); idx++)
|
||||||
|
{
|
||||||
|
printf("%ls\n", output.at(idx).completion.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
va_start( va, flags );
|
va_start( va, flags );
|
||||||
|
|
||||||
|
@ -574,6 +580,21 @@ static void test_expand()
|
||||||
err( L"Cannot skip wildcard expansion" );
|
err( L"Cannot skip wildcard expansion" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (system("mkdir -p /tmp/fish_expand_test/")) err(L"mkdir failed");
|
||||||
|
if (system("touch /tmp/fish_expand_test/.foo")) err(L"touch failed");
|
||||||
|
if (system("touch /tmp/fish_expand_test/bar")) err(L"touch failed");
|
||||||
|
|
||||||
|
// This is checking that .* does NOT match . and .. (https://github.com/fish-shell/fish-shell/issues/270). But it does have to match literal components (e.g. "./*" has to match the same as "*"
|
||||||
|
if (! expand_test( L"/tmp/fish_expand_test/.*", 0, L"/tmp/fish_expand_test/.foo", 0 ))
|
||||||
|
{
|
||||||
|
err( L"Expansion not correctly handling dotfiles" );
|
||||||
|
}
|
||||||
|
if (! expand_test( L"/tmp/fish_expand_test/./.*", 0, L"/tmp/fish_expand_test/.foo", 0 ))
|
||||||
|
{
|
||||||
|
err( L"Expansion not correctly handling literal path components in dotfiles" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//system("rm -Rf /tmp/fish_expand_test");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test path functions */
|
/** Test path functions */
|
||||||
|
|
50
wildcard.cpp
50
wildcard.cpp
|
@ -143,29 +143,36 @@ int wildcard_has( const wchar_t *str, int internal )
|
||||||
\param wc The wildcard.
|
\param wc The wildcard.
|
||||||
\param is_first Whether files beginning with dots should not be matched against wildcards.
|
\param is_first Whether files beginning with dots should not be matched against wildcards.
|
||||||
*/
|
*/
|
||||||
static int wildcard_match2( const wchar_t *str,
|
static bool wildcard_match2(const wchar_t *str,
|
||||||
const wchar_t *wc,
|
const wchar_t *wc,
|
||||||
int is_first )
|
bool is_first )
|
||||||
{
|
{
|
||||||
if( *str == 0 && *wc==0 )
|
if( *str == 0 && *wc==0 )
|
||||||
return 1;
|
return true;
|
||||||
|
|
||||||
|
/* Hackish fix for https://github.com/fish-shell/fish-shell/issues/270. Prevent wildcards from matching . or .., but we must still allow literal matches. */
|
||||||
|
if (is_first && contains(str, L".", L".."))
|
||||||
|
{
|
||||||
|
/* The string is '.' or '..'. Return true if the wildcard exactly matches. */
|
||||||
|
return ! wcscmp(str, wc);
|
||||||
|
}
|
||||||
|
|
||||||
if( *wc == ANY_STRING || *wc == ANY_STRING_RECURSIVE)
|
if( *wc == ANY_STRING || *wc == ANY_STRING_RECURSIVE)
|
||||||
{
|
{
|
||||||
/* Ignore hidden file */
|
/* Ignore hidden file */
|
||||||
if( is_first && *str == L'.' )
|
if( is_first && *str == L'.' )
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try all submatches */
|
/* Try all submatches */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if( wildcard_match2( str, wc+1, 0 ) )
|
if( wildcard_match2( str, wc+1, false ) )
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
while( *(str++) != 0 );
|
while( *(str++) != 0 );
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
else if( *str == 0 )
|
else if( *str == 0 )
|
||||||
{
|
{
|
||||||
|
@ -173,23 +180,23 @@ static int wildcard_match2( const wchar_t *str,
|
||||||
End of string, but not end of wildcard, and the next wildcard
|
End of string, but not end of wildcard, and the next wildcard
|
||||||
element is not a '*', so this is not a match.
|
element is not a '*', so this is not a match.
|
||||||
*/
|
*/
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( *wc == ANY_CHAR )
|
if( *wc == ANY_CHAR )
|
||||||
{
|
{
|
||||||
if( is_first && *str == L'.' )
|
if( is_first && *str == L'.' )
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wildcard_match2( str+1, wc+1, 0 );
|
return wildcard_match2( str+1, wc+1, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( *wc == *str )
|
if( *wc == *str )
|
||||||
return wildcard_match2( str+1, wc+1, 0 );
|
return wildcard_match2( str+1, wc+1, false );
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -303,9 +310,9 @@ bool wildcard_complete(const wcstring &str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int wildcard_match( const wcstring &str, const wcstring &wc )
|
bool wildcard_match( const wcstring &str, const wcstring &wc )
|
||||||
{
|
{
|
||||||
return wildcard_match2( str.c_str(), wc.c_str(), 1 );
|
return wildcard_match2( str.c_str(), wc.c_str(), true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -685,6 +692,10 @@ typedef std::pair<dev_t, ino_t> file_id_t;
|
||||||
This function traverses the relevant directory tree looking for
|
This function traverses the relevant directory tree looking for
|
||||||
matches, and recurses when needed to handle wildcrards spanning
|
matches, and recurses when needed to handle wildcrards spanning
|
||||||
multiple components and recursive wildcards.
|
multiple components and recursive wildcards.
|
||||||
|
|
||||||
|
Because this function calls itself recursively with substrings,
|
||||||
|
it's important that the parameters be raw pointers instead of wcstring,
|
||||||
|
which would be too expensive to construct for all substrings.
|
||||||
*/
|
*/
|
||||||
static int wildcard_expand_internal( const wchar_t *wc,
|
static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
const wchar_t *base_dir,
|
const wchar_t *base_dir,
|
||||||
|
@ -709,7 +720,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
|
|
||||||
/* Variables for testing for presense of recursive wildcards */
|
/* Variables for testing for presense of recursive wildcards */
|
||||||
const wchar_t *wc_recursive;
|
const wchar_t *wc_recursive;
|
||||||
int is_recursive;
|
bool is_recursive;
|
||||||
|
|
||||||
/* Slightly mangled version of base_dir */
|
/* Slightly mangled version of base_dir */
|
||||||
const wchar_t *dir_string;
|
const wchar_t *dir_string;
|
||||||
|
@ -843,7 +854,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( wildcard_match2( name, wc, 1 ) )
|
if( wildcard_match2( name, wc, true ) )
|
||||||
{
|
{
|
||||||
const wcstring long_name = make_path(base_dir, next);
|
const wcstring long_name = make_path(base_dir, next);
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
|
@ -938,7 +949,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
Test if the file/directory name matches the whole
|
Test if the file/directory name matches the whole
|
||||||
wildcard element, i.e. regular matching.
|
wildcard element, i.e. regular matching.
|
||||||
*/
|
*/
|
||||||
int whole_match = wildcard_match2( name, wc_str, 1 );
|
int whole_match = wildcard_match2( name, wc_str, true );
|
||||||
int partial_match = 0;
|
int partial_match = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -951,7 +962,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
{
|
{
|
||||||
const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE );
|
const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE );
|
||||||
wchar_t *wc_sub = wcsndup( wc, end-wc+1);
|
wchar_t *wc_sub = wcsndup( wc, end-wc+1);
|
||||||
partial_match = wildcard_match2( name, wc_sub, 1 );
|
partial_match = wildcard_match2( name, wc_sub, true );
|
||||||
free( wc_sub );
|
free( wc_sub );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,8 +985,9 @@ static int wildcard_expand_internal( const wchar_t *wc,
|
||||||
{
|
{
|
||||||
// Insert a "file ID" into visited_files
|
// Insert a "file ID" into visited_files
|
||||||
// If the insertion fails, we've already visited this file (i.e. a symlink loop)
|
// If the insertion fails, we've already visited this file (i.e. a symlink loop)
|
||||||
|
// If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
|
||||||
const file_id_t file_id(buf.st_dev, buf.st_ino);
|
const file_id_t file_id(buf.st_dev, buf.st_ino);
|
||||||
if( S_ISDIR(buf.st_mode) && visited_files.insert(file_id).second)
|
if( S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
|
||||||
{
|
{
|
||||||
size_t new_len = wcslen( new_dir );
|
size_t new_len = wcslen( new_dir );
|
||||||
new_dir[new_len] = L'/';
|
new_dir[new_len] = L'/';
|
||||||
|
|
|
@ -75,7 +75,7 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_
|
||||||
\param wc The wildcard to test against
|
\param wc The wildcard to test against
|
||||||
\return true if the wildcard matched
|
\return true if the wildcard matched
|
||||||
*/
|
*/
|
||||||
int wildcard_match( const wcstring &str, const wcstring &wc );
|
bool wildcard_match( const wcstring &str, const wcstring &wc );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue