aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-10-15 18:16:47 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-10-15 18:16:47 -0700
commit833abc27cc8653d92c4d275c042f35ced0ea3f94 (patch)
tree98b6af707453a688e6c4dbb258eca2f219ddfbf7
parent3d5a3f03fa160edd0423ab6e8e93ba43c56b97a8 (diff)
Make wildcards beginning with dots not match . and ..
-rw-r--r--common.cpp4
-rw-r--r--common.h2
-rw-r--r--fish_tests.cpp25
-rw-r--r--wildcard.cpp52
-rw-r--r--wildcard.h2
5 files changed, 59 insertions, 26 deletions
diff --git a/common.cpp b/common.cpp
index 0e349f9e..b8dc4ceb 100644
--- a/common.cpp
+++ b/common.cpp
@@ -512,7 +512,7 @@ bool contains_internal( const wchar_t *a, ... )
{
const wchar_t *arg;
va_list va;
- int res = 0;
+ bool res = false;
CHECK( a, 0 );
@@ -521,7 +521,7 @@ bool contains_internal( const wchar_t *a, ... )
{
if( wcscmp( a,arg) == 0 )
{
- res=1;
+ res = true;
break;
}
diff --git a/common.h b/common.h
index 3413d69c..313ffba7 100644
--- a/common.h
+++ b/common.h
@@ -175,7 +175,7 @@ extern const wchar_t *program_name;
#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 )
diff --git a/fish_tests.cpp b/fish_tests.cpp
index 438254b4..cc39d3a2 100644
--- a/fish_tests.cpp
+++ b/fish_tests.cpp
@@ -527,7 +527,13 @@ 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 );
while( (arg=va_arg(va, wchar_t *) )!= 0 )
@@ -573,7 +579,22 @@ static void test_expand()
{
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 */
diff --git a/wildcard.cpp b/wildcard.cpp
index db42fadc..d32c8e01 100644
--- a/wildcard.cpp
+++ b/wildcard.cpp
@@ -143,29 +143,36 @@ int wildcard_has( const wchar_t *str, int internal )
\param wc The wildcard.
\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,
- int is_first )
+ bool is_first )
{
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)
{
/* Ignore hidden file */
if( is_first && *str == L'.' )
{
- return 0;
+ return false;
}
/* Try all submatches */
do
{
- if( wildcard_match2( str, wc+1, 0 ) )
- return 1;
+ if( wildcard_match2( str, wc+1, false ) )
+ return true;
}
while( *(str++) != 0 );
- return 0;
+ return false;
}
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
element is not a '*', so this is not a match.
*/
- return 0;
+ return false;
}
if( *wc == ANY_CHAR )
{
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 )
- 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 );
}
/**
@@ -684,7 +691,11 @@ typedef std::pair<dev_t, ino_t> file_id_t;
This function traverses the relevant directory tree looking for
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,
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 */
const wchar_t *wc_recursive;
- int is_recursive;
+ bool is_recursive;
/* Slightly mangled version of base_dir */
const wchar_t *dir_string;
@@ -843,7 +854,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
}
else
{
- if( wildcard_match2( name, wc, 1 ) )
+ if( wildcard_match2( name, wc, true ) )
{
const wcstring long_name = make_path(base_dir, next);
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
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;
/*
@@ -951,7 +962,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
{
const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE );
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 );
}
@@ -974,8 +985,9 @@ static int wildcard_expand_internal( const wchar_t *wc,
{
// Insert a "file ID" into visited_files
// 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);
- 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 );
new_dir[new_len] = L'/';
diff --git a/wildcard.h b/wildcard.h
index 40830f0c..9380375c 100644
--- a/wildcard.h
+++ b/wildcard.h
@@ -75,7 +75,7 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_
\param wc The wildcard to test against
\return true if the wildcard matched
*/
-int wildcard_match( const wcstring &str, const wcstring &wc );
+bool wildcard_match( const wcstring &str, const wcstring &wc );
/**