1
- // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1
+ // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2
2
// file at the top-level directory of this distribution and at
3
3
// http://rust-lang.org/COPYRIGHT.
4
4
//
@@ -51,7 +51,7 @@ pub struct Paths {
51
51
/// Return an iterator that produces all the Paths that match the given pattern,
52
52
/// which may be absolute or relative to the current working directory.
53
53
///
54
- /// is method uses the default match options and is equivalent to calling
54
+ /// This method uses the default match options and is equivalent to calling
55
55
/// `glob_with(pattern, MatchOptions::new())`. Use `glob_with` directly if you
56
56
/// want to use non-default match options.
57
57
///
@@ -117,9 +117,15 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
117
117
let dir_patterns = pattern. slice_from ( cmp:: min ( root_len, pattern. len ( ) ) )
118
118
. split_terminator ( is_sep)
119
119
. map ( |s| Pattern :: new ( s) )
120
- . collect ( ) ;
120
+ . collect :: < Vec < Pattern > > ( ) ;
121
121
122
- let todo = list_dir_sorted ( & root) . move_iter ( ) . map ( |x|( x, 0 u) ) . collect ( ) ;
122
+ let mut todo = Vec :: new ( ) ;
123
+ if dir_patterns. len ( ) > 0 {
124
+ // Shouldn't happen, but we're using -1 as a special index.
125
+ assert ! ( dir_patterns. len( ) < -1 as uint) ;
126
+
127
+ fill_todo ( & mut todo, dir_patterns. as_slice ( ) , 0 , & root, options) ;
128
+ }
123
129
124
130
Paths {
125
131
root : root,
@@ -138,6 +144,9 @@ impl Iterator<Path> for Paths {
138
144
}
139
145
140
146
let ( path, idx) = self . todo . pop ( ) . unwrap ( ) ;
147
+ // idx -1: was already checked by fill_todo, maybe path was '.' or
148
+ // '..' that we can't match here because of normalization.
149
+ if idx == -1 as uint { return Some ( path) ; }
141
150
let ref pattern = * self . dir_patterns . get ( idx) ;
142
151
143
152
if pattern. matches_with ( match path. filename_str ( ) {
@@ -154,21 +163,22 @@ impl Iterator<Path> for Paths {
154
163
// so we don't need to check the children
155
164
return Some ( path) ;
156
165
} else {
157
- self . todo . extend ( list_dir_sorted ( & path) . move_iter ( ) . map ( |x|( x, idx+1 ) ) ) ;
166
+ fill_todo ( & mut self . todo , self . dir_patterns . as_slice ( ) ,
167
+ idx + 1 , & path, self . options ) ;
158
168
}
159
169
}
160
170
}
161
171
}
162
172
163
173
}
164
174
165
- fn list_dir_sorted ( path : & Path ) -> Vec < Path > {
175
+ fn list_dir_sorted ( path : & Path ) -> Option < Vec < Path > > {
166
176
match fs:: readdir ( path) {
167
177
Ok ( mut children) => {
168
178
children. sort_by ( |p1, p2| p2. filename ( ) . cmp ( & p1. filename ( ) ) ) ;
169
- children. move_iter ( ) . collect ( )
179
+ Some ( children. move_iter ( ) . collect ( ) )
170
180
}
171
- Err ( ..) => Vec :: new ( )
181
+ Err ( ..) => None
172
182
}
173
183
}
174
184
@@ -435,6 +445,72 @@ impl Pattern {
435
445
436
446
}
437
447
448
+ // Fills `todo` with paths under `path` to be matched by `patterns[idx]`,
449
+ // special-casing patterns to match `.` and `..`, and avoiding `readdir()`
450
+ // calls when there are no metacharacters in the pattern.
451
+ fn fill_todo ( todo : & mut Vec < ( Path , uint ) > , patterns : & [ Pattern ] , idx : uint , path : & Path ,
452
+ options : MatchOptions ) {
453
+ // convert a pattern that's just many Char(_) to a string
454
+ fn pattern_as_str ( pattern : & Pattern ) -> Option < ~str > {
455
+ let mut s = ~"";
456
+ for token in pattern. tokens . iter ( ) {
457
+ match * token {
458
+ Char ( c) => s. push_char ( c) ,
459
+ _ => return None
460
+ }
461
+ }
462
+ return Some ( s) ;
463
+ }
464
+
465
+ let add = |todo : & mut Vec < _ > , next_path : Path | {
466
+ if idx + 1 == patterns. len ( ) {
467
+ // We know it's good, so don't make the iterator match this path
468
+ // against the pattern again. In particular, it can't match
469
+ // . or .. globs since these never show up as path components.
470
+ todo. push ( ( next_path, -1 as uint ) ) ;
471
+ } else {
472
+ fill_todo ( todo, patterns, idx + 1 , & next_path, options) ;
473
+ }
474
+ } ;
475
+
476
+ let pattern = & patterns[ idx] ;
477
+
478
+ match pattern_as_str ( pattern) {
479
+ Some ( s) => {
480
+ // This pattern component doesn't have any metacharacters, so we
481
+ // don't need to read the current directory to know where to
482
+ // continue. So instead of passing control back to the iterator,
483
+ // we can just check for that one entry and potentially recurse
484
+ // right away.
485
+ let special = "." == s || ".." == s;
486
+ let next_path = path. join ( s) ;
487
+ if ( special && path. is_dir ( ) ) || ( !special && next_path. exists ( ) ) {
488
+ add ( todo, next_path) ;
489
+ }
490
+ } ,
491
+ None => {
492
+ match list_dir_sorted ( path) {
493
+ Some ( entries) => {
494
+ todo. extend ( entries. move_iter ( ) . map ( |x|( x, idx) ) ) ;
495
+
496
+ // Matching the special directory entries . and .. that refer to
497
+ // the current and parent directory respectively requires that
498
+ // the pattern has a leading dot, even if the `MatchOptions` field
499
+ // `require_literal_leading_dot` is not set.
500
+ if pattern. tokens . len ( ) > 0 && pattern. tokens . get ( 0 ) == & Char ( '.' ) {
501
+ for & special in [ "." , ".." ] . iter ( ) {
502
+ if pattern. matches_with ( special, options) {
503
+ add ( todo, path. join ( special) ) ;
504
+ }
505
+ }
506
+ }
507
+ }
508
+ None => { }
509
+ }
510
+ }
511
+ }
512
+ }
513
+
438
514
fn parse_char_specifiers ( s : & [ char ] ) -> Vec < CharSpecifier > {
439
515
let mut cs = Vec :: new ( ) ;
440
516
let mut i = 0 ;
@@ -567,7 +643,7 @@ mod test {
567
643
fn test_absolute_pattern ( ) {
568
644
// assume that the filesystem is not empty!
569
645
assert ! ( glob( "/*" ) . next( ) . is_some( ) ) ;
570
- assert ! ( glob( "//" ) . next( ) . is_none ( ) ) ;
646
+ assert ! ( glob( "//" ) . next( ) . is_some ( ) ) ;
571
647
572
648
// check windows absolute paths with host/device components
573
649
let root_with_device = os:: getcwd ( ) . root_path ( ) . unwrap ( ) . join ( "*" ) ;
0 commit comments