FileDocCategorySizeDatePackage
DirectoryScanner.javaAPI DocApache Ant 1.7060190Wed Dec 13 06:16:20 GMT 2006org.apache.tools.ant

DirectoryScanner

public class DirectoryScanner extends Object implements org.apache.tools.ant.types.selectors.SelectorScanner, org.apache.tools.ant.types.ResourceFactory, FileScanner
Class for scanning a directory for files/directories which match certain criteria.

These criteria consist of selectors and patterns which have been specified. With the selectors you can select which files you want to have included. Files which are not selected are excluded. With patterns you can include or exclude files based on their filename.

The idea is simple. A given directory is recursively scanned for all files and directories. Each file/directory is matched against a set of selectors, including special support for matching against filenames with include and and exclude patterns. Only files/directories which match at least one pattern of the include pattern list or other file selector, and don't match any pattern of the exclude pattern list or fail to match against a required selector 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. When no selectors are supplied, none are applied.

The filename 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 File.separator ('/' under UNIX, '\' under Windows). For example, "abc/def/ghi/xyz.java" is split up in the segments "abc", "def","ghi" and "xyz.java". The same is done for the pattern against which should be matched.

The segments of the name and the pattern are then matched against each other. When '**' is used for a path segment in the pattern, it matches zero or more path segments of the name.

There is a special case regarding the use of File.separators at the beginning of the pattern and the string to match:
When a pattern starts with a File.separator, the string to match must also start with a File.separator. When a pattern does not start with a File.separator, the string to match may not start with a File.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:

"**\*.class" matches all .class files/dirs in a directory tree.

"test\a??.java" matches all files/dirs which start with an 'a', then two more characters and then ".java", in a directory called test.

"**" matches everything in a directory tree.

"**\test\**\XYZ*" matches all files/dirs which 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:

String[] includes = {"**\\*.class"};
String[] excludes = {"modules\\*\\**"};
ds.setIncludes(includes);
ds.setExcludes(excludes);
ds.setBasedir(new File("test"));
ds.setCaseSensitive(true);
ds.scan();

System.out.println("FILES:");
String[] files = ds.getIncludedFiles();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
This will scan a directory called test for .class files, but excludes all files in all proper subdirectories of a directory called "modules"

Fields Summary
private static final boolean
ON_VMS
Is OpenVMS the operating system we're running on?
protected static final String[]
DEFAULTEXCLUDES
Patterns which should be excluded by default.

Note that you can now add patterns to the list of default excludes. Added patterns will not become part of this array that has only been kept around for backwards compatibility reasons.

private static final org.apache.tools.ant.util.FileUtils
FILE_UTILS
Helper.
private static final boolean[]
CS_SCAN_ONLY
iterations for case-sensitive scanning.
private static final boolean[]
CS_THEN_NON_CS
iterations for non-case-sensitive scanning.
private static Vector
defaultExcludes
Patterns which should be excluded by default.
protected File
basedir
The base directory to be scanned.
protected String[]
includes
The patterns for the files to be included.
protected String[]
excludes
The patterns for the files to be excluded.
protected org.apache.tools.ant.types.selectors.FileSelector[]
selectors
Selectors that will filter which files are in our candidate list.
protected Vector
filesIncluded
The files which matched at least one include and no excludes and were selected.
protected Vector
filesNotIncluded
The files which did not match any includes or selectors.
protected Vector
filesExcluded
The files which matched at least one include and at least one exclude.
protected Vector
dirsIncluded
The directories which matched at least one include and no excludes and were selected.
protected Vector
dirsNotIncluded
The directories which were found and did not match any includes.
protected Vector
dirsExcluded
The directories which matched at least one include and at least one exclude.
protected Vector
filesDeselected
The files which matched at least one include and no excludes and which a selector discarded.
protected Vector
dirsDeselected
The directories which matched at least one include and no excludes but which a selector discarded.
protected boolean
haveSlowResults
Whether or not our results were built by a slow scan.
protected boolean
isCaseSensitive
Whether or not the file system should be treated as a case sensitive one.
private boolean
followSymlinks
Whether or not symbolic links should be followed.
protected boolean
everythingIncluded
Whether or not everything tested so far has been included.
private Map
fileListMap
Temporary table to speed up the various scanning methods.
private Set
scannedDirs
List of all scanned directories.
private Set
includeNonPatterns
Set of all include patterns that are full file names and don't contain any wildcards.

If this instance is not case sensitive, the file names get turned to lower case.

Gets lazily initialized on the first invocation of isIncluded or isExcluded and cleared at the end of the scan method (cleared in clearCaches, actually).

private Set
excludeNonPatterns
Set of all include patterns that are full file names and don't contain any wildcards.

If this instance is not case sensitive, the file names get turned to lower case.

Gets lazily initialized on the first invocation of isIncluded or isExcluded and cleared at the end of the scan method (cleared in clearCaches, actually).

private String[]
includePatterns
Array of all include patterns that contain wildcards.

Gets lazily initialized on the first invocation of isIncluded or isExcluded and cleared at the end of the scan method (cleared in clearCaches, actually).

private String[]
excludePatterns
Array of all exclude patterns that contain wildcards.

Gets lazily initialized on the first invocation of isIncluded or isExcluded and cleared at the end of the scan method (cleared in clearCaches, actually).

private boolean
areNonPatternSetsReady
Have the non-pattern sets and pattern arrays for in- and excludes been initialized?
private boolean
scanning
Scanning flag.
private Object
scanLock
Scanning lock.
private boolean
slowScanning
Slow scanning flag.
private Object
slowScanLock
Slow scanning lock.
private IllegalStateException
illegal
Exception thrown during scan.
Constructors Summary
public DirectoryScanner()
Sole constructor.


           
      
    
Methods Summary
private voidaccountForIncludedDir(java.lang.String name, java.io.File file, boolean fast)
Process included directory.

param
name path of the directory relative to the directory of the FileSet.
param
file directory as File.
param
fast whether to perform fast scans.

        processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected);
        if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) {
            scandir(file, name + File.separator, fast);
        }
    
private voidaccountForIncludedFile(java.lang.String name, java.io.File file)
Process included file.

param
name path of the file relative to the directory of the FileSet.
param
file included File.

        processIncluded(name, file, filesIncluded, filesExcluded, filesDeselected);
    
public static booleanaddDefaultExclude(java.lang.String s)
Add a pattern to the default excludes unless it is already a default exclude.

param
s A string to add as an exclude pattern.
return
true if the string was added; false if it already existed.
since
Ant 1.6

        if (defaultExcludes.indexOf(s) == -1) {
            defaultExcludes.add(s);
            return true;
        }
        return false;
    
public synchronized voidaddDefaultExcludes()
Add default exclusions to the current exclusions set.

        int excludesLength = excludes == null ? 0 : excludes.length;
        String[] newExcludes;
        newExcludes = new String[excludesLength + defaultExcludes.size()];
        if (excludesLength > 0) {
            System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
        }
        String[] defaultExcludesTemp = getDefaultExcludes();
        for (int i = 0; i < defaultExcludesTemp.length; i++) {
            newExcludes[i + excludesLength] =
                defaultExcludesTemp[i].replace('/", File.separatorChar)
                .replace('\\", File.separatorChar);
        }
        excludes = newExcludes;
    
public synchronized voidaddExcludes(java.lang.String[] excludes)
Add to the list of exclude patterns to use. All '/' and '\' characters are replaced by File.separatorChar, so the separator used need not match File.separatorChar.

When a pattern ends with a '/' or '\', "**" is appended.

param
excludes A list of exclude patterns. May be null, in which case the exclude patterns don't get changed at all.
since
Ant 1.6.3

        if (excludes != null && excludes.length > 0) {
            if (this.excludes != null && this.excludes.length > 0) {
                String[] tmp = new String[excludes.length
                                          + this.excludes.length];
                System.arraycopy(this.excludes, 0, tmp, 0,
                                 this.excludes.length);
                for (int i = 0; i < excludes.length; i++) {
                    tmp[this.excludes.length + i] =
                        normalizePattern(excludes[i]);
                }
                this.excludes = tmp;
            } else {
                setExcludes(excludes);
            }
        }
    
private voidcheckIncludePatterns()
This routine is actually checking all the include patterns in order to avoid scanning everything under base dir.

since
Ant 1.6

        Map newroots = new HashMap();
        // put in the newroots map the include patterns without
        // wildcard tokens
        for (int i = 0; i < includes.length; i++) {
            if (FileUtils.isAbsolutePath(includes[i])) {
                //skip abs. paths not under basedir, if set:
                if (basedir != null
                    && !SelectorUtils.matchPatternStart(includes[i],
                    basedir.getAbsolutePath(), isCaseSensitive())) {
                    continue;
                }
            } else if (basedir == null) {
                //skip non-abs. paths if basedir == null:
                continue;
            }
            newroots.put(SelectorUtils.rtrimWildcardTokens(
                includes[i]), includes[i]);
        }
        if (newroots.containsKey("") && basedir != null) {
            // we are going to scan everything anyway
            scandir(basedir, "", true);
        } else {
            // only scan directories that can include matched files or
            // directories
            Iterator it = newroots.entrySet().iterator();

            File canonBase = null;
            if (basedir != null) {
                try {
                    canonBase = basedir.getCanonicalFile();
                } catch (IOException ex) {
                    throw new BuildException(ex);
                }
            }
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry) it.next();
                String currentelement = (String) entry.getKey();
                if (basedir == null && !FileUtils.isAbsolutePath(currentelement)) {
                    continue;
                }
                String originalpattern = (String) entry.getValue();
                File myfile = new File(basedir, currentelement);

                if (myfile.exists()) {
                    // may be on a case insensitive file system.  We want
                    // the results to show what's really on the disk, so
                    // we need to double check.
                    try {
                        String path = (basedir == null)
                            ? myfile.getCanonicalPath()
                            : FILE_UTILS.removeLeadingPath(canonBase,
                            myfile.getCanonicalFile());
                        if (!path.equals(currentelement) || ON_VMS) {
                            myfile = findFile(basedir, currentelement, true);
                            if (myfile != null && basedir != null) {
                                currentelement = FILE_UTILS.removeLeadingPath(
                                    basedir, myfile);
                            }
                        }
                    } catch (IOException ex) {
                        throw new BuildException(ex);
                    }
                }
                if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
                    File f = findFile(basedir, currentelement, false);
                    if (f != null && f.exists()) {
                        // adapt currentelement to the case we've
                        // actually found
                        currentelement = (basedir == null)
                            ? f.getAbsolutePath()
                            : FILE_UTILS.removeLeadingPath(basedir, f);
                        myfile = f;
                    }
                }
                if (myfile != null && myfile.exists()) {
                    if (!followSymlinks
                        && isSymlink(basedir, currentelement)) {
                        continue;
                    }
                    if (myfile.isDirectory()) {
                        if (isIncluded(currentelement)
                            && currentelement.length() > 0) {
                            accountForIncludedDir(currentelement, myfile, true);
                        }  else {
                            if (currentelement.length() > 0) {
                                if (currentelement.charAt(currentelement
                                                          .length() - 1)
                                    != File.separatorChar) {
                                    currentelement =
                                        currentelement + File.separatorChar;
                                }
                            }
                            scandir(myfile, currentelement, true);
                        }
                    } else {
                        boolean included = isCaseSensitive()
                            ? originalpattern.equals(currentelement)
                            : originalpattern.equalsIgnoreCase(currentelement);
                        if (included) {
                            accountForIncludedFile(currentelement, myfile);
                        }
                    }
                }
            }
        }
    
private synchronized voidclearCaches()
Clear internal caches.

since
Ant 1.6

        fileListMap.clear();
        includeNonPatterns.clear();
        excludeNonPatterns.clear();
        includePatterns = null;
        excludePatterns = null;
        areNonPatternSetsReady = false;
    
protected synchronized voidclearResults()
Clear the result caches for a scan.

        filesIncluded    = new Vector();
        filesNotIncluded = new Vector();
        filesExcluded    = new Vector();
        filesDeselected  = new Vector();
        dirsIncluded     = new Vector();
        dirsNotIncluded  = new Vector();
        dirsExcluded     = new Vector();
        dirsDeselected   = new Vector();
        everythingIncluded = (basedir != null);
        scannedDirs.clear();
    
private booleancontentsExcluded(java.lang.String name)
Test whether all contents of the specified directory must be excluded.

param
name the directory name to check.
return
whether all the specified directory's contents are excluded.

        name = (name.endsWith(File.separator)) ? name : name + File.separator;
        for (int i = 0; i < excludes.length; i++) {
            String e = excludes[i];
            if (e.endsWith("**") && SelectorUtils.matchPath(
                e.substring(0, e.length() - 2), name, isCaseSensitive())) {
                return true;
            }
        }
        return false;
    
protected booleancouldHoldIncluded(java.lang.String name)
Test whether or not a name matches the start of at least one include pattern.

param
name The name to match. Must not be null.
return
true when the name matches against the start of at least one include pattern, or false otherwise.

        for (int i = 0; i < includes.length; i++) {
            if (matchPatternStart(includes[i], name, isCaseSensitive())
                && isMorePowerfulThanExcludes(name, includes[i])
                && isDeeper(includes[i], name)) {
                return true;
            }
        }
        return false;
    
private synchronized voidensureNonPatternSetsReady()
Ensure that the in|exclude "patterns" have been properly divided up.

since
Ant 1.6.3

        if (!areNonPatternSetsReady) {
            includePatterns = fillNonPatternSet(includeNonPatterns, includes);
            excludePatterns = fillNonPatternSet(excludeNonPatterns, excludes);
            areNonPatternSetsReady = true;
        }
    
private java.lang.String[]fillNonPatternSet(java.util.Set set, java.lang.String[] patterns)
Add all patterns that are not real patterns (do not contain wildcards) to the set and returns the real patterns.

param
set Set to populate.
param
patterns String[] of patterns.
since
Ant 1.6.3

        ArrayList al = new ArrayList(patterns.length);
        for (int i = 0; i < patterns.length; i++) {
            if (!SelectorUtils.hasWildcards(patterns[i])) {
                set.add(isCaseSensitive() ? patterns[i]
                    : patterns[i].toUpperCase());
            } else {
                al.add(patterns[i]);
            }
        }
        return set.size() == 0 ? patterns
            : (String[]) al.toArray(new String[al.size()]);
    
private java.io.FilefindFile(java.io.File base, java.lang.String path, boolean cs)
From base traverse the filesystem in order to find a file that matches the given name.

param
base base File (dir).
param
path file path.
param
cs whether to scan case-sensitively.
return
File object that points to the file in question or null.
since
Ant 1.6.3

        if (FileUtils.isAbsolutePath(path)) {
            if (base == null) {
                String[] s = FILE_UTILS.dissect(path);
                base = new File(s[0]);
                path = s[1];
            } else {
                File f = FILE_UTILS.normalize(path);
                String s = FILE_UTILS.removeLeadingPath(base, f);
                if (s.equals(f.getAbsolutePath())) {
                    //removing base from path yields no change; path not child of base
                    return null;
                }
                path = s;
            }
        }
        return findFile(base, SelectorUtils.tokenizePath(path), cs);
    
private java.io.FilefindFile(java.io.File base, java.util.Vector pathElements, boolean cs)
From base traverse the filesystem in order to find a file that matches the given stack of names.

param
base base File (dir).
param
pathElements Vector of path elements (dirs...file).
param
cs whether to scan case-sensitively.
return
File object that points to the file in question or null.
since
Ant 1.6.3

        if (pathElements.size() == 0) {
            return base;
        }
        String current = (String) pathElements.remove(0);
        if (base == null) {
            return findFile(new File(current), pathElements, cs);
        }
        if (!base.isDirectory()) {
            return null;
        }
        String[] files = list(base);
        if (files == null) {
            throw new BuildException("IO error scanning directory "
                                     + base.getAbsolutePath());
        }
        boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
        for (int i = 0; i < matchCase.length; i++) {
            for (int j = 0; j < files.length; j++) {
                if (matchCase[i] ? files[j].equals(current)
                                 : files[j].equalsIgnoreCase(current)) {
                    return findFile(new File(base, files[j]), pathElements, cs);
                }
            }
        }
        return null;
    
public synchronized java.io.FilegetBasedir()
Return the base directory to be scanned. This is the directory which is scanned recursively.

return
the base directory to be scanned.

        return basedir;
    
public static java.lang.String[]getDefaultExcludes()
Get the list of patterns that should be excluded by default.

return
An array of String based on the current contents of the defaultExcludes Vector.
since
Ant 1.6

        return (String[]) defaultExcludes.toArray(new String[defaultExcludes
                                                             .size()]);
    
public synchronized java.lang.String[]getDeselectedDirectories()

Return the names of the directories which were selected out and therefore not ultimately included.

The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the directories which were deselected.
see
#slowScan

        slowScan();
        String[] directories = new String[dirsDeselected.size()];
        dirsDeselected.copyInto(directories);
        return directories;
    
public synchronized java.lang.String[]getDeselectedFiles()

Return the names of the files which were selected out and therefore not ultimately included.

The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the files which were deselected.
see
#slowScan

        slowScan();
        String[] files = new String[filesDeselected.size()];
        filesDeselected.copyInto(files);
        return files;
    
public synchronized java.lang.String[]getExcludedDirectories()
Return the names of the directories which matched at least one of the include patterns and at least one of the exclude patterns. The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the directories which matched at least one of the include patterns and at least one of the exclude patterns.
see
#slowScan

        slowScan();
        String[] directories = new String[dirsExcluded.size()];
        dirsExcluded.copyInto(directories);
        return directories;
    
public synchronized java.lang.String[]getExcludedFiles()
Return the names of the files which matched at least one of the include patterns and at least one of the exclude patterns. The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the files which matched at least one of the include patterns and at least one of the exclude patterns.
see
#slowScan

        slowScan();
        String[] files = new String[filesExcluded.size()];
        filesExcluded.copyInto(files);
        return files;
    
public synchronized java.lang.String[]getIncludedDirectories()
Return the names of the directories which matched at least one of the include patterns and none of the exclude patterns. The names are relative to the base directory.

return
the names of the directories which matched at least one of the include patterns and none of the exclude patterns.

        if (dirsIncluded == null) {
            throw new IllegalStateException("Must call scan() first");
        }
        String[] directories = new String[dirsIncluded.size()];
        dirsIncluded.copyInto(directories);
        Arrays.sort(directories);
        return directories;
    
public synchronized intgetIncludedDirsCount()
Return the count of included directories.

return
int.
since
Ant 1.6.3

        if (dirsIncluded == null) {
            throw new IllegalStateException("Must call scan() first");
        }
        return dirsIncluded.size();
    
public synchronized java.lang.String[]getIncludedFiles()
Return the names of the files which matched at least one of the include patterns and none of the exclude patterns. The names are relative to the base directory.

return
the names of the files which matched at least one of the include patterns and none of the exclude patterns.

        if (filesIncluded == null) {
            throw new IllegalStateException("Must call scan() first");
        }
        String[] files = new String[filesIncluded.size()];
        filesIncluded.copyInto(files);
        Arrays.sort(files);
        return files;
    
public synchronized intgetIncludedFilesCount()
Return the count of included files.

return
int.
since
Ant 1.6.3

        if (filesIncluded == null) {
            throw new IllegalStateException("Must call scan() first");
        }
        return filesIncluded.size();
    
public synchronized java.lang.String[]getNotIncludedDirectories()
Return the names of the directories which matched none of the include patterns. The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the directories which matched none of the include patterns.
see
#slowScan

        slowScan();
        String[] directories = new String[dirsNotIncluded.size()];
        dirsNotIncluded.copyInto(directories);
        return directories;
    
public synchronized java.lang.String[]getNotIncludedFiles()
Return the names of the files which matched none of the include patterns. The names are relative to the base directory. This involves performing a slow scan if one has not already been completed.

return
the names of the files which matched none of the include patterns.
see
#slowScan

        slowScan();
        String[] files = new String[filesNotIncluded.size()];
        filesNotIncluded.copyInto(files);
        return files;
    
public synchronized org.apache.tools.ant.types.ResourcegetResource(java.lang.String name)
Get the named resource.

param
name path name of the file relative to the dir attribute.
return
the resource with the given name.
since
Ant 1.5.2

        return new FileResource(basedir, name);
    
java.util.SetgetScannedDirs()
This method is of interest for testing purposes. The returned Set is live and should not be modified.

return
the Set of relative directory names that have been scanned.

        return scannedDirs;
    
private booleanhasBeenScanned(java.lang.String vpath)
Has the directory with the given path relative to the base directory already been scanned?

Registers the given directory as scanned as a side effect.

since
Ant 1.6

        return !scannedDirs.add(vpath);
    
public synchronized booleanisCaseSensitive()
Find out whether include exclude patterns are matched in a case sensitive way.

return
whether or not the scanning is case sensitive.
since
Ant 1.6

        return isCaseSensitive;
    
private booleanisDeeper(java.lang.String pattern, java.lang.String name)
Verify that a pattern specifies files deeper than the level of the specified file.

param
pattern the pattern to check.
param
name the name to check.
return
whether the pattern is deeper than the name.
since
Ant 1.6.3

        Vector p = SelectorUtils.tokenizePath(pattern);
        Vector n = SelectorUtils.tokenizePath(name);
        return p.contains("**") || p.size() > n.size();
    
public synchronized booleanisEverythingIncluded()
Return whether or not the scanner has included all the files or directories it has come across so far.

return
true if all files and directories which have been found so far have been included.

        return everythingIncluded;
    
protected booleanisExcluded(java.lang.String name)
Test whether or not a name matches against at least one exclude pattern.

param
name The name to match. Must not be null.
return
true when the name matches against at least one exclude pattern, or false otherwise.

        ensureNonPatternSetsReady();

        if (isCaseSensitive()
            ? excludeNonPatterns.contains(name)
            : excludeNonPatterns.contains(name.toUpperCase())) {
            return true;
        }
        for (int i = 0; i < excludePatterns.length; i++) {
            if (matchPath(excludePatterns[i], name, isCaseSensitive())) {
                return true;
            }
        }
        return false;
    
public synchronized booleanisFollowSymlinks()
Get whether or not a DirectoryScanner follows symbolic links.

return
flag indicating whether symbolic links should be followed.
since
Ant 1.6

        return followSymlinks;
    
protected booleanisIncluded(java.lang.String name)
Test whether or not a name matches against at least one include pattern.

param
name The name to match. Must not be null.
return
true when the name matches against at least one include pattern, or false otherwise.

        ensureNonPatternSetsReady();

        if (isCaseSensitive()
            ? includeNonPatterns.contains(name)
            : includeNonPatterns.contains(name.toUpperCase())) {
            return true;
        }
        for (int i = 0; i < includePatterns.length; i++) {
            if (matchPath(includePatterns[i], name, isCaseSensitive())) {
                return true;
            }
        }
        return false;
    
private booleanisMorePowerfulThanExcludes(java.lang.String name, java.lang.String includepattern)
Find out whether one particular include pattern is more powerful than all the excludes. Note: the power comparison is based on the length of the include pattern and of the exclude patterns without the wildcards. Ideally the comparison should be done based on the depth of the match; that is to say how many file separators have been matched before the first ** or the end of the pattern. IMPORTANT : this function should return false "with care".

param
name the relative path to test.
param
includepattern one include pattern.
return
true if there is no exclude pattern more powerful than this include pattern.
since
Ant 1.6

        String soughtexclude = name + File.separator + "**";
        for (int counter = 0; counter < excludes.length; counter++) {
            if (excludes[counter].equals(soughtexclude))  {
                return false;
            }
        }
        return true;
    
protected booleanisSelected(java.lang.String name, java.io.File file)
Test whether a file should be selected.

param
name the filename to check for selecting.
param
file the java.io.File object for this filename.
return
false when the selectors says that the file should not be selected, true otherwise.

        if (selectors != null) {
            for (int i = 0; i < selectors.length; i++) {
                if (!selectors[i].isSelected(basedir, name, file)) {
                    return false;
                }
            }
        }
        return true;
    
private booleanisSymlink(java.io.File base, java.lang.String path)
Do we have to traverse a symlink when trying to reach path from basedir?

param
base base File (dir).
param
path file path.
since
Ant 1.6

        return isSymlink(base, SelectorUtils.tokenizePath(path));
    
private booleanisSymlink(java.io.File base, java.util.Vector pathElements)
Do we have to traverse a symlink when trying to reach path from basedir?

param
base base File (dir).
param
pathElements Vector of path elements (dirs...file).
since
Ant 1.6

        if (pathElements.size() > 0) {
            String current = (String) pathElements.remove(0);
            try {
                return FILE_UTILS.isSymbolicLink(base, current)
                    || isSymlink(new File(base, current), pathElements);
            } catch (IOException ioe) {
                String msg = "IOException caught while checking "
                    + "for links, couldn't get canonical path!";
                // will be caught and redirected to Ant's logging system
                System.err.println(msg);
            }
        }
        return false;
    
private java.lang.String[]list(java.io.File file)
Return a cached result of list performed on file, if available. Invokes the method and caches the result otherwise.

param
file File (dir) to list.
since
Ant 1.6

        String[] files = (String[]) fileListMap.get(file);
        if (files == null) {
            files = file.list();
            if (files != null) {
                fileListMap.put(file, files);
            }
        }
        return files;
    
public static booleanmatch(java.lang.String pattern, java.lang.String str)
Test whether or not a string matches against a pattern. The pattern may contain two special characters:
'*' means zero or more characters
'?' means one and only one character

param
pattern The pattern to match against. Must not be null.
param
str The string which must be matched against the pattern. Must not be null.
return
true if the string matches against the pattern, or false otherwise.

        return SelectorUtils.match(pattern, str);
    
protected static booleanmatch(java.lang.String pattern, java.lang.String str, boolean isCaseSensitive)
Test whether or not a string matches against a pattern. The pattern may contain two special characters:
'*' means zero or more characters
'?' means one and only one character

param
pattern The pattern to match against. Must not be null.
param
str The string which must be matched against the pattern. Must not be null.
param
isCaseSensitive Whether or not matching should be performed case sensitively.
return
true if the string matches against the pattern, or false otherwise.

        return SelectorUtils.match(pattern, str, isCaseSensitive);
    
protected static booleanmatchPath(java.lang.String pattern, java.lang.String str)
Test whether or not a given path matches a given pattern.

param
pattern The pattern to match against. Must not be null.
param
str The path to match, as a String. Must not be null.
return
true if the pattern matches against the string, or false otherwise.

        return SelectorUtils.matchPath(pattern, str);
    
protected static booleanmatchPath(java.lang.String pattern, java.lang.String str, boolean isCaseSensitive)
Test whether or not a given path matches a given pattern.

param
pattern The pattern to match against. Must not be null.
param
str The path to match, as a String. Must not be null.
param
isCaseSensitive Whether or not matching should be performed case sensitively.
return
true if the pattern matches against the string, or false otherwise.

        return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
    
protected static booleanmatchPatternStart(java.lang.String pattern, java.lang.String str)
Test whether or not a given path matches the start of a given pattern up to the first "**".

This is not a general purpose test and should only be used if you can live with false positives. For example, pattern=**\a and str=b will yield true.

param
pattern The pattern to match against. Must not be null.
param
str The path to match, as a String. Must not be null.
return
whether or not a given path matches the start of a given pattern up to the first "**".

        return SelectorUtils.matchPatternStart(pattern, str);
    
protected static booleanmatchPatternStart(java.lang.String pattern, java.lang.String str, boolean isCaseSensitive)
Test whether or not a given path matches the start of a given pattern up to the first "**".

This is not a general purpose test and should only be used if you can live with false positives. For example, pattern=**\a and str=b will yield true.

param
pattern The pattern to match against. Must not be null.
param
str The path to match, as a String. Must not be null.
param
isCaseSensitive Whether or not matching should be performed case sensitively.
return
whether or not a given path matches the start of a given pattern up to the first "**".

        return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
    
private static java.lang.StringnormalizePattern(java.lang.String p)
All '/' and '\' characters are replaced by File.separatorChar, so the separator used need not match File.separatorChar.

When a pattern ends with a '/' or '\', "**" is appended.

since
Ant 1.6.3

        String pattern = p.replace('/", File.separatorChar)
            .replace('\\", File.separatorChar);
        if (pattern.endsWith(File.separator)) {
            pattern += "**";
        }
        return pattern;
    
private voidprocessIncluded(java.lang.String name, java.io.File file, java.util.Vector inc, java.util.Vector exc, java.util.Vector des)


        if (inc.contains(name) || exc.contains(name) || des.contains(name)) { return; }

        boolean included = false;
        if (isExcluded(name)) {
            exc.add(name);
        } else if (isSelected(name, file)) {
            included = true;
            inc.add(name);
        } else {
            des.add(name);
        }
        everythingIncluded &= included;
    
private voidprocessSlowScan(java.lang.String[] arr)

        for (int i = 0; i < arr.length; i++) {
            if (!couldHoldIncluded(arr[i])) {
                scandir(new File(basedir, arr[i]),
                        arr[i] + File.separator, false);
            }
        }
    
public static booleanremoveDefaultExclude(java.lang.String s)
Remove a string if it is a default exclude.

param
s The string to attempt to remove.
return
true if s was a default exclude (and thus was removed); false if s was not in the default excludes list to begin with.
since
Ant 1.6

        return defaultExcludes.remove(s);
    
public static voidresetDefaultExcludes()
Go back to the hardwired default exclude patterns.

since
Ant 1.6

        defaultExcludes = new Vector();
        for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
            defaultExcludes.add(DEFAULTEXCLUDES[i]);
        }
    
public voidscan()
Scan for files which match at least one include pattern and don't match any exclude patterns. If there are selectors then the files must pass muster there, as well. Scans under basedir, if set; otherwise the include patterns without leading wildcards specify the absolute paths of the files that may be included.

exception
IllegalStateException if the base directory was set incorrectly (i.e. if it doesn't exist or isn't a directory).

        synchronized (scanLock) {
            if (scanning) {
                while (scanning) {
                    try {
                        scanLock.wait();
                    } catch (InterruptedException e) {
                        continue;
                    }
                }
                if (illegal != null) {
                    throw illegal;
                }
                return;
            }
            scanning = true;
        }
        try {
            synchronized (this) {
                illegal = null;
                clearResults();

                // set in/excludes to reasonable defaults if needed:
                boolean nullIncludes = (includes == null);
                includes = nullIncludes ? new String[] {"**"} : includes;
                boolean nullExcludes = (excludes == null);
                excludes = nullExcludes ? new String[0] : excludes;

                if (basedir == null) {
                    // if no basedir and no includes, nothing to do:
                    if (nullIncludes) {
                        return;
                    }
                } else {
                    if (!basedir.exists()) {
                        illegal = new IllegalStateException("basedir " + basedir
                                                            + " does not exist");
                    }
                    if (!basedir.isDirectory()) {
                        illegal = new IllegalStateException("basedir " + basedir
                                                            + " is not a directory");
                    }
                    if (illegal != null) {
                        throw illegal;
                    }
                }
                if (isIncluded("")) {
                    if (!isExcluded("")) {
                        if (isSelected("", basedir)) {
                            dirsIncluded.addElement("");
                        } else {
                            dirsDeselected.addElement("");
                        }
                    } else {
                        dirsExcluded.addElement("");
                    }
                } else {
                    dirsNotIncluded.addElement("");
                }
                checkIncludePatterns();
                clearCaches();
                includes = nullIncludes ? null : includes;
                excludes = nullExcludes ? null : excludes;
            }
        } finally {
            synchronized (scanLock) {
                scanning = false;
                scanLock.notifyAll();
            }
        }
    
protected voidscandir(java.io.File dir, java.lang.String vpath, boolean fast)
Scan the given directory for files and directories. Found files and directories are placed in their respective collections, based on the matching of includes, excludes, and the selectors. When a directory is found, it is scanned recursively.

param
dir The directory to scan. Must not be null.
param
vpath The path relative to the base directory (needed to prevent problems with an absolute path when using dir). Must not be null.
param
fast Whether or not this call is part of a fast scan.
see
#filesIncluded
see
#filesNotIncluded
see
#filesExcluded
see
#dirsIncluded
see
#dirsNotIncluded
see
#dirsExcluded
see
#slowScan

        if (dir == null) {
            throw new BuildException("dir must not be null.");
        } else if (!dir.exists()) {
            throw new BuildException(dir + " doesn't exist.");
        } else if (!dir.isDirectory()) {
            throw new BuildException(dir + " is not a directory.");
        }
        // avoid double scanning of directories, can only happen in fast mode
        if (fast && hasBeenScanned(vpath)) {
            return;
        }
        String[] newfiles = dir.list();

        if (newfiles == null) {
            /*
             * two reasons are mentioned in the API docs for File.list
             * (1) dir is not a directory. This is impossible as
             *     we wouldn't get here in this case.
             * (2) an IO error occurred (why doesn't it throw an exception
             *     then???)
             */
            throw new BuildException("IO error scanning directory '"
                                     + dir.getAbsolutePath() + "'");
        }
        if (!followSymlinks) {
            Vector noLinks = new Vector();
            for (int i = 0; i < newfiles.length; i++) {
                try {
                    if (FILE_UTILS.isSymbolicLink(dir, newfiles[i])) {
                        String name = vpath + newfiles[i];
                        File file = new File(dir, newfiles[i]);
                        (file.isDirectory()
                            ? dirsExcluded : filesExcluded).addElement(name);
                    } else {
                        noLinks.addElement(newfiles[i]);
                    }
                } catch (IOException ioe) {
                    String msg = "IOException caught while checking "
                        + "for links, couldn't get canonical path!";
                    // will be caught and redirected to Ant's logging system
                    System.err.println(msg);
                    noLinks.addElement(newfiles[i]);
                }
            }
            newfiles = (String[]) (noLinks.toArray(new String[noLinks.size()]));
        }
        for (int i = 0; i < newfiles.length; i++) {
            String name = vpath + newfiles[i];
            File file = new File(dir, newfiles[i]);
            if (file.isDirectory()) {
                if (isIncluded(name)) {
                    accountForIncludedDir(name, file, fast);
                } else {
                    everythingIncluded = false;
                    dirsNotIncluded.addElement(name);
                    if (fast && couldHoldIncluded(name)) {
                        scandir(file, name + File.separator, fast);
                    }
                }
                if (!fast) {
                    scandir(file, name + File.separator, fast);
                }
            } else if (file.isFile()) {
                if (isIncluded(name)) {
                    accountForIncludedFile(name, file);
                } else {
                    everythingIncluded = false;
                    filesNotIncluded.addElement(name);
                }
            }
        }
    
public voidsetBasedir(java.lang.String basedir)
Set the base directory to be scanned. This is the directory which is scanned recursively. All '/' and '\' characters are replaced by File.separatorChar, so the separator used need not match File.separatorChar.

param
basedir The base directory to scan.

        setBasedir(basedir == null ? (File) null
            : new File(basedir.replace('/", File.separatorChar).replace(
            '\\", File.separatorChar)));
    
public synchronized voidsetBasedir(java.io.File basedir)
Set the base directory to be scanned. This is the directory which is scanned recursively.

param
basedir The base directory for scanning.

        this.basedir = basedir;
    
public synchronized voidsetCaseSensitive(boolean isCaseSensitive)
Set whether or not include and exclude patterns are matched in a case sensitive way.

param
isCaseSensitive whether or not the file system should be regarded as a case sensitive one.

        this.isCaseSensitive = isCaseSensitive;
    
public synchronized voidsetExcludes(java.lang.String[] excludes)
Set the list of exclude patterns to use. All '/' and '\' characters are replaced by File.separatorChar, so the separator used need not match File.separatorChar.

When a pattern ends with a '/' or '\', "**" is appended.

param
excludes A list of exclude patterns. May be null, indicating that no files should be excluded. If a non-null list is given, all elements must be non-null.

        if (excludes == null) {
            this.excludes = null;
        } else {
            this.excludes = new String[excludes.length];
            for (int i = 0; i < excludes.length; i++) {
                this.excludes[i] = normalizePattern(excludes[i]);
            }
        }
    
public synchronized voidsetFollowSymlinks(boolean followSymlinks)
Set whether or not symbolic links should be followed.

param
followSymlinks whether or not symbolic links should be followed.

        this.followSymlinks = followSymlinks;
    
public synchronized voidsetIncludes(java.lang.String[] includes)
Set the list of include patterns to use. All '/' and '\' characters are replaced by File.separatorChar, so the separator used need not match File.separatorChar.

When a pattern ends with a '/' or '\', "**" is appended.

param
includes A list of include patterns. May be null, indicating that all files should be included. If a non-null list is given, all elements must be non-null.

        if (includes == null) {
            this.includes = null;
        } else {
            this.includes = new String[includes.length];
            for (int i = 0; i < includes.length; i++) {
                this.includes[i] = normalizePattern(includes[i]);
            }
        }
    
public synchronized voidsetSelectors(org.apache.tools.ant.types.selectors.FileSelector[] selectors)
Set the selectors that will select the filelist.

param
selectors specifies the selectors to be invoked on a scan.

        this.selectors = selectors;
    
protected voidslowScan()
Top level invocation for a slow scan. A slow scan builds up a full list of excluded/included files/directories, whereas a fast scan will only have full results for included files, as it ignores directories which can't possibly hold any included files/directories.

Returns immediately if a slow scan has already been completed.

        synchronized (slowScanLock) {
            if (haveSlowResults) {
                return;
            }
            if (slowScanning) {
                while (slowScanning) {
                    try {
                        slowScanLock.wait();
                    } catch (InterruptedException e) {
                        // Empty
                    }
                }
                return;
            }
            slowScanning = true;
        }
        try {
            synchronized (this) {

                // set in/excludes to reasonable defaults if needed:
                boolean nullIncludes = (includes == null);
                includes = nullIncludes ? new String[] {"**"} : includes;
                boolean nullExcludes = (excludes == null);
                excludes = nullExcludes ? new String[0] : excludes;

                String[] excl = new String[dirsExcluded.size()];
                dirsExcluded.copyInto(excl);

                String[] notIncl = new String[dirsNotIncluded.size()];
                dirsNotIncluded.copyInto(notIncl);

                processSlowScan(excl);
                processSlowScan(notIncl);
                clearCaches();
                includes = nullIncludes ? null : includes;
                excludes = nullExcludes ? null : excludes;
            }
        } finally {
            synchronized (slowScanLock) {
                haveSlowResults = true;
                slowScanning = false;
                slowScanLock.notifyAll();
            }
        }