From 9993ff07f2a89b249c7b39a017b87945f153e1e8 Mon Sep 17 00:00:00 2001 From: axel Date: Wed, 30 Nov 2005 00:33:52 +1000 Subject: [PATCH] Fix problem with recursive wildcards not working properly when postfixed with a regular string darcs-hash:20051129143352-ac50b-6fec789be36250f29d35458b15dbae423eed195c.gz --- wildcard.c | 266 +++++++++++++++++++++++++++-------------------------- 1 file changed, 134 insertions(+), 132 deletions(-) diff --git a/wildcard.c b/wildcard.c index 1421f4410..5ecdb9165 100644 --- a/wildcard.c +++ b/wildcard.c @@ -1,6 +1,8 @@ /** \file wildcard.c - My own globbing implementation. Needed to implement this to - support tab-expansion of globbed parameters. + + Fish needs it's own globbing implementation to support + tab-expansion of globbed parameters. Also provides recursive + wildcards using **. */ @@ -206,15 +208,13 @@ static wchar_t *make_path( const wchar_t *base_dir, const wchar_t *name ) int base_len = wcslen( base_dir ); if( !(long_name= malloc( sizeof(wchar_t)*(base_len+wcslen(name)+1) ))) { - - return 0; + die_mem(); } wcscpy( long_name, base_dir ); wcscpy(&long_name[base_len], name ); return long_name; } - void get_desc( wchar_t *fn, string_buffer_t *sb, int is_cmd ) { const wchar_t *desc; @@ -283,6 +283,11 @@ void get_desc( wchar_t *fn, string_buffer_t *sb, int is_cmd ) } } +/* + Test if the file specified by the given filename matches the + expantion flags specified. flags can be a combination of + EXECUTABLES_ONLY and DIRECTORIES_ONLY. +*/ static int test_flags( wchar_t *filename, int flags ) { @@ -307,11 +312,37 @@ int wildcard_expand( const wchar_t *wc, int flags, array_list_t *out ) { + + /* Points to the end of the current wildcard segment */ + wchar_t *wc_end; + + /* Variables for traversing a directory */ + struct dirent *next; + DIR *dir; + + /* The result returned */ + int res = 0; + + /* Length of the directory to search in */ + int base_len; + + /* Variables for testing for presense of recursive wildcards */ + wchar_t *wc_recursive; + int is_recursive; + + /* Sligtly mangled version of base_dir */ + const wchar_t *dir_string; + + /* Description for completions */ + string_buffer_t sb_desc; + // debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir ); if( flags & ACCEPT_INCOMPLETE ) { - /* Avoid excessive number of returned matches for wc ending with a * */ + /* + Avoid excessive number of returned matches for wc ending with a * + */ int len = wcslen(wc); if( len && (wc[len-1]==ANY_STRING) ) { @@ -322,50 +353,45 @@ int wildcard_expand( const wchar_t *wc, return res; } } - - struct dirent *next; - wchar_t *wc_end = wcschr(wc,L'/'); - DIR *dir; - - int res = 0; - int base_len = wcslen( base_dir ); - wchar_t *wc_recursive = wcschr( wc, ANY_STRING_RECURSIVE ); - int is_recursive = is_recursive = ( wc_recursive && (!wc_end || wc_recursive < wc_end)); + /* + Initialize various variables + */ - const wchar_t *dir_string = base_dir[0]==L'\0'?L".":base_dir; - - string_buffer_t sb_desc; - - sb_init( &sb_desc ); -// if( accept_incomplete ) -// wprintf( L"Glob %ls in '%ls'\n", wc, base_dir );//[0]==L'\0'?L".":base_dir ); - -/* - Test for recursive match string in current segment -*/ + dir_string = base_dir[0]==L'\0'?L".":base_dir; if( !(dir = wopendir( dir_string ))) { -// if( errno != EACCES && errno != ENOENT ) -// wperror( L"opendir" ); return 0; } -/* - Is this segment of the wildcard the last? -*/ - if( wc_end == 0 ) + wc_end = wcschr(wc,L'/'); + base_len = wcslen( base_dir ); + + /* + Test for recursive match string in current segment + */ + wc_recursive = wcschr( wc, ANY_STRING_RECURSIVE ); + is_recursive = ( wc_recursive && (!wc_end || wc_recursive < wc_end)); + + if( flags & ACCEPT_INCOMPLETE ) + sb_init( &sb_desc ); + + /* + Is this segment of the wildcard the last? + */ + if( !wc_end && !is_recursive ) { /* - Wildcard segment is the last segment + Wildcard segment is the last segment, Insert all matching files/directories */ if( wc[0]=='\0' ) { /* - The last wildcard segment is empty. Insert everything if completing, the directory itself otherwise. + The last wildcard segment is empty. Insert everything if + completing, the directory itself otherwise. */ if( flags & ACCEPT_INCOMPLETE ) { @@ -376,26 +402,16 @@ int wildcard_expand( const wchar_t *wc, wchar_t *name = str2wcs(next->d_name); if( name == 0 ) { -/* closedir( dir );*/ -/* return -1; */ continue; } wchar_t *long_name = make_path( base_dir, name ); - if( long_name == 0 ) - { - wperror( L"malloc" ); - closedir( dir ); - free(name); - return 0; - } - if( test_flags( long_name, flags ) ) { get_desc( long_name, &sb_desc, flags & EXECUTABLES_ONLY ); - al_push_check( out, + al_push( out, wcsdupcat(name, (wchar_t *)sb_desc.buff) ); } @@ -408,7 +424,7 @@ int wildcard_expand( const wchar_t *wc, else { res = 1; - al_push_check( out, wcsdup( base_dir ) ); + al_push( out, wcsdup( base_dir ) ); } } else @@ -424,31 +440,22 @@ int wildcard_expand( const wchar_t *wc, continue; } -/* wprintf( L"Filen heter %s\n\n\n", next->d_name );*/ /* wprintf( L"Match %ls (%s) against %ls\n\n\n", name, "tjo", wc );*/ if( flags & ACCEPT_INCOMPLETE ) { /* wprintf( L"match %ls to %ls\n", name, wc );*/ wchar_t *long_name = make_path( base_dir, name ); - if( long_name == 0 ) - { - wperror( L"malloc" ); - closedir( dir ); - free(name); - return 0; - } + /* - Test for matches before stating file, so as to minimize the number of stat calls + Test for matches before stating file, so as to minimize the number of calls to the much slower stat function */ if( wildcard_complete( name, wc, L"", 0, 0 ) ) - { - - + { if( test_flags( long_name, flags ) ) { get_desc( long_name, @@ -471,15 +478,8 @@ int wildcard_expand( const wchar_t *wc, if( wildcard_match2( name, wc, 1 ) ) { wchar_t *long_name = make_path( base_dir, name ); - if( long_name == 0 ) - { - wperror( L"malloc" ); - closedir( dir ); - free(name); - return 0; - } - al_push_check( out, long_name ); + al_push( out, long_name ); res = 1; } } @@ -507,23 +507,13 @@ int wildcard_expand( const wchar_t *wc, } new_dir= malloc( sizeof(wchar_t)*(base_len+ln+2) ); - wc_str = wcsndup(wc, wc_end-wc); + wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc); if( (!new_dir) || (!wc_str) ) { - if( new_dir ) - free( new_dir ); - if( wc_str ) - free( wc_str ); - wperror( L"malloc" ); - closedir( dir ); - return 0; + die_mem(); } - wcscpy( new_dir, base_dir ); - int has_base = 0; - - if ( *wc == ANY_STRING_RECURSIVE ) - has_base = wildcard_expand( wc_end + 1, base_dir, flags, out ); + wcscpy( new_dir, base_dir ); while( (next=readdir(dir))!=0 ) { @@ -532,75 +522,87 @@ int wildcard_expand( const wchar_t *wc, { continue; } + + /* + 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 partial_match = 0; - if( wildcard_match2( name, wc_str, 1 ) ) + /* + If we are doing recursive matching, also check if this + directory matches the part up to the recusrive + wildcard, if so, then we can search all subdirectories + for matches. + */ + if( is_recursive ) + { + 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 ); + free( wc_sub ); + } + + if( whole_match || partial_match ) { int new_len; struct stat buf; - wcscpy(&new_dir[base_len], name ); - free(name); - char *dir_str = wcs2str( new_dir ); + char *dir_str; int stat_res; - - if( !dir_str ) - { - continue; - } - - stat_res= stat( dir_str, &buf ); - free( dir_str ); - - if( stat_res ) - { - continue; - } - if( buf.st_mode & S_IFDIR ) + wcscpy(&new_dir[base_len], name ); + dir_str = wcs2str( new_dir ); + + if( dir_str ) { - new_len = wcslen( new_dir ); - new_dir[new_len] = L'/'; - new_dir[new_len+1] = L'\0'; + stat_res= stat( dir_str, &buf ); + free( dir_str ); - int has_entries = 0; - if( *wc == ANY_STRING_RECURSIVE ) - has_entries = wildcard_expand( wc, new_dir, flags, out ); - else - has_entries = wildcard_expand( wc_end + 1, new_dir, flags, out ); - - switch( has_entries ) + if( !stat_res ) { - case 0: - break; - case 1: - res = 1; - break; + if( buf.st_mode & S_IFDIR ) + { + new_len = wcslen( new_dir ); + new_dir[new_len] = L'/'; + new_dir[new_len+1] = L'\0'; + + /* + Regular matching + */ + if( whole_match ) + { + res |= wildcard_expand( wc_end?wc_end + 1:L"", + new_dir, + flags, + out ); + } + + /* + Recursive matching + */ + if( partial_match ) + { + res |= wildcard_expand( wcschr( wc, ANY_STRING_RECURSIVE ), + new_dir, + flags, + out ); + } + } } - } + } } - else - { - free(name); - } + free(name); } - res = res || has_base; + free( wc_str ); free( new_dir ); } closedir( dir ); - - sb_destroy( &sb_desc ); - + + if( flags & ACCEPT_INCOMPLETE ) + sb_destroy( &sb_desc ); + return res; } - -void al_push_check( array_list_t *l, const wchar_t *new ) -{ - int i; - - for( i = 0; i < al_get_count(l); i++ ) - if( !wcscmp( al_get(l, i), new ) ) - return; - - al_push( l, new ); -}