diff --git a/src/main/org/apache/tools/ant/DirectoryScanner.java b/src/main/org/apache/tools/ant/DirectoryScanner.java
index d971cf1c0..009bd3ee9 100644
--- a/src/main/org/apache/tools/ant/DirectoryScanner.java
+++ b/src/main/org/apache/tools/ant/DirectoryScanner.java
@@ -145,30 +145,30 @@ public class DirectoryScanner
*/
protected static final String[] DEFAULTEXCLUDES = {
// Miscellaneous typical temporary files
- SelectorUtils.DEEP_ROOT_MATCH + "*~",
- SelectorUtils.DEEP_ROOT_MATCH + "#*#",
- SelectorUtils.DEEP_ROOT_MATCH + ".#*",
- SelectorUtils.DEEP_ROOT_MATCH + "%*%",
- SelectorUtils.DEEP_ROOT_MATCH + "._*",
+ SelectorUtils.DEEP_TREE_MATCH + "/*~",
+ SelectorUtils.DEEP_TREE_MATCH + "/#*#",
+ SelectorUtils.DEEP_TREE_MATCH + "/.#*",
+ SelectorUtils.DEEP_TREE_MATCH + "/%*%",
+ SelectorUtils.DEEP_TREE_MATCH + "/._*",
// CVS
- SelectorUtils.DEEP_ROOT_MATCH + "CVS",
- SelectorUtils.DEEP_ROOT_MATCH + "CVS" + SelectorUtils.DEEP_LEAVES_MATCH,
- SelectorUtils.DEEP_ROOT_MATCH + ".cvsignore",
+ SelectorUtils.DEEP_TREE_MATCH + "/CVS",
+ SelectorUtils.DEEP_TREE_MATCH + "/CVS/" + SelectorUtils.DEEP_TREE_MATCH,
+ SelectorUtils.DEEP_TREE_MATCH + "/.cvsignore",
// SCCS
- SelectorUtils.DEEP_ROOT_MATCH + "SCCS",
- SelectorUtils.DEEP_ROOT_MATCH + "SCCS" + SelectorUtils.DEEP_LEAVES_MATCH,
+ SelectorUtils.DEEP_TREE_MATCH + "/SCCS",
+ SelectorUtils.DEEP_TREE_MATCH + "/SCCS/" + SelectorUtils.DEEP_TREE_MATCH,
// Visual SourceSafe
- SelectorUtils.DEEP_ROOT_MATCH + "vssver.scc",
+ SelectorUtils.DEEP_TREE_MATCH + "/vssver.scc",
// Subversion
- SelectorUtils.DEEP_ROOT_MATCH + ".svn",
- SelectorUtils.DEEP_ROOT_MATCH + ".svn" + SelectorUtils.DEEP_LEAVES_MATCH,
+ SelectorUtils.DEEP_TREE_MATCH + "/.svn",
+ SelectorUtils.DEEP_TREE_MATCH + "/.svn/" + SelectorUtils.DEEP_TREE_MATCH,
// Mac
- SelectorUtils.DEEP_ROOT_MATCH + ".DS_Store"
+ SelectorUtils.DEEP_TREE_MATCH + "/.DS_Store"
};
/**
@@ -1295,10 +1295,13 @@ public class DirectoryScanner
* least one include pattern, or false
otherwise.
*/
protected boolean couldHoldIncluded(String name) {
+ final PathPattern tokenizedName = new PathPattern(name);
for (int i = 0; i < includes.length; i++) {
- if (matchPatternStart(includes[i], name, isCaseSensitive())
+ PathPattern tokenizedInclude = new PathPattern(includes[i]);
+ if (tokenizedName.matchPatternStartOf(tokenizedInclude,
+ isCaseSensitive())
&& isMorePowerfulThanExcludes(name, includes[i])
- && isDeeper(includes[i], name)) {
+ && isDeeper(tokenizedInclude, tokenizedName)) {
return true;
}
}
@@ -1313,13 +1316,9 @@ public class DirectoryScanner
* @return whether the pattern is deeper than the name.
* @since Ant 1.6.3
*/
- private boolean isDeeper(String pattern, String name) {
- Vector p = SelectorUtils.tokenizePath(pattern);
- if (!p.contains(SelectorUtils.DEEP_TREE_MATCH)) {
- Vector n = SelectorUtils.tokenizePath(name);
- return p.size() > n.size();
- }
- return true;
+ private boolean isDeeper(PathPattern pattern, PathPattern name) {
+ return pattern.containsPattern(SelectorUtils.DEEP_TREE_MATCH)
+ || pattern.depth() > name.depth();
}
/**
@@ -1341,7 +1340,8 @@ public class DirectoryScanner
*/
private boolean isMorePowerfulThanExcludes(String name,
String includepattern) {
- String soughtexclude = name + SelectorUtils.DEEP_LEAVES_MATCH;
+ final String soughtexclude =
+ name + File.separatorChar + SelectorUtils.DEEP_TREE_MATCH;
for (int counter = 0; counter < excludes.length; counter++) {
if (excludes[counter].equals(soughtexclude)) {
return false;
diff --git a/src/main/org/apache/tools/ant/types/selectors/PathPattern.java b/src/main/org/apache/tools/ant/types/selectors/PathPattern.java
index ae031c9f8..aa2e28fe7 100644
--- a/src/main/org/apache/tools/ant/types/selectors/PathPattern.java
+++ b/src/main/org/apache/tools/ant/types/selectors/PathPattern.java
@@ -69,6 +69,16 @@ public class PathPattern {
return SelectorUtils.matchPath(tokenizedPattern, str, isCaseSensitive);
}
+ /**
+ * Tests whether or not this PathPattern matches the start of
+ * another pattern.
+ */
+ public boolean matchPatternStartOf(PathPattern other,
+ boolean caseSensitive) {
+ return SelectorUtils.matchPatternStart(other.tokenizedPattern,
+ tokenizedPattern, caseSensitive);
+ }
+
/**
* @return The pattern String
*/
@@ -79,4 +89,23 @@ public class PathPattern {
public String getPattern() {
return pattern;
}
+
+ /**
+ * The depth (or length) of a pattern.
+ */
+ public int depth() {
+ return tokenizedPattern.length;
+ }
+
+ /**
+ * Does the tokenized pattern contain the given string?
+ */
+ public boolean containsPattern(String pat) {
+ for (int i = 0; i < tokenizedPattern.length; i++) {
+ if (tokenizedPattern[i].equals(pat)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
index a40f49d24..7a6da092a 100644
--- a/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
+++ b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
@@ -44,20 +44,6 @@ public final class SelectorUtils {
*/
public static final String DEEP_TREE_MATCH = "**";
- /**
- * The pattern that matches an arbitrary number of directories at
- * the leaves.
- * @since Ant 1.8.0
- */
- public static final String DEEP_LEAVES_MATCH = File.separatorChar + "**";
-
- /**
- * The pattern that matches an arbitrary number of directories at
- * the root.
- * @since Ant 1.8.0
- */
- public static final String DEEP_ROOT_MATCH = "**" + File.separatorChar;
-
private static final SelectorUtils instance = new SelectorUtils();
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
@@ -126,7 +112,30 @@ public final class SelectorUtils {
String[] patDirs = tokenizePathAsArray(pattern);
String[] strDirs = tokenizePathAsArray(str);
+ return matchPatternStart(patDirs, strDirs, isCaseSensitive);
+ }
+
+ /**
+ * Tests 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 patDirs The tokenized pattern to match against. Must not be
+ * null
.
+ * @param strDirs The tokenized path to match. 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 "**".
+ */
+ static boolean matchPatternStart(String[] patDirs, String[] strDirs,
+ boolean isCaseSensitive) {
int patIdxStart = 0;
int patIdxEnd = patDirs.length - 1;
int strIdxStart = 0;