summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/util/DirectoryScanner.php
blob: e04c4880635105518e428726d6620684d0e6c956 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
<?php
/*
 *  $Id: DirectoryScanner.php,v 1.15 2005/12/13 21:56:26 hlellelid Exp $
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information please see
 * <http://phing.info>.
 */

require_once 'phing/types/selectors/SelectorScanner.php'; 
include_once 'phing/util/StringHelper.php';
include_once 'phing/types/selectors/SelectorUtils.php';

/**
 * Class for scanning a directory for files/directories that match a certain
 * criteria.
 *
 * These criteria consist of a set of include and exclude patterns. With these
 * patterns, you can select which files you want to have included, and which
 * files you want to have excluded.
 *
 * The idea is simple. A given directory is recursively scanned for all files
 * and directories. Each file/directory is matched against a set of include
 * and exclude patterns. Only files/directories that match at least one
 * pattern of the include pattern list, and don't match a pattern of the
 * exclude pattern list will be placed in the list of files/directories found.
 *
 * When no list of include patterns is supplied, "**" will be used, which
 * means that everything will be matched. When no list of exclude patterns is
 * supplied, an empty list is used, such that nothing will be excluded.
 *
 * The pattern matching is done as follows:
 * The name to be matched is split up in path segments. A path segment is the
 * name of a directory or file, which is bounded by DIRECTORY_SEPARATOR
 * ('/' under UNIX, '\' under Windows).
 * E.g. "abc/def/ghi/xyz.php" is split up in the segments "abc", "def", "ghi"
 * and "xyz.php".
 * The same is done for the pattern against which should be matched.
 *
 * Then the segments of the name and the pattern will be matched against each
 * other. When '**' is used for a path segment in the pattern, then it matches
 * zero or more path segments of the name.
 *
 * There are special case regarding the use of DIRECTORY_SEPARATOR at
 * the beginning of the pattern and the string to match:
 * When a pattern starts with a DIRECTORY_SEPARATOR, the string
 * to match must also start with a DIRECTORY_SEPARATOR.
 * When a pattern does not start with a DIRECTORY_SEPARATOR, the
 * string to match may not start with a DIRECTORY_SEPARATOR.
 * When one of these rules is not obeyed, the string will not
 * match.
 *
 * When a name path segment is matched against a pattern path segment, the
 * following special characters can be used:
 *   '*' matches zero or more characters,
 *   '?' matches one character.
 *
 * Examples:
 *
 * "**\*.php" matches all .php files/dirs in a directory tree.
 *
 * "test\a??.php" matches all files/dirs which start with an 'a', then two
 * more characters and then ".php", in a directory called test.
 *
 * "**" matches everything in a directory tree.
 *
 * "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where
 * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
 *
 * Case sensitivity may be turned off if necessary.  By default, it is
 * turned on.
 *
 * Example of usage:
 *   $ds = new DirectroyScanner();
 *   $includes = array("**\*.php");
 *   $excludes = array("modules\*\**");
 *   $ds->SetIncludes($includes);
 *   $ds->SetExcludes($excludes);
 *   $ds->SetBasedir("test");
 *   $ds->SetCaseSensitive(true);
 *   $ds->Scan();
 *
 *   print("FILES:");
 *   $files = ds->GetIncludedFiles();
 *   for ($i = 0; $i < count($files);$i++) {
 *     println("$files[$i]\n");
 *   }
 *
 * This will scan a directory called test for .php files, but excludes all
 * .php files in all directories under a directory called "modules"
 *
 * This class is complete preg/ereg free port of the Java class
 * org.apache.tools.ant.DirectoryScanner. Even functions that use preg/ereg
 * internally (like split()) are not used. Only the _fast_ string functions
 * and comparison operators (=== !=== etc) are used for matching and tokenizing.
 *
 *  @author   Arnout J. Kuiper, ajkuiper@wxs.nl
 *  @author   Magesh Umasankar, umagesh@rediffmail.com
 *  @author   Andreas Aderhold, andi@binarycloud.com
 *
 *  @version   $Revision: 1.15 $
 *  @package   phing.util
 */
class DirectoryScanner implements SelectorScanner {

    /** default set of excludes */
    protected $DEFAULTEXCLUDES = array(
        "**/*~",
        "**/#*#",
        "**/.#*",
        "**/%*%",
        "**/CVS",
        "**/CVS/**",
        "**/.cvsignore",
        "**/SCCS",
        "**/SCCS/**",
        "**/vssver.scc",
		"**/.svn",
		"**/.svn/**",
		"**/._*",
		"**/.DS_Store",
    );

    /** The base directory which should be scanned. */
    protected $basedir;

    /** The patterns for the files that should be included. */
    protected $includes = null;

    /** The patterns for the files that should be excluded. */
    protected $excludes = null;

    /**
     * The files that where found and matched at least one includes, and matched
     * no excludes.
     */
    protected $filesIncluded;

    /** The files that where found and did not match any includes. Trie */
    protected $filesNotIncluded;

    /**
     * The files that where found and matched at least one includes, and also
     * matched at least one excludes. Trie object.
     */
    protected $filesExcluded;

    /**
     * The directories that where found and matched at least one includes, and
     * matched no excludes.
     */
    protected $dirsIncluded;

    /** The directories that where found and did not match any includes. */
    protected $dirsNotIncluded;

    /**
     * The files that where found and matched at least one includes, and also
     * matched at least one excludes.
     */
    protected $dirsExcluded;

    /** Have the vars holding our results been built by a slow scan? */
    protected $haveSlowResults = false;

    /** Should the file system be treated as a case sensitive one? */
    protected $isCaseSensitive = true;

    /** Selectors */
    protected $selectors = null;
    
    protected $filesDeselected;
    protected $dirsDeselected;
    
    /** if there are no deselected files */
    protected $everythingIncluded = true;        

    /**
     * Does the path match the start of this pattern up to the first "**".
     * This is a static mehtod and should always be called static
     *
     * This is not a general purpose test and should only be used if you
     * can live with false positives.
     *
     * pattern=**\a and str=b will yield true.
     *
     * @param   pattern             the (non-null) pattern to match against
     * @param   str                 the (non-null) string (path) to match
     * @param   isCaseSensitive     must matches be case sensitive?
     * @return  boolean             true if matches, otherwise false
     */
    function matchPatternStart($pattern, $str, $isCaseSensitive = true) {
        return SelectorUtils::matchPatternStart($pattern, $str, $isCaseSensitive);
    }

    /**
     * Matches a path against a pattern. Static
     *
     * @param pattern            the (non-null) pattern to match against
     * @param str                the (non-null) string (path) to match
     * @param isCaseSensitive    must a case sensitive match be done?
     *
     * @return true when the pattern matches against the string.
     *         false otherwise.
     */
    function matchPath($pattern, $str, $isCaseSensitive = true) {
        return SelectorUtils::matchPath($pattern, $str, $isCaseSensitive);
    }

    /**
     * Matches a string against a pattern. The pattern contains two special
     * characters:
     * '*' which means zero or more characters,
     * '?' which means one and only one character.
     *
     * @param  pattern the (non-null) pattern to match against
     * @param  str     the (non-null) string that must be matched against the
     *                 pattern
     *
     * @return boolean true when the string matches against the pattern,
     *                 false otherwise.
     * @access public
     */
    function match($pattern, $str, $isCaseSensitive = true) {
        return SelectorUtils::match($pattern, $str, $isCaseSensitive);
    }

    /**
     * Sets the basedir for scanning. This is the directory that is scanned
     * recursively. All '/' and '\' characters are replaced by
     * DIRECTORY_SEPARATOR
     *
     * @param basedir the (non-null) basedir for scanning
     */
    function setBasedir($_basedir) {
        $_basedir = str_replace('\\', DIRECTORY_SEPARATOR, $_basedir);
        $_basedir = str_replace('/', DIRECTORY_SEPARATOR, $_basedir);
        $this->basedir = $_basedir;
    }

    /**
     * Gets the basedir that is used for scanning. This is the directory that
     * is scanned recursively.
     *
     * @return the basedir that is used for scanning
     */
    function getBasedir() {
        return $this->basedir;
    }

    /**
     * Sets the case sensitivity of the file system
     *
     * @param specifies if the filesystem is case sensitive
     */
    function setCaseSensitive($_isCaseSensitive) {
        $this->isCaseSensitive = ($_isCaseSensitive) ? true : false;
    }

    /**
     * Sets the set of include patterns to use. All '/' and '\' characters are
     * replaced by DIRECTORY_SEPARATOR. So the separator used need
     * not match DIRECTORY_SEPARATOR.
     *
     * When a pattern ends with a '/' or '\', "**" is appended.
     *
     * @param includes list of include patterns
     */
    function setIncludes($_includes = array()) {
        if (empty($_includes) || is_null($_includes)) {
            $this->includes = null;
        } else {
            for ($i = 0; $i < count($_includes); $i++) {
                $pattern = null;
                $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_includes[$i]);
                $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern);
                if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) {
                    $pattern .= "**";
                }
                $this->includes[] = $pattern;
            }
        }
    }

    /**
     * Sets the set of exclude patterns to use. All '/' and '\' characters are
     * replaced by <code>File.separatorChar</code>. So the separator used need
     * not match <code>File.separatorChar</code>.
     *
     * When a pattern ends with a '/' or '\', "**" is appended.
     *
     * @param excludes list of exclude patterns
     */

    function setExcludes($_excludes = array()) {
        if (empty($_excludes) || is_null($_excludes)) {
            $this->excludes = null;
        } else {
            for ($i = 0; $i < count($_excludes); $i++) {
                $pattern = null;
                $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_excludes[$i]);
                $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern);
                if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) {
                    $pattern .= "**";
                }
                $this->excludes[] = $pattern;
            }
        }
    }

    /**
     * Scans the base directory for files that match at least one include
     * pattern, and don't match any exclude patterns.
     *
     */
    function scan() {
    
        if ((empty($this->basedir)) || (!@is_dir($this->basedir))) {
            return false;
        }

        if ($this->includes === null) {
            // No includes supplied, so set it to 'matches all'
            $this->includes = array("**");
        }
        if (is_null($this->excludes)) {
            $this->excludes = array();
        }

        $this->filesIncluded = array();
        $this->filesNotIncluded = array();
        $this->filesExcluded = array();
        $this->dirsIncluded = array();
        $this->dirsNotIncluded = array();
        $this->dirsExcluded = array();
        $this->dirsDeselected = array();
        $this->filesDeselected = array();
        
        if ($this->isIncluded("")) {
            if (!$this->isExcluded("")) {
                if ($this->isSelected("", $this->basedir)) {
                    $this->dirsIncluded[] = "";
                } else {
                    $this->dirsDeselected[] = "";
                }                
            } else {
                $this->dirsExcluded[] = "";
            }
        } else {
            $this->dirsNotIncluded[] = "";
        }

        $this->scandir($this->basedir, "", true);
        return true;
    }

    /**
     * Toplevel invocation for the scan.
     *
     * Returns immediately if a slow scan has already been requested.
     */
    protected function slowScan() {

        if ($this->haveSlowResults) {
            return;
        }

        // copy trie object add CopyInto() method
        $excl    = $this->dirsExcluded;
        $notIncl = $this->dirsNotIncluded;

        for ($i=0, $_i=count($excl); $i < $_i; $i++) {
            if (!$this->couldHoldIncluded($excl[$i])) {
                $this->scandir($this->basedir.$excl[$i], $excl[$i].DIRECTORY_SEPARATOR, false);
            }
        }

        for ($i=0, $_i=count($notIncl); $i < $_i; $i++) {
            if (!$this->couldHoldIncluded($notIncl[$i])) {
                $this->scandir($this->basedir.$notIncl[$i], $notIncl[$i].DIRECTORY_SEPARATOR, false);
            }
        }

        $this->haveSlowResults = true;
    }

    /**
     * Lists contens of a given directory and returns array with entries
     *
     * @param   src String. Source path and name file to copy.
     *
     * @access  public
     * @return  array  directory entries
     * @author  Albert Lash, alash@plateauinnovation.com
     */

    function listDir($_dir) {
        $d = dir($_dir);
        $list = array();
        while($entry = $d->read()) {
            if ($entry != "." && $entry != "..") {
                $list[] = $entry;
            }
        }
        $d->close();
        return $list;
    }

    /**
     * Scans the passed dir for files and directories. Found files and
     * directories are placed in their respective collections, based on the
     * matching of includes and excludes. When a directory is found, it is
     * scanned recursively.
     *
     * @param dir   the directory to scan
     * @param vpath the path relative to the basedir (needed to prevent
     *              problems with an absolute path when using dir)
     *
     * @access private
     * @see #filesIncluded
     * @see #filesNotIncluded
     * @see #filesExcluded
     * @see #dirsIncluded
     * @see #dirsNotIncluded
     * @see #dirsExcluded
     */
    private function scandir($_rootdir, $_vpath, $_fast) {
        
        if (!is_readable($_rootdir)) {
            return;
        }                                
        
        $newfiles = self::listDir($_rootdir);
        
        for ($i=0,$_i=count($newfiles); $i < $_i; $i++) {
            
            $file = $_rootdir . DIRECTORY_SEPARATOR . $newfiles[$i];
            $name = $_vpath . $newfiles[$i];

            if (@is_dir($file)) {
                if ($this->isIncluded($name)) {
                    if (!$this->isExcluded($name)) {
                        if ($this->isSelected($name, $file)) {
                            $this->dirsIncluded[] = $name;
                            if ($_fast) {
                                $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast);
                            }
                        } else {
                            $this->everythingIncluded = false;
                            $this->dirsDeselected[] = $name;
                            if ($_fast && $this->couldHoldIncluded($name)) {
                                $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast);
                            }                            
                        }                                                
                    } else {
                        $this->everythingIncluded = false;
                        $this->dirsExcluded[] = $name;
                        if ($_fast && $this->couldHoldIncluded($name)) {
                            $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast);
                        }
                    }
                } else {
                    $this->everythingIncluded = false;
                    $this->dirsNotIncluded[] = $name;
                    if ($_fast && $this->couldHoldIncluded($name)) {
                        $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast);
                    }
                }
                
                if (!$_fast) {
                    $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast);
                }
                
            } elseif (@is_file($file)) {
                if ($this->isIncluded($name)) {
                    if (!$this->isExcluded($name)) {
                        if ($this->isSelected($name, $file)) {
                            $this->filesIncluded[] = $name;
                        } else {
                            $this->everythingIncluded = false;
                            $this->filesDeselected[] = $name;
                        }                        
                    } else {
                        $this->everythingIncluded = false;
                        $this->filesExcluded[] = $name;
                    }
                } else {
                    $this->everythingIncluded = false;
                    $this->filesNotIncluded[] = $name;
                }
            }
        }
    }

    /**
     * Tests whether a name matches against at least one include pattern.
     *
     * @param name the name to match
     * @return <code>true</code> when the name matches against at least one
     *         include pattern, <code>false</code> otherwise.
     */
    protected function isIncluded($_name) {
        for ($i=0, $_i=count($this->includes); $i < $_i; $i++) {
            if (DirectoryScanner::matchPath($this->includes[$i], $_name, $this->isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether a name matches the start of at least one include pattern.
     *
     * @param name the name to match
     * @return <code>true</code> when the name matches against at least one
     *         include pattern, <code>false</code> otherwise.
     */
    protected function couldHoldIncluded($_name) {
        for ($i = 0; $i < count($this->includes); $i++) {
            if (DirectoryScanner::matchPatternStart($this->includes[$i], $_name, $this->isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether a name matches against at least one exclude pattern.
     *
     * @param name the name to match
     * @return <code>true</code> when the name matches against at least one
     *         exclude pattern, <code>false</code> otherwise.
     */
    protected function isExcluded($_name) {
        for ($i = 0; $i < count($this->excludes); $i++) {
            if (DirectoryScanner::matchPath($this->excludes[$i], $_name, $this->isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get the names of the files that matched at least one of the include
     * patterns, and matched none of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */
    function getIncludedFiles() {
        return $this->filesIncluded;        
    }

    /**
     * Get the names of the files that matched at none of the include patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */
    function getNotIncludedFiles() {
        $this->slowScan();
        return $this->filesNotIncluded;
    }

    /**
     * Get the names of the files that matched at least one of the include
     * patterns, an matched also at least one of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */

    function getExcludedFiles() {
        $this->slowScan();
        return $this->filesExcluded;
    }

    /**
     * <p>Returns the names of the files which were selected out and
     * therefore not ultimately included.</p>
     *
     * <p>The names are relative to the base directory. This involves
     * performing a slow scan if one has not already been completed.</p>
     *
     * @return the names of the files which were deselected.
     *
     * @see #slowScan
     */
    public function getDeselectedFiles() {
        $this->slowScan();        
        return $this->filesDeselected;
    }

    /**
     * Get the names of the directories that matched at least one of the include
     * patterns, an matched none of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */

    function getIncludedDirectories() {
        return $this->dirsIncluded;        
    }

    /**
     * Get the names of the directories that matched at none of the include
     * patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */
    function getNotIncludedDirectories() {
        $this->slowScan();
        return $this->dirsNotIncluded;        
    }

    /**
     * <p>Returns the names of the directories which were selected out and
     * therefore not ultimately included.</p>
     *
     * <p>The names are relative to the base directory. This involves
     * performing a slow scan if one has not already been completed.</p>
     *
     * @return the names of the directories which were deselected.
     *
     * @see #slowScan
     */
    public function getDeselectedDirectories() {
        $this->slowScan();
        return $this->dirsDeselected;
    }
    
    /**
     * Get the names of the directories that matched at least one of the include
     * patterns, an matched also at least one of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */
    function getExcludedDirectories() {
        $this->slowScan();
        return $this->dirsExcluded;        
    }

    /**
     * Adds the array with default exclusions to the current exclusions set.
     *
     */
    function addDefaultExcludes() {
        //$excludesLength = ($this->excludes == null) ? 0 : count($this->excludes);
        foreach($this->DEFAULTEXCLUDES as $pattern) {
            $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $pattern);
            $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern);
            $this->excludes[] = $pattern;
        }
    }
    
    /**
     * Sets the selectors that will select the filelist.
     *
     * @param selectors specifies the selectors to be invoked on a scan
     */
    public function setSelectors($selectors) {
        $this->selectors = $selectors;
    }

    /**
     * Returns whether or not the scanner has included all the files or
     * directories it has come across so far.
     *
     * @return <code>true</code> if all files and directories which have
     *         been found so far have been included.
     */
    public function isEverythingIncluded() {
        return $this->everythingIncluded;
    }
        
    /**
     * Tests whether a name should be selected.
     *
     * @param string $name The filename to check for selecting.
     * @param string $file The full file path.
     * @return boolean False when the selectors says that the file
     *         should not be selected, True otherwise.
     */
    protected function isSelected($name, $file) {
        if ($this->selectors !== null) {
            for ($i=0,$size=count($this->selectors); $i < $size; $i++) {
                if (($this->selectors[$i]->isSelected(new PhingFile($this->basedir), $name, new PhingFile($file))) === false) {
                    return false;
                }
            }
        }
        return true;
    }

}