summaryrefslogtreecommitdiff
path: root/src/main/org/apache/tools/ant
diff options
context:
space:
mode:
authorMagesh Umasankar <umagesh@apache.org>2002-04-30 22:38:36 +0000
committerMagesh Umasankar <umagesh@apache.org>2002-04-30 22:38:36 +0000
commitf61c1bcd3a4a540bac7ae97559f37c49bfee75d8 (patch)
treee2101b9f4ce2d6bf0463ac829b38653d5ca9a427 /src/main/org/apache/tools/ant
parented1abbaa01fd034c3d4d9a61f8a2bfc268ea74e6 (diff)
downloadant-f61c1bcd3a4a540bac7ae97559f37c49bfee75d8.tar.gz
Selectors feature to specify sophisticated selection criteria to create filesets.
Got it in in the 11(and a half)th hour ;-) Submitted by: Bruce Atherton <bruce@callenish.com> Docs and testcases to follow in the next few days. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272630 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/main/org/apache/tools/ant')
-rw-r--r--src/main/org/apache/tools/ant/DirectoryScanner.java656
-rw-r--r--src/main/org/apache/tools/ant/types/AbstractFileSet.java204
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/AndSelector.java111
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java121
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/BaseSelector.java143
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java312
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java197
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/DateSelector.java250
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/DependSelector.java186
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/DepthSelector.java209
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java78
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java213
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/FileSelector.java85
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java195
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java135
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/NoneSelector.java112
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/NotSelector.java99
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/OrSelector.java112
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/PresentSelector.java208
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java178
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java86
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java564
-rw-r--r--src/main/org/apache/tools/ant/types/selectors/SizeSelector.java313
23 files changed, 4324 insertions, 443 deletions
diff --git a/src/main/org/apache/tools/ant/DirectoryScanner.java b/src/main/org/apache/tools/ant/DirectoryScanner.java
index d06c5081a..12b46560e 100644
--- a/src/main/org/apache/tools/ant/DirectoryScanner.java
+++ b/src/main/org/apache/tools/ant/DirectoryScanner.java
@@ -58,29 +58,37 @@ import java.io.File;
import java.util.Vector;
import java.util.StringTokenizer;
+import org.apache.tools.ant.types.selectors.SelectorScanner;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+
/**
* Class for scanning a directory for files/directories which match certain
* criteria.
* <p>
- * 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.
+ * 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.
* <p>
* 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 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, and don't match any pattern of the
- * exclude pattern list will be placed in the list of files/directories found.
+ * 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.
* <p>
* 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.
+ * supplied, an empty list is used, such that nothing will be excluded. When
+ * no selectors are supplied, none are applied.
* <p>
- * The pattern matching is done as follows:
+ * 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
* <code>File.separator</code> ('/' under UNIX, '\' under Windows).
- * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
+ * 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.
* <p>
@@ -136,11 +144,12 @@ import java.util.StringTokenizer;
* This will scan a directory called test for .class files, but excludes all
* files in all proper subdirectories of a directory called "modules"
*
- * @author Arnout J. Kuiper
+ * @author Arnout J. Kuiper
* <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a>
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
*/
-public class DirectoryScanner implements FileScanner {
+public class DirectoryScanner implements FileScanner, SelectorScanner {
/**
* Patterns which should be excluded by default.
@@ -170,36 +179,53 @@ public class DirectoryScanner implements FileScanner {
/** The patterns for the files to be excluded. */
protected String[] excludes;
- /** The files which matched at least one include and no excludes. */
+ /** Selectors that will filter which files are in our candidate list. */
+ protected FileSelector[] selectors = null;
+
+ /** The files which matched at least one include and no excludes
+ * and were selected.
+ */
protected Vector filesIncluded;
- /** The files which did not match any includes. */
+ /** The files which did not match any includes or selectors. */
protected Vector filesNotIncluded;
- /**
- * The files which matched at least one include and at least
+ /**
+ * The files which matched at least one include and at least
* one exclude.
*/
protected Vector filesExcluded;
- /** The directories which matched at least one include and no excludes. */
+ /** The directories which matched at least one include and no excludes
+ * and were selected.
+ */
protected Vector dirsIncluded;
/** The directories which were found and did not match any includes. */
protected Vector dirsNotIncluded;
- /**
- * The directories which matched at least one include and at least one
+ /**
+ * The directories which matched at least one include and at least one
* exclude.
*/
protected Vector dirsExcluded;
+ /** The files which matched at least one include and no excludes and
+ * which a selector discarded.
+ */
+ protected Vector filesDeselected;
+
+ /** The directories which matched at least one include and no excludes
+ * but which a selector discarded.
+ */
+ protected Vector dirsDeselected;
+
/** Whether or not our results were built by a slow scan. */
protected boolean haveSlowResults = false;
- /**
- * Whether or not the file system should be treated as a case sensitive
- * one.
+ /**
+ * Whether or not the file system should be treated as a case sensitive
+ * one.
*/
protected boolean isCaseSensitive = true;
@@ -213,241 +239,87 @@ public class DirectoryScanner implements FileScanner {
}
/**
- * Tests whether or not a given path matches the start of a given
+ * Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
* <p>
* This is not a general purpose test and should only be used if you
- * can live with false positives. For example, <code>pattern=**\a</code>
+ * can live with false positives. For example, <code>pattern=**\a</code>
* and <code>str=b</code> will yield <code>true</code>.
*
- * @param pattern The pattern to match against. Must not be
+ * @param pattern The pattern to match against. Must not be
* <code>null</code>.
- * @param str The path to match, as a String. Must not be
+ * @param str The path to match, as a String. Must not be
* <code>null</code>.
- *
- * @return whether or not a given path matches the start of a given
+ *
+ * @return whether or not a given path matches the start of a given
* pattern up to the first "**".
*/
protected static boolean matchPatternStart(String pattern, String str) {
- return matchPatternStart(pattern, str, true);
+ return SelectorUtils.matchPatternStart(pattern, str);
}
/**
- * Tests whether or not a given path matches the start of a given
+ * Tests whether or not a given path matches the start of a given
* pattern up to the first "**".
* <p>
* This is not a general purpose test and should only be used if you
- * can live with false positives. For example, <code>pattern=**\a</code>
+ * can live with false positives. For example, <code>pattern=**\a</code>
* and <code>str=b</code> will yield <code>true</code>.
*
- * @param pattern The pattern to match against. Must not be
+ * @param pattern The pattern to match against. Must not be
* <code>null</code>.
- * @param str The path to match, as a String. Must not be
+ * @param str The path to match, as a String. Must not be
* <code>null</code>.
- * @param isCaseSensitive Whether or not matching should be performed
+ * @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
- *
- * @return whether or not a given path matches the start of a given
+ *
+ * @return whether or not a given path matches the start of a given
* pattern up to the first "**".
*/
protected static boolean matchPatternStart(String pattern, String str,
boolean isCaseSensitive) {
- // When str starts with a File.separator, pattern has to start with a
- // File.separator.
- // When pattern starts with a File.separator, str has to start with a
- // File.separator.
- if (str.startsWith(File.separator) !=
- pattern.startsWith(File.separator)) {
- return false;
- }
-
- Vector patDirs = tokenizePath (pattern);
- Vector strDirs = tokenizePath (str);
-
- int patIdxStart = 0;
- int patIdxEnd = patDirs.size() - 1;
- int strIdxStart = 0;
- int strIdxEnd = strDirs.size() - 1;
-
- // up to first '**'
- while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
- String patDir = (String) patDirs.elementAt(patIdxStart);
- if (patDir.equals("**")) {
- break;
- }
- if (!match(patDir, (String) strDirs.elementAt(strIdxStart), isCaseSensitive)) {
- return false;
- }
- patIdxStart++;
- strIdxStart++;
- }
-
- if (strIdxStart > strIdxEnd) {
- // String is exhausted
- return true;
- } else if (patIdxStart > patIdxEnd) {
- // String not exhausted, but pattern is. Failure.
- return false;
- } else {
- // pattern now holds ** while string is not exhausted
- // this will generate false positives but we can live with that.
- return true;
- }
+ return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
}
/**
* Tests whether or not a given path matches a given pattern.
*
- * @param pattern The pattern to match against. Must not be
+ * @param pattern The pattern to match against. Must not be
* <code>null</code>.
- * @param str The path to match, as a String. Must not be
+ * @param str The path to match, as a String. Must not be
* <code>null</code>.
*
- * @return <code>true</code> if the pattern matches against the string,
+ * @return <code>true</code> if the pattern matches against the string,
* or <code>false</code> otherwise.
*/
protected static boolean matchPath(String pattern, String str) {
- return matchPath(pattern, str, true);
+ return SelectorUtils.matchPath(pattern, str);
}
/**
* Tests whether or not a given path matches a given pattern.
*
- * @param pattern The pattern to match against. Must not be
+ * @param pattern The pattern to match against. Must not be
* <code>null</code>.
- * @param str The path to match, as a String. Must not be
+ * @param str The path to match, as a String. Must not be
* <code>null</code>.
- * @param isCaseSensitive Whether or not matching should be performed
+ * @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
*
- * @return <code>true</code> if the pattern matches against the string,
+ * @return <code>true</code> if the pattern matches against the string,
* or <code>false</code> otherwise.
*/
- protected static boolean matchPath(String pattern, String str,
+ protected static boolean matchPath(String pattern, String str,
boolean isCaseSensitive) {
- // When str starts with a File.separator, pattern has to start with a
- // File.separator.
- // When pattern starts with a File.separator, str has to start with a
- // File.separator.
- if (str.startsWith(File.separator) !=
- pattern.startsWith(File.separator)) {
- return false;
- }
-
- Vector patDirs = tokenizePath (pattern);
- Vector strDirs = tokenizePath (str);
-
- int patIdxStart = 0;
- int patIdxEnd = patDirs.size() - 1;
- int strIdxStart = 0;
- int strIdxEnd = strDirs.size() - 1;
-
- // up to first '**'
- while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
- String patDir = (String) patDirs.elementAt(patIdxStart);
- if (patDir.equals("**")) {
- break;
- }
- if (!match(patDir, (String) strDirs.elementAt(strIdxStart), isCaseSensitive)) {
- return false;
- }
- patIdxStart++;
- strIdxStart++;
- }
- if (strIdxStart > strIdxEnd) {
- // String is exhausted
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!patDirs.elementAt(i).equals("**")) {
- return false;
- }
- }
- return true;
- } else {
- if (patIdxStart > patIdxEnd) {
- // String not exhausted, but pattern is. Failure.
- return false;
- }
- }
-
- // up to last '**'
- while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
- String patDir = (String) patDirs.elementAt(patIdxEnd);
- if (patDir.equals("**")) {
- break;
- }
- if (!match(patDir, (String) strDirs.elementAt(strIdxEnd), isCaseSensitive)) {
- return false;
- }
- patIdxEnd--;
- strIdxEnd--;
- }
- if (strIdxStart > strIdxEnd) {
- // String is exhausted
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!patDirs.elementAt(i).equals("**")) {
- return false;
- }
- }
- return true;
- }
-
- while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
- int patIdxTmp = -1;
- for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
- if (patDirs.elementAt(i).equals("**")) {
- patIdxTmp = i;
- break;
- }
- }
- if (patIdxTmp == patIdxStart + 1) {
- // '**/**' situation, so skip one
- patIdxStart++;
- continue;
- }
- // Find the pattern between padIdxStart & padIdxTmp in str between
- // strIdxStart & strIdxEnd
- int patLength = (patIdxTmp - patIdxStart - 1);
- int strLength = (strIdxEnd - strIdxStart + 1);
- int foundIdx = -1;
-strLoop:
- for (int i = 0; i <= strLength - patLength; i++) {
- for (int j = 0; j < patLength; j++) {
- String subPat
- = (String) patDirs.elementAt(patIdxStart + j + 1);
- String subStr
- = (String) strDirs.elementAt(strIdxStart + i + j);
- if (!match(subPat, subStr, isCaseSensitive)) {
- continue strLoop;
- }
- }
-
- foundIdx = strIdxStart + i;
- break;
- }
-
- if (foundIdx == -1) {
- return false;
- }
-
- patIdxStart = patIdxTmp;
- strIdxStart = foundIdx + patLength;
- }
-
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!patDirs.elementAt(i).equals("**")) {
- return false;
- }
- }
-
- return true;
+ return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
}
/**
- * Tests whether or not a string matches against a pattern.
+ * Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:<br>
* '*' means zero or more characters<br>
* '?' means one and only one character
- *
- * @param pattern The pattern to match against.
+ *
+ * @param pattern The pattern to match against.
* Must not be <code>null</code>.
* @param str The string which must be matched against the pattern.
* Must not be <code>null</code>.
@@ -456,211 +328,62 @@ strLoop:
* or <code>false</code> otherwise.
*/
public static boolean match(String pattern, String str) {
- return match(pattern, str, true);
+ return SelectorUtils.match(pattern, str);
}
/**
- * Tests whether or not a string matches against a pattern.
+ * Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:<br>
* '*' means zero or more characters<br>
* '?' means one and only one character
- *
- * @param pattern The pattern to match against.
+ *
+ * @param pattern The pattern to match against.
* Must not be <code>null</code>.
* @param str The string which must be matched against the pattern.
* Must not be <code>null</code>.
- * @param isCaseSensitive Whether or not matching should be performed
+ * @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
*
*
- * @return <code>true</code> if the string matches against the pattern,
+ * @return <code>true</code> if the string matches against the pattern,
* or <code>false</code> otherwise.
*/
- protected static boolean match(String pattern, String str,
+ protected static boolean match(String pattern, String str,
boolean isCaseSensitive) {
- char[] patArr = pattern.toCharArray();
- char[] strArr = str.toCharArray();
- int patIdxStart = 0;
- int patIdxEnd = patArr.length - 1;
- int strIdxStart = 0;
- int strIdxEnd = strArr.length - 1;
- char ch;
-
- boolean containsStar = false;
- for (int i = 0; i < patArr.length; i++) {
- if (patArr[i] == '*') {
- containsStar = true;
- break;
- }
- }
-
- if (!containsStar) {
- // No '*'s, so we make a shortcut
- if (patIdxEnd != strIdxEnd) {
- return false; // Pattern and string do not have the same size
- }
- for (int i = 0; i <= patIdxEnd; i++) {
- ch = patArr[i];
- if (ch != '?') {
- if (isCaseSensitive && ch != strArr[i]) {
- return false;// Character mismatch
- }
- if (!isCaseSensitive && Character.toUpperCase(ch) !=
- Character.toUpperCase(strArr[i])) {
- return false; // Character mismatch
- }
- }
- }
- return true; // String matches against pattern
- }
-
- if (patIdxEnd == 0) {
- return true; // Pattern contains only '*', which matches anything
- }
-
- // Process characters before first star
- while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
- if (ch != '?') {
- if (isCaseSensitive && ch != strArr[strIdxStart]) {
- return false;// Character mismatch
- }
- if (!isCaseSensitive && Character.toUpperCase(ch) !=
- Character.toUpperCase(strArr[strIdxStart])) {
- return false;// Character mismatch
- }
- }
- patIdxStart++;
- strIdxStart++;
- }
- if (strIdxStart > strIdxEnd) {
- // All characters in the string are used. Check if only '*'s are
- // left in the pattern. If so, we succeeded. Otherwise failure.
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (patArr[i] != '*') {
- return false;
- }
- }
- return true;
- }
-
- // Process characters after last star
- while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
- if (ch != '?') {
- if (isCaseSensitive && ch != strArr[strIdxEnd]) {
- return false;// Character mismatch
- }
- if (!isCaseSensitive && Character.toUpperCase(ch) !=
- Character.toUpperCase(strArr[strIdxEnd])) {
- return false;// Character mismatch
- }
- }
- patIdxEnd--;
- strIdxEnd--;
- }
- if (strIdxStart > strIdxEnd) {
- // All characters in the string are used. Check if only '*'s are
- // left in the pattern. If so, we succeeded. Otherwise failure.
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (patArr[i] != '*') {
- return false;
- }
- }
- return true;
- }
-
- // process pattern between stars. padIdxStart and patIdxEnd point
- // always to a '*'.
- while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
- int patIdxTmp = -1;
- for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
- if (patArr[i] == '*') {
- patIdxTmp = i;
- break;
- }
- }
- if (patIdxTmp == patIdxStart + 1) {
- // Two stars next to each other, skip the first one.
- patIdxStart++;
- continue;
- }
- // Find the pattern between padIdxStart & padIdxTmp in str between
- // strIdxStart & strIdxEnd
- int patLength = (patIdxTmp - patIdxStart - 1);
- int strLength = (strIdxEnd - strIdxStart + 1);
- int foundIdx = -1;
- strLoop:
- for (int i = 0; i <= strLength - patLength; i++) {
- for (int j = 0; j < patLength; j++) {
- ch = patArr[patIdxStart + j + 1];
- if (ch != '?') {
- if (isCaseSensitive
- && ch != strArr[strIdxStart + i + j]) {
- continue strLoop;
- }
- if (!isCaseSensitive && Character.toUpperCase(ch) !=
- Character.toUpperCase(strArr[strIdxStart + i + j])) {
- continue strLoop;
- }
- }
- }
-
- foundIdx = strIdxStart + i;
- break;
- }
-
- if (foundIdx == -1) {
- return false;
- }
-
- patIdxStart = patIdxTmp;
- strIdxStart = foundIdx + patLength;
- }
-
- // All characters in the string are used. Check if only '*'s are left
- // in the pattern. If so, we succeeded. Otherwise failure.
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (patArr[i] != '*') {
- return false;
- }
- }
- return true;
+ return SelectorUtils.match(pattern, str, isCaseSensitive);
}
/**
* Breaks a path up into a Vector of path elements, tokenizing on
* <code>File.separator</code>.
- *
+ *
* @param path Path to tokenize. Must not be <code>null</code>.
- *
+ *
* @return a Vector of path elements from the tokenized path
*/
private static Vector tokenizePath (String path) {
- Vector ret = new Vector();
- StringTokenizer st = new StringTokenizer(path, File.separator);
- while (st.hasMoreTokens()) {
- ret.addElement(st.nextToken());
- }
- return ret;
+ return SelectorUtils.tokenizePath(path);
}
-
+
/**
* Sets the base directory to be scanned. This is the directory which is
* scanned recursively. All '/' and '\' characters are replaced by
* <code>File.separatorChar</code>, so the separator used need not match
* <code>File.separatorChar</code>.
*
- * @param basedir The base directory to scan.
+ * @param basedir The base directory to scan.
* Must not be <code>null</code>.
*/
public void setBasedir(String basedir) {
- setBasedir(new File(basedir.replace('/', File.separatorChar).replace('\\', File.separatorChar)));
+ setBasedir(new File(basedir.replace('/', File.separatorChar).replace(
+ '\\', File.separatorChar)));
}
/**
- * Sets the base directory to be scanned. This is the directory which is
+ * Sets the base directory to be scanned. This is the directory which is
* scanned recursively.
*
- * @param basedir The base directory for scanning.
+ * @param basedir The base directory for scanning.
* Should not be <code>null</code>.
*/
public void setBasedir(File basedir) {
@@ -668,7 +391,7 @@ strLoop:
}
/**
- * Returns the base directory to be scanned.
+ * Returns the base directory to be scanned.
* This is the directory which is scanned recursively.
*
* @return the base directory to be scanned
@@ -680,7 +403,7 @@ strLoop:
/**
* Sets whether or not the file system should be regarded as case sensitive.
*
- * @param isCaseSensitive whether or not the file system should be
+ * @param isCaseSensitive whether or not the file system should be
* regarded as a case sensitive one
*/
public void setCaseSensitive(boolean isCaseSensitive) {
@@ -688,16 +411,16 @@ strLoop:
}
/**
- * Sets the list of include patterns to use. All '/' and '\' characters
- * are replaced by <code>File.separatorChar</code>, so the separator used
+ * Sets the list of include patterns to use. All '/' and '\' characters
+ * are replaced by <code>File.separatorChar</code>, so the separator used
* need not match <code>File.separatorChar</code>.
* <p>
* When a pattern ends with a '/' or '\', "**" is appended.
*
* @param includes A list of include patterns.
- * May be <code>null</code>, indicating that all files
+ * May be <code>null</code>, indicating that all files
* should be included. If a non-<code>null</code>
- * list is given, all elements must be
+ * list is given, all elements must be
* non-<code>null</code>.
*/
public void setIncludes(String[] includes) {
@@ -707,7 +430,8 @@ strLoop:
this.includes = new String[includes.length];
for (int i = 0; i < includes.length; i++) {
String pattern;
- pattern = includes[i].replace('/', File.separatorChar).replace('\\', File.separatorChar);
+ pattern = includes[i].replace('/', File.separatorChar).replace(
+ '\\', File.separatorChar);
if (pattern.endsWith(File.separator)) {
pattern += "**";
}
@@ -716,16 +440,17 @@ strLoop:
}
}
+
/**
- * Sets the list of exclude patterns to use. All '/' and '\' characters
- * are replaced by <code>File.separatorChar</code>, so the separator used
+ * Sets the list 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>.
* <p>
* When a pattern ends with a '/' or '\', "**" is appended.
*
- * @param excludes A list of exclude patterns.
- * May be <code>null</code>, indicating that no files
- * should be excluded. If a non-<code>null</code> list is
+ * @param excludes A list of exclude patterns.
+ * May be <code>null</code>, indicating that no files
+ * should be excluded. If a non-<code>null</code> list is
* given, all elements must be non-<code>null</code>.
*/
public void setExcludes(String[] excludes) {
@@ -735,7 +460,8 @@ strLoop:
this.excludes = new String[excludes.length];
for (int i = 0; i < excludes.length; i++) {
String pattern;
- pattern = excludes[i].replace('/', File.separatorChar).replace('\\', File.separatorChar);
+ pattern = excludes[i].replace('/', File.separatorChar).replace(
+ '\\', File.separatorChar);
if (pattern.endsWith(File.separator)) {
pattern += "**";
}
@@ -744,11 +470,22 @@ strLoop:
}
}
+
+ /**
+ * Sets the selectors that will select the filelist.
+ *
+ * @param selectors specifies the selectors to be invoked on a scan
+ */
+ public void setSelectors(FileSelector[] 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
+ * @return <code>true</code> if all files and directories which have
* been found so far have been included.
*/
public boolean isEverythingIncluded() {
@@ -757,9 +494,10 @@ strLoop:
/**
* Scans the base directory for files which match at least one include
- * pattern and don't match any exclude patterns.
+ * pattern and don't match any exclude patterns. If there are selectors
+ * then the files must pass muster there, as well.
*
- * @exception IllegalStateException if the base directory was set
+ * @exception IllegalStateException if the base directory was set
* incorrectly (i.e. if it is <code>null</code>, doesn't exist,
* or isn't a directory).
*/
@@ -788,13 +526,19 @@ strLoop:
filesIncluded = new Vector();
filesNotIncluded = new Vector();
filesExcluded = new Vector();
+ filesDeselected = new Vector();
dirsIncluded = new Vector();
dirsNotIncluded = new Vector();
dirsExcluded = new Vector();
+ dirsDeselected = new Vector();
if (isIncluded("")) {
if (!isExcluded("")) {
- dirsIncluded.addElement("");
+ if (isSelected("",basedir)) {
+ dirsIncluded.addElement("");
+ } else {
+ dirsDeselected.addElement("");
+ }
} else {
dirsExcluded.addElement("");
}
@@ -806,8 +550,8 @@ strLoop:
/**
* 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
+ * 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.
* <p>
* Returns immediately if a slow scan has already been completed.
@@ -843,12 +587,12 @@ strLoop:
/**
* Scans the given directory 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.
+ * 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 <code>null</code>.
- * @param vpath The path relative to the base directory (needed to
- * prevent problems with an absolute path when using
+ * @param vpath The path relative to the base directory (needed to
+ * prevent problems with an absolute path when using
* dir). Must not be <code>null</code>.
* @param fast Whether or not this call is part of a fast scan.
*
@@ -881,10 +625,19 @@ strLoop:
if (file.isDirectory()) {
if (isIncluded(name)) {
if (!isExcluded(name)) {
- dirsIncluded.addElement(name);
- if (fast) {
- scandir(file, name + File.separator, fast);
+ if (isSelected(name,file)) {
+ dirsIncluded.addElement(name);
+ if (fast) {
+ scandir(file, name + File.separator, fast);
+ }
+ } else {
+ everythingIncluded = false;
+ dirsDeselected.addElement(name);
+ if (fast && couldHoldIncluded(name)) {
+ scandir(file, name + File.separator, fast);
+ }
}
+
} else {
everythingIncluded = false;
dirsExcluded.addElement(name);
@@ -905,7 +658,12 @@ strLoop:
} else if (file.isFile()) {
if (isIncluded(name)) {
if (!isExcluded(name)) {
- filesIncluded.addElement(name);
+ if (isSelected(name,file)) {
+ filesIncluded.addElement(name);
+ } else {
+ everythingIncluded = false;
+ filesDeselected.addElement(name);
+ }
} else {
everythingIncluded = false;
filesExcluded.addElement(name);
@@ -919,7 +677,7 @@ strLoop:
}
/**
- * Tests whether or not a name matches against at least one include
+ * Tests whether or not a name matches against at least one include
* pattern.
*
* @param name The name to match. Must not be <code>null</code>.
@@ -936,11 +694,11 @@ strLoop:
}
/**
- * Tests whether or not a name matches the start of at least one include
+ * Tests whether or not a name matches the start of at least one include
* pattern.
*
* @param name The name to match. Must not be <code>null</code>.
- * @return <code>true</code> when the name matches against the start of at
+ * @return <code>true</code> when the name matches against the start of at
* least one include pattern, or <code>false</code> otherwise.
*/
protected boolean couldHoldIncluded(String name) {
@@ -953,7 +711,7 @@ strLoop:
}
/**
- * Tests whether or not a name matches against at least one exclude
+ * Tests whether or not a name matches against at least one exclude
* pattern.
*
* @param name The name to match. Must not be <code>null</code>.
@@ -970,7 +728,26 @@ strLoop:
}
/**
- * Returns the names of the files which matched at least one of the
+ * Tests whether a name should be selected.
+ *
+ * @param name the filename to check for selecting
+ * @param file the java.io.File object for this filename
+ * @return <code>false</code> when the selectors says that the file
+ * should not be selected, <code>true</code> otherwise.
+ */
+ protected boolean isSelected(String name, File file) {
+ if (selectors != null) {
+ for (int i = 0; i < selectors.length; i++) {
+ if ((selectors[i].isSelected(basedir, name, file)) == false) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns 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.
*
@@ -981,19 +758,19 @@ strLoop:
int count = filesIncluded.size();
String[] files = new String[count];
for (int i = 0; i < count; i++) {
- files[i] = (String) filesIncluded.elementAt(i);
+ files[i] = (String)filesIncluded.elementAt(i);
}
return files;
}
/**
- * Returns the names of the files which matched none of the include
+ * Returns 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
+ * @return the names of the files which matched none of the include
* patterns.
- *
+ *
* @see #slowScan
*/
public String[] getNotIncludedFiles() {
@@ -1001,20 +778,20 @@ strLoop:
int count = filesNotIncluded.size();
String[] files = new String[count];
for (int i = 0; i < count; i++) {
- files[i] = (String) filesNotIncluded.elementAt(i);
+ files[i] = (String)filesNotIncluded.elementAt(i);
}
return files;
}
/**
- * Returns the names of the files which matched at least one of the
+ * Returns 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
+ * @return the names of the files which matched at least one of the
* include patterns and at at least one of the exclude patterns.
- *
+ *
* @see #slowScan
*/
public String[] getExcludedFiles() {
@@ -1022,13 +799,32 @@ strLoop:
int count = filesExcluded.size();
String[] files = new String[count];
for (int i = 0; i < count; i++) {
- files[i] = (String) filesExcluded.elementAt(i);
+ files[i] = (String)filesExcluded.elementAt(i);
+ }
+ return files;
+ }
+
+ /**
+ * Returns the names of the files which were selected. 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 selected.
+ *
+ * @see #slowScan
+ */
+ public String[] getDeselectedFiles() {
+ slowScan();
+ int count = filesDeselected.size();
+ String[] files = new String[count];
+ for (int i = 0; i < count; i++) {
+ files[i] = (String)filesDeselected.elementAt(i);
}
return files;
}
/**
- * Returns the names of the directories which matched at least one of the
+ * Returns 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.
*
@@ -1039,7 +835,7 @@ strLoop:
int count = dirsIncluded.size();
String[] directories = new String[count];
for (int i = 0; i < count; i++) {
- directories[i] = (String) dirsIncluded.elementAt(i);
+ directories[i] = (String)dirsIncluded.elementAt(i);
}
return directories;
}
@@ -1051,7 +847,7 @@ strLoop:
*
* @return the names of the directories which matched none of the include
* patterns.
- *
+ *
* @see #slowScan
*/
public String[] getNotIncludedDirectories() {
@@ -1059,20 +855,20 @@ strLoop:
int count = dirsNotIncluded.size();
String[] directories = new String[count];
for (int i = 0; i < count; i++) {
- directories[i] = (String) dirsNotIncluded.elementAt(i);
+ directories[i] = (String)dirsNotIncluded.elementAt(i);
}
return directories;
}
/**
- * Returns the names of the directories which matched at least one of the
+ * Returns 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
+ *
+ * @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
*/
public String[] getExcludedDirectories() {
@@ -1080,7 +876,26 @@ strLoop:
int count = dirsExcluded.size();
String[] directories = new String[count];
for (int i = 0; i < count; i++) {
- directories[i] = (String) dirsExcluded.elementAt(i);
+ directories[i] = (String)dirsExcluded.elementAt(i);
+ }
+ return directories;
+ }
+
+ /**
+ * Returns the names of the directories which were selected. 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 selected.
+ *
+ * @see #slowScan
+ */
+ public String[] getDeselectedDirectories() {
+ slowScan();
+ int count = dirsDeselected.size();
+ String[] directories = new String[count];
+ for (int i = 0; i < count; i++) {
+ directories[i] = (String)dirsDeselected.elementAt(i);
}
return directories;
}
@@ -1096,7 +911,8 @@ strLoop:
System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
}
for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
- newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace('/', File.separatorChar).replace('\\', File.separatorChar);
+ newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace('/',
+ File.separatorChar).replace('\\', File.separatorChar);
}
excludes = newExcludes;
}
diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java
index 6e457d056..00b4a4bb6 100644
--- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java
+++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java
@@ -57,6 +57,7 @@ import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.FileScanner;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.selectors.*;
import java.io.File;
import java.util.Stack;
@@ -70,23 +71,26 @@ import java.util.Enumeration;
*
* <p>Common base class for DirSet and FileSet.</p>
*
- * @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a>
+ * @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
* @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a>
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
*/
-public abstract class AbstractFileSet extends DataType implements Cloneable {
-
+public abstract class AbstractFileSet extends DataType implements Cloneable,
+ SelectorContainer {
+
private PatternSet defaultPatterns = new PatternSet();
private Vector additionalPatterns = new Vector();
+ private Vector selectors = new Vector();
private File dir;
private boolean useDefaultExcludes = true;
private boolean isCaseSensitive = true;
-
+
public AbstractFileSet() {
super();
}
@@ -104,7 +108,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
* Makes this instance in effect a reference to another instance.
*
* <p>You must not set another attribute or nest elements inside
- * this element if you make it a reference.</p>
+ * this element if you make it a reference.</p>
*/
public void setRefid(Reference r) throws BuildException {
if (dir != null || defaultPatterns.hasPatterns()) {
@@ -158,7 +162,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
}
return defaultPatterns.createInclude();
}
-
+
/**
* add a name entry on the include files list
*/
@@ -168,7 +172,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
}
return defaultPatterns.createIncludesFile();
}
-
+
/**
* add a name entry on the exclude list
*/
@@ -188,7 +192,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
}
return defaultPatterns.createExcludesFile();
}
-
+
/**
* Appends <code>includes</code> to the current list of include
* patterns.
@@ -224,7 +228,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
/**
* Sets the name of the file containing the includes patterns.
*
- * @param incl The file to fetch the include patterns from.
+ * @param incl The file to fetch the include patterns from.
*/
public void setIncludesfile(File incl) throws BuildException {
if (isReference()) {
@@ -237,7 +241,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
/**
* Sets the name of the file containing the includes patterns.
*
- * @param excl The file to fetch the exclude patterns from.
+ * @param excl The file to fetch the exclude patterns from.
*/
public void setExcludesfile(File excl) throws BuildException {
if (isReference()) {
@@ -250,7 +254,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
/**
* Sets whether default exclusions should be used or not.
*
- * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+ * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
* should be used, "false"|"off"|"no" when they
* shouldn't be used.
*/
@@ -272,8 +276,8 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
this.isCaseSensitive = isCaseSensitive;
}
-
-
+
+
/**
* sets the name used for this datatype instance.
*/
@@ -290,14 +294,14 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
}
}
}
-
+
String classname = getClass().getName();
-
+
int dotIndex = classname.lastIndexOf(".");
if (dotIndex == -1) {
return classname;
}
- return classname.substring(dotIndex + 1);
+ return classname.substring(dotIndex + 1);
}
/**
@@ -326,12 +330,12 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
ds.scan();
return ds;
}
-
+
public void setupDirectoryScanner(FileScanner ds, Project p) {
if (ds == null) {
throw new IllegalArgumentException("ds cannot be null");
}
-
+
ds.setBasedir(dir);
final int count = additionalPatterns.size();
@@ -340,11 +344,16 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
defaultPatterns.append((PatternSet) o, p);
}
- p.log(getDataTypeName() + ": Setup scanner in dir " + dir +
+ p.log(getDataTypeName() + ": Setup scanner in dir " + dir +
" with " + defaultPatterns, Project.MSG_DEBUG);
-
+
ds.setIncludes(defaultPatterns.getIncludePatterns(p));
ds.setExcludes(defaultPatterns.getExcludePatterns(p));
+ if (ds instanceof SelectorScanner) {
+ SelectorScanner ss = (SelectorScanner)ds;
+ ss.setSelectors(getSelectors(p));
+ }
+
if (useDefaultExcludes) {
ds.addDefaultExcludes();
}
@@ -353,7 +362,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
/**
* Performs the check for circular references and returns the
- * referenced FileSet.
+ * referenced FileSet.
*/
protected AbstractFileSet getRef(Project p) {
if (!checked) {
@@ -361,10 +370,10 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
stk.push(this);
dieOnCircularReference(stk, p);
}
-
+
Object o = ref.getReferencedObject(p);
if (!getClass().isAssignableFrom(o.getClass())) {
- String msg = ref.getRefId() + " doesn\'t denote a "
+ String msg = ref.getRefId() + " doesn\'t denote a "
+ getDataTypeName();
throw new BuildException(msg);
} else {
@@ -372,4 +381,153 @@ public abstract class AbstractFileSet extends DataType implements Cloneable {
}
}
+ // SelectorContainer methods
+
+ /**
+ * Indicates whether there are any selectors here.
+ *
+ * @return whether any selectors are in this container
+ */
+ public boolean hasSelectors() {
+ return !(selectors.isEmpty());
+ }
+
+ /**
+ * Gives the count of the number of selectors in this container
+ *
+ * @return the number of selectors in this container
+ */
+ public int selectorCount() {
+ return selectors.size();
+ }
+
+ /**
+ * Returns the set of selectors as an array.
+ *
+ * @return an array of selectors in this container
+ */
+ public FileSelector[] getSelectors(Project p) {
+ if (isReference()) {
+ return getRef(p).getSelectors(p);
+ } else {
+ FileSelector[] result = new FileSelector[selectors.size()];
+ selectors.copyInto(result);
+ return result;
+ }
+ }
+
+ /**
+ * Returns an enumerator for accessing the set of selectors.
+ *
+ * @return an enumerator that goes through each of the selectors
+ */
+ public Enumeration selectorElements() {
+ return selectors.elements();
+ }
+
+ /**
+ * Add a new selector into this container.
+ *
+ * @param selector the new selector to add
+ */
+ public void appendSelector(FileSelector selector) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ selectors.addElement(selector);
+ }
+
+ /* Methods below all implement the static selectors */
+
+ /**
+ * add an "And" selector entry on the selector list
+ */
+ public void addAnd(AndSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add an "Or" selector entry on the selector list
+ */
+ public void addOr(OrSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a "Not" selector entry on the selector list
+ */
+ public void addNot(NotSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a "None" selector entry on the selector list
+ */
+ public void addNone(NoneSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a majority selector entry on the selector list
+ */
+ public void addMajority(MajoritySelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector date entry on the selector list
+ */
+ public void addDateselect(DateSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector size entry on the selector list
+ */
+ public void addSizeselect(SizeSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector filename entry on the selector list
+ */
+ public void addFilenameselect(FilenameSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add an extended selector entry on the selector list
+ */
+ public void addExtendSelect(ExtendSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a contains selector entry on the selector list
+ */
+ public void addContainsSelect(ContainsSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a present selector entry on the selector list
+ */
+ public void addPresentSelect(PresentSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a depth selector entry on the selector list
+ */
+ public void addDepthSelect(DepthSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a depends selector entry on the selector list
+ */
+ public void addDependSelect(DependSelector selector) {
+ appendSelector(selector);
+ }
+
}
diff --git a/src/main/org/apache/tools/ant/types/selectors/AndSelector.java b/src/main/org/apache/tools/ant/types/selectors/AndSelector.java
new file mode 100644
index 000000000..51345571e
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/AndSelector.java
@@ -0,0 +1,111 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors, all of which have to
+ * select a file in order for this selector to select it.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class AndSelector extends BaseSelectorContainer {
+
+ /**
+ * Default constructor.
+ */
+ public AndSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (hasSelectors()) {
+ buf.append("{andselect: ");
+ buf.append(super.toString());
+ buf.append("}");
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns true (the file is selected) only if all other selectors
+ * agree that the file should be selected.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename the name of the file to check
+ * @param file a java.io.File object for the filename that the selector
+ * can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+ Enumeration e = selectorElements();
+ boolean result;
+
+ while(e.hasMoreElements()) {
+ result = ((FileSelector)e.nextElement()).isSelected(basedir,
+ filename,file);
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java b/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java
new file mode 100644
index 000000000..73095f8d3
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java
@@ -0,0 +1,121 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Parameter;
+
+
+/**
+ * Convenience base class for all selectors accessed through ExtendSelector.
+ * It provides support for gathering the parameters together as well as for
+ * assigning an error message and throwing a build exception if an error is
+ * detected.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public abstract class BaseExtendSelector extends BaseSelector implements
+ ExtendFileSelector {
+
+ /** The passed in parameter array. */
+ protected Parameter[] parameters = null;
+
+ /**
+ * Default constructor.
+ */
+ public BaseExtendSelector() {
+ }
+
+ /**
+ * Set all the Parameters for this dynamic selector, collected by
+ * the ExtendSelector class.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Allows access to the parameters gathered and set within the
+ * <extendselect> tag.
+ *
+ * @return the set of parameters defined for this selector
+ */
+ protected Parameter[] getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Method that each selector will implement to create their
+ * selection behaviour. If there is a problem with the setup
+ * of a selector, it can throw a BuildException to indicate
+ * the problem.
+ *
+ * @param basedir A java.io.File object for the base directory
+ * @param filename The name of the file to check
+ * @param file A File object for this filename
+ * @return whether the file should be selected or not
+ */
+ public abstract boolean isSelected(File basedir, String filename,
+ File file)
+ throws BuildException;
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java
new file mode 100644
index 000000000..b1e0a0f3f
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java
@@ -0,0 +1,143 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+
+/**
+ * A convenience base class that you can subclass Selectors from. It
+ * provides some helpful common behaviour. Note that there is no need
+ * for Selectors to inherit from this class, it is only necessary that
+ * they implement FileSelector.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public abstract class BaseSelector extends DataType implements FileSelector {
+
+ private String errmsg = null;
+
+
+ /**
+ * Do nothing constructor.
+ */
+ public BaseSelector() {
+ }
+
+ /**
+ * Allows all selectors to indicate a setup error. Note that only
+ * the first error message is recorded.
+ *
+ * @param msg The error message any BuildException should throw.
+ */
+ public void setError(String msg) {
+ if (errmsg == null) {
+ errmsg = msg;
+ }
+ }
+
+ /**
+ * Returns any error messages that have been set.
+ *
+ * @return the error condition
+ */
+ public String getError() {
+ return errmsg;
+ }
+
+
+ /**
+ * <p>Subclasses can override this method to provide checking of their
+ * state. So long as they call validate() from isSelected(), this will
+ * be called automatically (unless they override validate()).</p>
+ * <p>Implementations should check for incorrect settings and call
+ * setError() as necessary.</p>
+ */
+ public void verifySettings() {
+ }
+
+
+
+ /**
+ * Subclasses can use this to throw the requisite exception
+ * in isSelected() in the case of an error condition.
+ */
+ public void validate() {
+ verifySettings();
+ if (getError() != null) {
+ throw new BuildException(errmsg);
+ }
+ }
+
+ /**
+ * Method that each selector will implement to create their
+ * selection behaviour. If there is a problem with the setup
+ * of a selector, it can throw a BuildException to indicate
+ * the problem.
+ *
+ * @param basedir A java.io.File object for the base directory
+ * @param filename The name of the file to check
+ * @param file A File object for this filename
+ * @return whether the file should be selected or not
+ */
+ public abstract boolean isSelected(File basedir, String filename,
+ File file);
+
+}
+
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java
new file mode 100644
index 000000000..ac3a97f6c
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java
@@ -0,0 +1,312 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Reference;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * This is the base class for selectors that can contain other selectors.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public abstract class BaseSelectorContainer extends BaseSelector
+ implements SelectorContainer {
+
+ private Vector selectorsList = new Vector();
+
+ /**
+ * Default constructor.
+ */
+ public BaseSelectorContainer() {
+ }
+
+ /**
+ * Indicates whether there are any selectors here.
+ */
+ public boolean hasSelectors() {
+ return !(selectorsList.isEmpty());
+ }
+
+ /**
+ * Gives the count of the number of selectors in this container
+ */
+ public int selectorCount() {
+ return selectorsList.size();
+ }
+
+ /**
+ * Returns the set of selectors as an array.
+ */
+ public FileSelector[] getSelectors(Project p) {
+ if (isReference()) {
+ return getRef(p).getSelectors(p);
+ } else {
+ FileSelector[] result = new FileSelector[selectorsList.size()];
+ selectorsList.copyInto(result);
+ return result;
+ }
+ }
+
+ /**
+ * Returns an enumerator for accessing the set of selectors.
+ */
+ public Enumeration selectorElements() {
+ return selectorsList.elements();
+ }
+
+ /**
+ * Performs the check for circular references and returns the
+ * referenced SelectorContainer.
+ */
+ private SelectorContainer getRef(Project p) {
+ if (!checked) {
+ Stack stk = new Stack();
+ stk.push(this);
+ dieOnCircularReference(stk, p);
+ }
+
+ Object o = ref.getReferencedObject(p);
+ if (!(o instanceof SelectorContainer)) {
+ throw new BuildException(ref.getRefId() +
+ " doesn\'t denote a selector type");
+ } else {
+ return (SelectorContainer) o;
+ }
+ }
+
+ /**
+ * Convert the Selectors within this container to a string. This will
+ * just be a helper class for the subclasses that put their own name
+ * around the contents listed here.
+ *
+ * @return comma separated list of Selectors contained in this one
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ Enumeration e = selectorElements();
+ if (e.hasMoreElements()) {
+ while(e.hasMoreElements()) {
+ buf.append(e.nextElement().toString());
+ if (e.hasMoreElements()) {
+ buf.append(", ");
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Add a new selector into this container.
+ *
+ * @param selector the new selector to add
+ * @return the selector that was added
+ */
+ public void appendSelector(FileSelector selector) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ selectorsList.addElement(selector);
+ }
+
+ /**
+ * <p>This implementation validates the container by calling
+ * verifySettings() and then validates each contained selector
+ * provided that the selector implements the validate interface.
+ * </p>
+ * <p>Ordinarily, this will validate all the elements of a selector
+ * container even if the isSelected() method of some elements is
+ * never called. This has two effects:</p>
+ * <ul>
+ * <li>Validation will often occur twice.
+ * <li>Since it is not required that selectors derive from
+ * BaseSelector, there could be selectors in the container whose
+ * error conditions are not detected if their isSelected() call
+ * is never made.
+ * </ul>
+ */
+ public void validate() {
+ verifySettings();
+ String errmsg = getError();
+ if (errmsg != null) {
+ throw new BuildException(errmsg);
+ }
+ Enumeration e = selectorElements();
+ while(e.hasMoreElements()) {
+ Object o = e.nextElement();
+ if (o instanceof BaseSelector) {
+ ((BaseSelector)o).validate();
+ }
+ }
+ }
+
+
+ /**
+ * Method that each selector will implement to create their selection
+ * behaviour. This is what makes SelectorContainer abstract.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename the name of the file to check
+ * @param file a java.io.File object for the filename that the selector
+ * can use
+ * @return whether the file should be selected or not
+ */
+ public abstract boolean isSelected(File basedir, String filename,
+ File file);
+
+
+ /* Methods below all implement the static selectors */
+
+ /**
+ * add an "And" selector entry on the selector list
+ */
+ public void addAnd(AndSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add an "Or" selector entry on the selector list
+ */
+ public void addOr(OrSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a "Not" selector entry on the selector list
+ */
+ public void addNot(NotSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a "None" selector entry on the selector list
+ */
+ public void addNone(NoneSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a majority selector entry on the selector list
+ */
+ public void addMajority(MajoritySelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector date entry on the selector list
+ */
+ public void addDateselect(DateSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector size entry on the selector list
+ */
+ public void addSizeselect(SizeSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a selector filename entry on the selector list
+ */
+ public void addFilenameselect(FilenameSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add an extended selector entry on the selector list
+ */
+ public void addExtendSelect(ExtendSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a contains selector entry on the selector list
+ */
+ public void addContainsSelect(ContainsSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a present selector entry on the selector list
+ */
+ public void addPresentSelect(PresentSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a depth selector entry on the selector list
+ */
+ public void addDepthSelect(DepthSelector selector) {
+ appendSelector(selector);
+ }
+
+ /**
+ * add a depends selector entry on the selector list
+ */
+ public void addDependSelect(DependSelector selector) {
+ appendSelector(selector);
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java
new file mode 100644
index 000000000..e7b505b44
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java
@@ -0,0 +1,197 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Selector that filters files based on whether they contain a
+ * particular string.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class ContainsSelector extends BaseExtendSelector {
+
+ private String contains = null;
+ private boolean casesensitive = true;
+ public final static String CONTAINS_KEY = "contains";
+ public final static String CASE_KEY = "casesensitive";
+
+
+ public ContainsSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{containsselector contains: ");
+ buf.append(contains);
+ buf.append(" casesensitive: ");
+ if (casesensitive) {
+ buf.append("true");
+ } else {
+ buf.append("false");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * The string to search for within a file.
+ *
+ * @param contains the string that a file must contain to be selected.
+ */
+ public void setContains(String contains) {
+ this.contains = contains;
+ }
+
+ /**
+ * Whether to ignore case in the string being searched.
+ *
+ * @param casesensitive whether to pay attention to case sensitivity
+ */
+ public void setCasesensitive(boolean casesensitive) {
+ this.casesensitive = casesensitive;
+ }
+
+ /**
+ * When using this as a dynamic selector, this method will be called.
+ * It translates each parameter into the appropriate setXXX() call.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ super.setParameters(parameters);
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ String paramname = parameters[i].getName();
+ if (CONTAINS_KEY.equalsIgnoreCase(paramname)) {
+ setContains(parameters[i].getValue());
+ }
+ else if (CASE_KEY.equalsIgnoreCase(paramname)) {
+ setCasesensitive(Project.toBoolean(
+ parameters[i].getValue()));
+ }
+ else {
+ setError("Invalid parameter " + paramname);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks to make sure all settings are kosher. In this case, it
+ * means that the pattern attribute has been set.
+ *
+ */
+ public void verifySettings() {
+ if (contains == null) {
+ setError("The contains attribute is required");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+
+ // throw BuildException on error
+ validate();
+
+ if (file.isDirectory()) {
+ return true;
+ }
+
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new InputStreamReader(
+ new FileInputStream(file)));
+ String teststr = in.readLine();
+ while (teststr != null) {
+ if (teststr.indexOf(contains) > -1) {
+ return true;
+ }
+ teststr = in.readLine();
+ }
+ return false;
+ }
+ catch (IOException ioe) {
+ throw new BuildException("Could not read file " + filename);
+ }
+ finally {
+ try {
+ in.close();
+ }
+ catch (Exception e) {
+ throw new BuildException("Could not close file " + filename);
+ }
+ }
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/DateSelector.java b/src/main/org/apache/tools/ant/types/selectors/DateSelector.java
new file mode 100644
index 000000000..d72e45893
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/DateSelector.java
@@ -0,0 +1,250 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that chooses files based on their last modified date.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class DateSelector extends BaseExtendSelector {
+
+ private long millis = -1;
+ private String dateTime = null;
+ private boolean includeDirs = false;
+ private int cmp = 0;
+ public final static String MILLIS_KEY = "millis";
+ public final static String DATETIME_KEY = "datetime";
+ public final static String CHECKDIRS_KEY = "checkdirs";
+ public final static String WHEN_KEY = "when";
+
+ public DateSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{dateselector date: ");
+ buf.append(dateTime);
+ buf.append("compare: ");
+ if (cmp == 0) {
+ buf.append("before");
+ }
+ else if (cmp == 1) {
+ buf.append("after");
+ } else {
+ buf.append("equal");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * For users that prefer to express time in milliseconds since 1970
+ *
+ * @param millis the time to compare file's last modified date to,
+ * expressed in milliseconds
+ */
+ public void setMillis(long millis) {
+ this.millis = millis;
+ }
+
+ /**
+ * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM
+ * format
+ *
+ * @param dateTime a string in MM/DD/YYYY HH:MM AM_PM format
+ */
+ public void setDatetime(String dateTime) {
+ this.dateTime = dateTime;
+ if (dateTime != null) {
+ DateFormat df = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT,
+ DateFormat.SHORT,
+ Locale.US);
+ try {
+ setMillis(df.parse(dateTime).getTime());
+ if (millis < 0) {
+ setError("Date of " + dateTime
+ + " results in negative milliseconds value relative"
+ + " to epoch (January 1, 1970, 00:00:00 GMT).");
+ }
+ } catch (ParseException pe) {
+ setError("Date of " + dateTime
+ + " Cannot be parsed correctly. It should be in"
+ + " MM/DD/YYYY HH:MM AM_PM format.");
+ }
+ }
+ }
+
+ /**
+ * Should we be checking dates on directories?
+ *
+ * @param includeDirs whether to check the timestamp on directories
+ */
+ public void setCheckdirs(boolean includeDirs) {
+ this.includeDirs = includeDirs;
+ }
+
+ /**
+ * Sets the type of comparison to be done on the file's last modified
+ * date.
+ *
+ * @param cmp The comparison to perform, an EnumeratedAttribute
+ */
+ public void setWhen(TimeComparisons cmp) {
+ this.cmp = cmp.getIndex();
+ }
+
+ /**
+ * When using this as a dynamic selector, this method will be called.
+ * It translates each parameter into the appropriate setXXX() call.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ super.setParameters(parameters);
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ String paramname = parameters[i].getName();
+ if (MILLIS_KEY.equalsIgnoreCase(paramname)) {
+ try {
+ setMillis(new Long(parameters[i].getValue()
+ ).longValue());
+ } catch (NumberFormatException nfe) {
+ setError("Invalid millisecond setting " +
+ parameters[i].getValue());
+ }
+ }
+ else if (DATETIME_KEY.equalsIgnoreCase(paramname)) {
+ setDatetime(parameters[i].getValue());
+ }
+ else if (CHECKDIRS_KEY.equalsIgnoreCase(paramname)) {
+ setCheckdirs(Project.toBoolean(parameters[i].getValue()));
+ }
+ else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
+ TimeComparisons cmp = new TimeComparisons();
+ cmp.setValue(parameters[i].getValue());
+ setWhen(cmp);
+ }
+ else {
+ setError("Invalid parameter " + paramname);
+ }
+ }
+ }
+ }
+
+ /**
+ * This is a consistency check to ensure the selector's required
+ * values have been set.
+ */
+ public void verifySettings() {
+ if (dateTime == null && millis < 0) {
+ setError("You must provide a datetime or the number of "
+ + "milliseconds.");
+ }
+ else if (millis < 0) {
+ setError("Date of " + dateTime
+ + " results in negative milliseconds"
+ + " value relative to epoch (January 1, 1970, 00:00:00 GMT).");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+ if (file.isDirectory() && (includeDirs == false)) {
+ return true;
+ }
+ if (cmp == 0) {
+ return (file.lastModified() < millis);
+ }
+ else if (cmp == 1) {
+ return (file.lastModified() > millis);
+ }
+ else {
+ return (file.lastModified() == millis);
+ }
+ }
+
+ /**
+ * Enumerated attribute with the values for time comparison.
+ * <p>
+ */
+ public static class TimeComparisons extends EnumeratedAttribute {
+ public String[] getValues() {
+ return new String[] {"before", "after", "equal"};
+ }
+ }
+
+}
+
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/DependSelector.java b/src/main/org/apache/tools/ant/types/selectors/DependSelector.java
new file mode 100644
index 000000000..ceefdd7f9
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/DependSelector.java
@@ -0,0 +1,186 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Selector that filters files based on whether they are newer than
+ * a matching file in another directory tree. It can contain a mapper
+ * element, so isn't available as an ExtendSelector (since those
+ * parameters can't hold other elements).
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class DependSelector extends BaseSelector {
+
+ private String targetdir = null;
+ private File targetbase = null;
+ private Mapper mapperElement = null;
+ private FileNameMapper map = null;
+ private int granularity = 0;
+
+ public DependSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{dependselector targetdir: ");
+ buf.append(targetdir);
+ buf.append(" granularity: ");
+ buf.append(granularity);
+ if (map != null) {
+ buf.append(" mapper: ");
+ buf.append(map.toString());
+ }
+ else if (mapperElement != null) {
+ buf.append(" mapper: ");
+ buf.append(mapperElement.toString());
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * The name of the file or directory which is checked for out-of-date
+ * files.
+ *
+ * @param targetdir the directory to scan looking for files.
+ */
+ public void setTargetdir(String targetdir) {
+ this.targetdir = SelectorUtils.fixPath(targetdir);
+ targetbase = new File(this.targetdir);
+ }
+
+ /**
+ * Sets the number of milliseconds leeway we will give before we consider
+ * a file out of date.
+ */
+ public void setGranularity(int granularity) {
+ this.granularity = granularity;
+ }
+
+ /**
+ * Defines the FileNameMapper to use (nested mapper element).
+ */
+ public Mapper createMapper() throws BuildException {
+ if (mapperElement != null) {
+ throw new BuildException("Cannot define more than one mapper");
+ }
+ mapperElement = new Mapper(project);
+ return mapperElement;
+ }
+
+
+ /**
+ * Checks to make sure all settings are kosher. In this case, it
+ * means that the dest attribute has been set and we have a mapper.
+ */
+ public void verifySettings() {
+ if (targetdir == null) {
+ setError("The targetdir attribute is required.");
+ }
+ if (mapperElement == null) {
+ map = new IdentityMapper();
+ }
+ else {
+ map = mapperElement.getImplementation();
+ }
+ if (map == null) {
+ setError("Could not set <mapper> element.");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+
+ // throw BuildException on error
+ validate();
+
+ // Get File object for the target directory
+ File target = targetbase;
+ if (target == null) {
+ target = new File(basedir,targetdir);
+ }
+
+ // Determine file whose out-of-dateness is to be checked
+ String[] destfiles = map.mapFileName(filename);
+ // Sanity check
+ if (destfiles.length != 1 || destfiles[0] == null) {
+ throw new BuildException("Invalid destination file results for "
+ + targetdir + " with filename " + filename);
+ }
+ String destname = destfiles[0];
+ File destfile = new File(target,destname);
+
+ return SelectorUtils.isOutOfDate(file, destfile, granularity);
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java b/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java
new file mode 100644
index 000000000..1b2002216
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java
@@ -0,0 +1,209 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Selector that filters files based on the how deep in the directory
+ * tree they are.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class DepthSelector extends BaseExtendSelector {
+
+ public int min = -1;
+ public int max = -1;
+ public final static String MIN_KEY = "min";
+ public final static String MAX_KEY = "max";
+
+ public DepthSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{depthselector min: ");
+ buf.append(min);
+ buf.append(" max: ");
+ buf.append(max);
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * The minimum depth below the basedir before a file is selected.
+ *
+ * @param min minimum directory levels below basedir to go
+ */
+ public void setMin(int min) {
+ this.min = min;
+ }
+
+ /**
+ * The minimum depth below the basedir before a file is selected.
+ *
+ * @param min maximum directory levels below basedir to go
+ */
+ public void setMax(int max) {
+ this.max = max;
+ }
+
+ /**
+ * When using this as a dynamic selector, this method will be called.
+ * It translates each parameter into the appropriate setXXX() call.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ super.setParameters(parameters);
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ String paramname = parameters[i].getName();
+ if (MIN_KEY.equalsIgnoreCase(paramname)) {
+ try {
+ setMin(Integer.parseInt(parameters[i].getValue()));
+ }
+ catch (NumberFormatException nfe1) {
+ setError("Invalid minimum value "
+ + parameters[i].getValue());
+ }
+ }
+ else if (MAX_KEY.equalsIgnoreCase(paramname)) {
+ try {
+ setMax(Integer.parseInt(parameters[i].getValue()));
+ }
+ catch (NumberFormatException nfe1) {
+ setError("Invalid maximum value "
+ + parameters[i].getValue());
+ }
+ }
+ else {
+ setError("Invalid parameter " + paramname);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks to make sure all settings are kosher. In this case, it
+ * means that the max depth is not lower than the min depth.
+ */
+ public void verifySettings() {
+ if (min < 0 && max < 0) {
+ setError("You must set at least one of the min or the " +
+ "max levels.");
+ }
+ if (max < min) {
+ setError("The maximum depth is lower than the minimum.");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset. Most of the work
+ * for this selector is offloaded into SelectorUtils, a static class
+ * that provides the same services for both FilenameSelector and
+ * DirectoryScanner.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+
+ // throw BuildException on error
+ validate();
+
+ int depth = -1;
+ // If you felt daring, you could cache the basedir absolute path
+ String abs_base = basedir.getAbsolutePath();
+ String abs_file = file.getAbsolutePath();
+ StringTokenizer tok_base = new StringTokenizer(abs_base, File.separator);
+ StringTokenizer tok_file = new StringTokenizer(abs_file, File.separator);
+ while (tok_file.hasMoreTokens()) {
+ String filetoken = tok_file.nextToken();
+ if (tok_base.hasMoreTokens()) {
+ String basetoken = tok_base.nextToken();
+ // Sanity check. Ditch it if you want faster performance
+ if (!basetoken.equals(filetoken)) {
+ throw new BuildException("File " + filename +
+ " does not appear within " + abs_base + "directory");
+ }
+ }
+ else {
+ depth += 1;
+ if (max > -1 && depth > max) {
+ return false;
+ }
+ }
+ }
+ if (tok_base.hasMoreTokens()) {
+ throw new BuildException("File " + filename +
+ " is outside of " + abs_base + "directory tree");
+ }
+ if (min > -1 && depth < min) {
+ return false;
+ }
+ return true;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java b/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java
new file mode 100644
index 000000000..25d968c9b
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java
@@ -0,0 +1,78 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.types.Parameterizable;
+
+/**
+ * This is the interface to be used by all dynamic selectors, those that are
+ * called through the <extendselect> tag. It is the amalgamation of two
+ * interfaces, the FileSelector and the Paramterizable interface. Note that
+ * you will almost certainly want the default behaviour for handling
+ * Parameters, so you probably want to use the BaseExtendSelector class
+ * as the base class for your dynamic selector rather than implementing
+ * this interface from scratch.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public interface ExtendFileSelector extends FileSelector, Parameterizable {
+
+ // No further methods necessary. This is just an amalgamation of two other
+ // interfaces.
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java b/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java
new file mode 100644
index 000000000..9925fe971
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java
@@ -0,0 +1,213 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Selector that selects files by forwarding the request on to other classes.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class ExtendSelector extends BaseSelector {
+
+ private String classname = null;
+ private ExtendFileSelector dynselector = null;
+ private Vector paramVec = new Vector();
+ private Path classpath = null;
+
+ /**
+ * Default constructor.
+ */
+ public ExtendSelector() {
+ }
+
+ /**
+ * Sets the classname of the dynamic selector.
+ *
+ * @param classname is the class which implements this selector
+ */
+ public void setClassname(String classname) {
+ this.classname = classname;
+ }
+
+ /**
+ * Instantiates the identified dynamic selector class.
+ */
+ public void selectorCreate() {
+ if (classname != null && classname.length() > 0) {
+ try {
+ dynselector = (ExtendFileSelector)
+ Class.forName(classname).newInstance();
+ }
+ catch (ClassNotFoundException cnfexcept) {
+ setError("Selector " + classname +
+ " not initialized, no such class");
+ }
+ catch (InstantiationException iexcept) {
+ setError("Selector " + classname +
+ " not initialized, could not create class");
+ }
+ catch (IllegalAccessException iaexcept) {
+ setError("Selector " + classname +
+ " not initialized, class not accessible");
+ }
+ } else {
+ setError("There is no classname specified");
+ }
+ }
+
+ /**
+ * Create new parameters to pass to dynamic selector.
+ *
+ * @param p The new Parameter object
+ */
+ public void addParam(Parameter p) {
+ paramVec.addElement(p);
+ }
+
+
+ /**
+ * Set the classpath to load the classname specified using an attribute.
+ */
+ public final void setClasspath(Path classpath) {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * Specify the classpath to use to load the Selector (nested element).
+ */
+ public final Path createClasspath() {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ if (this.classpath == null) {
+ this.classpath = new Path(getProject());
+ }
+ return this.classpath.createPath();
+ }
+
+ /**
+ * Get the classpath
+ */
+ public final Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * Set the classpath to use for loading a dynamic selector by using
+ * a reference.
+ */
+ public void setClasspathref(Reference r) {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * These are errors specific to ExtendSelector only. If there are
+ * errors in the dynamic selector, it should throw a BuildException
+ * when isSelected() is called.
+ */
+ public void verifySettings() {
+ if (classname == null || classname.length() < 1) {
+ setError("The classname attribute is required");
+ }
+ else if (dynselector == null) {
+ setError("Internal Error: The dynamic selector is not set");
+ }
+ }
+
+
+ /**
+ * Allows the dynamic selector to choose whether to select a file. This
+ * is also where the Parameters are passed to the dynamic selector,
+ * since we know we must have them all by now. And since we must know
+ * both classpath and classname, creating the class is deferred to here
+ * as well.
+ */
+ public boolean isSelected(File basedir, String filename, File file)
+ throws BuildException {
+ if (dynselector == null) {
+ selectorCreate();
+ }
+ validate();
+ if (paramVec.size() > 0) {
+ Parameter[] paramArray = new Parameter[paramVec.size()];
+ paramVec.copyInto(paramArray);
+ // We know that dynselector must be non-null if no error message
+ dynselector.setParameters(paramArray);
+ }
+ return dynselector.isSelected(basedir,filename,file);
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/FileSelector.java b/src/main/org/apache/tools/ant/types/selectors/FileSelector.java
new file mode 100644
index 000000000..f877ff7bc
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/FileSelector.java
@@ -0,0 +1,85 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This is the interface to be used by all selectors.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public interface FileSelector {
+
+ /**
+ * Method that each selector will implement to create their
+ * selection behaviour. If there is a problem with the setup
+ * of a selector, it can throw a BuildException to indicate
+ * the problem.
+ *
+ * @param basedir A java.io.File object for the base directory
+ * @param filename The name of the file to check
+ * @param file A File object for this filename
+ * @return whether the file should be selected or not
+ * @exception BuildException if the selector was not configured correctly
+ */
+ public boolean isSelected(File basedir, String filename, File file)
+ throws BuildException;
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java b/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java
new file mode 100644
index 000000000..1706790bb
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java
@@ -0,0 +1,195 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that filters files based on the filename.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class FilenameSelector extends BaseExtendSelector {
+
+ private String pattern = null;
+ private boolean casesensitive = true;
+ private boolean negated = false;
+ public final static String NAME_KEY = "name";
+ public final static String CASE_KEY = "casesensitive";
+ public final static String NEGATE_KEY = "negate";
+
+ public FilenameSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{filenameselector name: ");
+ buf.append(pattern);
+ buf.append(" negate: ");
+ if (negated) {
+ buf.append("true");
+ } else {
+ buf.append("false");
+ }
+ buf.append(" casesensitive: ");
+ if (casesensitive) {
+ buf.append("true");
+ } else {
+ buf.append("false");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * The name of the file, or the pattern for the name, that
+ * should be used for selection.
+ *
+ * @param pattern the file pattern that any filename must match
+ * against in order to be selected.
+ */
+ public void setName(String pattern) {
+ pattern = pattern.replace('/',File.separatorChar).replace('\\',
+ File.separatorChar);
+ if (pattern.endsWith(File.separator)) {
+ pattern += "**";
+ }
+ this.pattern = pattern;
+ }
+
+ /**
+ * Whether to ignore case when checking filenames.
+ *
+ * @param casesensitive whether to pay attention to case sensitivity
+ */
+ public void setCasesensitive(boolean casesensitive) {
+ this.casesensitive = casesensitive;
+ }
+
+ /**
+ * You can optionally reverse the selection of this selector,
+ * thereby emulating an <exclude> tag, by setting the attribute
+ * negate to true. This is identical to surrounding the selector
+ * with <not></not>.
+ *
+ * @param negated whether to negate this selection
+ */
+ public void setNegate(boolean negated) {
+ this.negated = negated;
+ }
+
+ /**
+ * When using this as a dynamic selector, this method will be called.
+ * It translates each parameter into the appropriate setXXX() call.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ super.setParameters(parameters);
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ String paramname = parameters[i].getName();
+ if (NAME_KEY.equalsIgnoreCase(paramname)) {
+ setName(parameters[i].getValue());
+ }
+ else if (CASE_KEY.equalsIgnoreCase(paramname)) {
+ setCasesensitive(Project.toBoolean(
+ parameters[i].getValue()));
+ }
+ else if (NEGATE_KEY.equalsIgnoreCase(paramname)) {
+ setNegate(Project.toBoolean(parameters[i].getValue()));
+ }
+ else {
+ setError("Invalid parameter " + paramname);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks to make sure all settings are kosher. In this case, it
+ * means that the name attribute has been set.
+ *
+ */
+ public void verifySettings() {
+ if (pattern == null) {
+ setError("The name attribute is required");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset. Most of the work
+ * for this selector is offloaded into SelectorUtils, a static class
+ * that provides the same services for both FilenameSelector and
+ * DirectoryScanner.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+
+ return SelectorUtils.matchPath(pattern,filename,
+ casesensitive);
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java b/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java
new file mode 100644
index 000000000..1d4364406
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java
@@ -0,0 +1,135 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector is here just to shake up your thinking a bit. Don't get
+ * too caught up in boolean, there are other ways you can evaluate a
+ * collection of selectors. This one takes a vote of the selectors it
+ * contains, and majority wins. You could also have an "all-but-one"
+ * selector, a "weighted-average" selector, and so on. These are left
+ * as exercises for the reader (as are the usecases where this would
+ * be necessary).
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class MajoritySelector extends BaseSelectorContainer {
+
+ private boolean allowtie = true;
+
+ /**
+ * Default constructor.
+ */
+ public MajoritySelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (hasSelectors()) {
+ buf.append("{majorityselect: ");
+ buf.append(super.toString());
+ buf.append("}");
+ }
+ return buf.toString();
+ }
+
+ public void setAllowtie(boolean tiebreaker) {
+ allowtie = tiebreaker;
+ }
+
+ /**
+ * Returns true (the file is selected) if most of the other selectors
+ * agree. In case of a tie, go by the allowtie setting. That defaults
+ * to true, meaning in case of a tie, the file is selected.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object for the filename that the selector
+ * can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+ int yesvotes = 0;
+ int novotes = 0;
+ Enumeration e = selectorElements();
+ boolean result;
+
+ while(e.hasMoreElements()) {
+ result = ((FileSelector)e.nextElement()).isSelected(basedir,
+ filename,file);
+ if (result) {
+ yesvotes = yesvotes + 1;
+ }
+ else {
+ novotes = novotes + 1;
+ }
+ }
+ if (yesvotes > novotes)
+ {
+ return true;
+ }
+ else if (novotes > yesvotes) {
+ return false;
+ }
+ // At this point, we know we have a tie.
+ return allowtie;
+ }
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java b/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java
new file mode 100644
index 000000000..a07c76fb3
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java
@@ -0,0 +1,112 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors. All of those selectors
+ * must refuse to select a file before the file is considered selected by
+ * this selector.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class NoneSelector extends BaseSelectorContainer {
+
+ /**
+ * Default constructor.
+ */
+ public NoneSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (hasSelectors()) {
+ buf.append("{noneselect: ");
+ buf.append(super.toString());
+ buf.append("}");
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns true (the file is selected) only if all other selectors
+ * agree that the file should not be selected.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object for the filename that the selector
+ * can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+ Enumeration e = selectorElements();
+ boolean result;
+
+ while(e.hasMoreElements()) {
+ result = ((FileSelector)e.nextElement()).isSelected(basedir,
+ filename,file);
+ if (result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/NotSelector.java b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java
new file mode 100644
index 000000000..7a16930e0
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java
@@ -0,0 +1,99 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has one other selectors whose meaning it inverts. It
+ * actually relies on NoneSelector for its implementation of the
+ * isSelected() method, but it adds a check to ensure there is only one
+ * other selector contained within.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class NotSelector extends NoneSelector {
+
+ /**
+ * Default constructor.
+ */
+ public NotSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (hasSelectors()) {
+ buf.append("{notselect: ");
+ buf.append(super.toString());
+ buf.append("}");
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Makes sure that there is only one entry, sets an error message if
+ * not.
+ */
+ public void verifySettings() {
+ if (selectorCount() != 1) {
+ setError("One and only one selector is allowed within the " +
+ "<not> tag");
+ }
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/OrSelector.java b/src/main/org/apache/tools/ant/types/selectors/OrSelector.java
new file mode 100644
index 000000000..324a33d55
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/OrSelector.java
@@ -0,0 +1,112 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors, any of which have to
+ * select a file in order for this selector to select it.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class OrSelector extends BaseSelectorContainer {
+
+ /**
+ * Default constructor.
+ */
+ public OrSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (hasSelectors()) {
+ buf.append("{orselect: ");
+ buf.append(super.toString());
+ buf.append("}");
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns true (the file is selected) if any of the other selectors
+ * agree that the file should be selected.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename the name of the file to check
+ * @param file a java.io.File object for the filename that the selector
+ * can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+ validate();
+ Enumeration e = selectorElements();
+ boolean result;
+
+ // First, check that all elements are correctly configured
+ while(e.hasMoreElements()) {
+ result = ((FileSelector)e.nextElement()).isSelected(basedir,
+ filename,file);
+ if (result) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java b/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java
new file mode 100644
index 000000000..9efab0f0a
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java
@@ -0,0 +1,208 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Selector that filters files based on whether they appear in another
+ * directory tree. It can contain a mapper element, so isn't available
+ * as an ExtendSelector (since those parameters can't hold other
+ * elements).
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class PresentSelector extends BaseSelector {
+
+ private String targetdir = null;
+ private File targetbase = null;
+ private Mapper mapperElement = null;
+ private FileNameMapper map = null;
+ private boolean destmustexist = true;
+
+ public PresentSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{presentselector targetdir: ");
+ buf.append(targetdir);
+ buf.append(" present: ");
+ if (destmustexist) {
+ buf.append("both");
+ } else {
+ buf.append("srconly");
+ }
+ if (map != null) {
+ buf.append(map.toString());
+ }
+ else if (mapperElement != null) {
+ buf.append(mapperElement.toString());
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * The name of the file or directory which is checked for matching
+ * files.
+ *
+ * @param targetdir the directory to scan looking for matching files.
+ */
+ public void setTargetdir(String targetdir) {
+ this.targetdir = SelectorUtils.fixPath(targetdir);
+ targetbase = new File(this.targetdir);
+ }
+
+ /**
+ * Defines the FileNameMapper to use (nested mapper element).
+ */
+ public Mapper createMapper() throws BuildException {
+ if (mapperElement != null) {
+ throw new BuildException("Cannot define more than one mapper");
+ }
+ mapperElement = new Mapper(project);
+ return mapperElement;
+ }
+
+
+ /**
+ * This sets whether to select a file if its dest file is present.
+ * It could be a <code>negate</code> boolean, but by doing things
+ * this way, we get some documentation on how the system works.
+ * A user looking at the documentation should clearly understand
+ * that the ONLY files whose presence is being tested are those
+ * that already exist in the source directory, hence the lack of
+ * a <code>destonly</code> option.
+ *
+ * @param fp An attribute set to either <code>srconly</code or
+ * <code>both</code>.
+ */
+ public void setPresent(FilePresence fp) {
+ if (fp.getIndex() == 0) {
+ destmustexist = false;
+ }
+ }
+
+ /**
+ * Checks to make sure all settings are kosher. In this case, it
+ * means that the targetdir attribute has been set and we have a mapper.
+ */
+ public void verifySettings() {
+ if (targetdir == null) {
+ setError("The targetdir attribute is required.");
+ }
+ if (mapperElement == null) {
+ map = new IdentityMapper();
+ }
+ else {
+ map = mapperElement.getImplementation();
+ }
+ if (map == null) {
+ setError("Could not set <mapper> element.");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset.
+ *
+ * @param basedir the base directory the scan is being done from
+ * @param filename is the name of the file to check
+ * @param file is a java.io.File object the selector can use
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+
+ // throw BuildException on error
+ validate();
+
+ // Get File object for the target directory
+ File target = targetbase;
+ if (target == null) {
+ target = new File(basedir,targetdir);
+ }
+
+ // Determine file whose existence is to be checked
+ String[] destfiles = map.mapFileName(filename);
+ // Sanity check
+ if (destfiles.length != 1 || destfiles[0] == null) {
+ throw new BuildException("Invalid destination file results for "
+ + targetdir + " with filename " + filename);
+ }
+ String destname = destfiles[0];
+ File destfile = new File(target,destname);
+ return destfile.exists() == destmustexist;
+ }
+
+ /**
+ * Enumerated attribute with the values for indicating where a file's
+ * presence is allowed and required.
+ */
+ public static class FilePresence extends EnumeratedAttribute {
+ public String[] getValues() {
+ return new String[] {"srconly", "both"};
+ }
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java
new file mode 100644
index 000000000..819e88fa9
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java
@@ -0,0 +1,178 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Reference;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * This is the base class for selectors that can contain other selectors.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public interface SelectorContainer {
+
+ /**
+ * Indicates whether there are any selectors here.
+ *
+ * @return whether any selectors are in this container
+ */
+ public boolean hasSelectors();
+
+ /**
+ * Gives the count of the number of selectors in this container
+ *
+ * @return the number of selectors in this container
+ */
+ public int selectorCount();
+
+ /**
+ * Returns the set of selectors as an array.
+ *
+ * @return an array of selectors in this container
+ */
+ public FileSelector[] getSelectors(Project p);
+
+ /**
+ * Returns an enumerator for accessing the set of selectors.
+ *
+ * @return an enumerator that goes through each of the selectors
+ */
+ public Enumeration selectorElements();
+
+ /**
+ * Add a new selector into this container.
+ *
+ * @param selector the new selector to add
+ * @return the selector that was added
+ */
+ public void appendSelector(FileSelector selector);
+
+ /* Methods below all implement the static selectors */
+
+ /**
+ * add an "And" selector entry on the selector list
+ */
+ public void addAnd(AndSelector selector);
+
+ /**
+ * add an "Or" selector entry on the selector list
+ */
+ public void addOr(OrSelector selector);
+
+ /**
+ * add a "Not" selector entry on the selector list
+ */
+ public void addNot(NotSelector selector);
+
+ /**
+ * add a "None" selector entry on the selector list
+ */
+ public void addNone(NoneSelector selector);
+
+ /**
+ * add a majority selector entry on the selector list
+ */
+ public void addMajority(MajoritySelector selector);
+
+ /**
+ * add a selector date entry on the selector list
+ */
+ public void addDateselect(DateSelector selector);
+
+ /**
+ * add a selector size entry on the selector list
+ */
+ public void addSizeselect(SizeSelector selector);
+
+ /**
+ * add a selector filename entry on the selector list
+ */
+ public void addFilenameselect(FilenameSelector selector);
+
+ /**
+ * add an extended selector entry on the selector list
+ */
+ public void addExtendSelect(ExtendSelector selector);
+
+ /**
+ * add a contains selector entry on the selector list
+ */
+ public void addContainsSelect(ContainsSelector selector);
+
+ /**
+ * add a present selector entry on the selector list
+ */
+ public void addPresentSelect(PresentSelector selector);
+
+ /**
+ * add a depth selector entry on the selector list
+ */
+ public void addDepthSelect(DepthSelector selector);
+
+ /**
+ * add a depends selector entry on the selector list
+ */
+ public void addDependSelect(DependSelector selector);
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java b/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java
new file mode 100644
index 000000000..7d6786ed2
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java
@@ -0,0 +1,86 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.tools.ant.types.selectors;
+
+/**
+ * An interface used to describe the actions required by any type of
+ * directory scanner that supports Selecters.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public interface SelectorScanner {
+ /**
+ * Sets the selectors the scanner should use.
+ *
+ * @param selectors the list of selectors
+ */
+ void setSelectors(FileSelector[] selectors);
+
+ /**
+ * Directories which were selected out of a scan.
+ *
+ * @param selectors list selector objects
+ */
+ public String[] getDeselectedDirectories();
+
+ /**
+ * Files which were selected out of a scan.
+ *
+ * @param selectors list selector objects
+ */
+ public String[] getDeselectedFiles();
+
+
+}
diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
new file mode 100644
index 000000000..5c678fb26
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
@@ -0,0 +1,564 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * <p>This is a utility class used by selectors and DirectoryScanner. The
+ * functionality more properly belongs just to selectors, but unfortunately
+ * DirectoryScanner exposed these as protected methods. Thus we have to
+ * support any subclasses of DirectoryScanner that may access these methods.
+ * </p>
+ * <p>This is a Singleton.</p>
+ *
+ * @author Arnout J. Kuiper
+ * <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
+ * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a>
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public final class SelectorUtils {
+
+ private static SelectorUtils instance = new SelectorUtils();
+
+ /**
+ * Private Constructor
+ */
+ private SelectorUtils() {
+ }
+
+ /**
+ * Retrieves the instance of the Singleton.
+ */
+ public static SelectorUtils getInstance() {
+ return instance;
+ }
+
+ /**
+ * Tests whether or not a given path matches the start of a given
+ * pattern up to the first "**".
+ * <p>
+ * This is not a general purpose test and should only be used if you
+ * can live with false positives. For example, <code>pattern=**\a</code>
+ * and <code>str=b</code> will yield <code>true</code>.
+ *
+ * @param pattern The pattern to match against. Must not be
+ * <code>null</code>.
+ * @param str The path to match, as a String. Must not be
+ * <code>null</code>.
+ *
+ * @return whether or not a given path matches the start of a given
+ * pattern up to the first "**".
+ */
+ public static boolean matchPatternStart(String pattern, String str) {
+ return matchPatternStart(pattern, str, true);
+ }
+ /**
+ * Tests whether or not a given path matches the start of a given
+ * pattern up to the first "**".
+ * <p>
+ * This is not a general purpose test and should only be used if you
+ * can live with false positives. For example, <code>pattern=**\a</code>
+ * and <code>str=b</code> will yield <code>true</code>.
+ *
+ * @param pattern The pattern to match against. Must not be
+ * <code>null</code>.
+ * @param str The path to match, as a String. Must not be
+ * <code>null</code>.
+ * @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 "**".
+ */
+ public static boolean matchPatternStart(String pattern, String str,
+ boolean isCaseSensitive) {
+ // When str starts with a File.separator, pattern has to start with a
+ // File.separator.
+ // When pattern starts with a File.separator, str has to start with a
+ // File.separator.
+ if (str.startsWith(File.separator) !=
+ pattern.startsWith(File.separator)) {
+ return false;
+ }
+
+ Vector patDirs = tokenizePath (pattern);
+ Vector strDirs = tokenizePath (str);
+
+ int patIdxStart = 0;
+ int patIdxEnd = patDirs.size()-1;
+ int strIdxStart = 0;
+ int strIdxEnd = strDirs.size()-1;
+
+ // up to first '**'
+ while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+ String patDir = (String)patDirs.elementAt(patIdxStart);
+ if (patDir.equals("**")) {
+ break;
+ }
+ if (!match(patDir,(String)strDirs.elementAt(strIdxStart),
+ isCaseSensitive)) {
+ return false;
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+
+ if (strIdxStart > strIdxEnd) {
+ // String is exhausted
+ return true;
+ } else if (patIdxStart > patIdxEnd) {
+ // String not exhausted, but pattern is. Failure.
+ return false;
+ } else {
+ // pattern now holds ** while string is not exhausted
+ // this will generate false positives but we can live with that.
+ return true;
+ }
+ }
+
+ /**
+ * Tests whether or not a given path matches a given pattern.
+ *
+ * @param pattern The pattern to match against. Must not be
+ * <code>null</code>.
+ * @param str The path to match, as a String. Must not be
+ * <code>null</code>.
+ *
+ * @return <code>true</code> if the pattern matches against the string,
+ * or <code>false</code> otherwise.
+ */
+ public static boolean matchPath(String pattern, String str) {
+ return matchPath(pattern, str, true);
+ }
+
+ /**
+ * Tests whether or not a given path matches a given pattern.
+ *
+ * @param pattern The pattern to match against. Must not be
+ * <code>null</code>.
+ * @param str The path to match, as a String. Must not be
+ * <code>null</code>.
+ * @param isCaseSensitive Whether or not matching should be performed
+ * case sensitively.
+ *
+ * @return <code>true</code> if the pattern matches against the string,
+ * or <code>false</code> otherwise.
+ */
+ public static boolean matchPath(String pattern, String str,
+ boolean isCaseSensitive) {
+ // When str starts with a File.separator, pattern has to start with a
+ // File.separator.
+ // When pattern starts with a File.separator, str has to start with a
+ // File.separator.
+ if (str.startsWith(File.separator) !=
+ pattern.startsWith(File.separator)) {
+ return false;
+ }
+
+ Vector patDirs = tokenizePath (pattern);
+ Vector strDirs = tokenizePath (str);
+
+ int patIdxStart = 0;
+ int patIdxEnd = patDirs.size()-1;
+ int strIdxStart = 0;
+ int strIdxEnd = strDirs.size()-1;
+
+ // up to first '**'
+ while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+ String patDir = (String)patDirs.elementAt(patIdxStart);
+ if (patDir.equals("**")) {
+ break;
+ }
+ if (!match(patDir,(String)strDirs.elementAt(strIdxStart),
+ isCaseSensitive)) {
+ return false;
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // String is exhausted
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (!patDirs.elementAt(i).equals("**")) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ if (patIdxStart > patIdxEnd) {
+ // String not exhausted, but pattern is. Failure.
+ return false;
+ }
+ }
+
+ // up to last '**'
+ while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+ String patDir = (String)patDirs.elementAt(patIdxEnd);
+ if (patDir.equals("**")) {
+ break;
+ }
+ if (!match(patDir,(String)strDirs.elementAt(strIdxEnd),
+ isCaseSensitive)) {
+ return false;
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // String is exhausted
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (!patDirs.elementAt(i).equals("**")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+ int patIdxTmp = -1;
+ for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
+ if (patDirs.elementAt(i).equals("**")) {
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if (patIdxTmp == patIdxStart+1) {
+ // '**/**' situation, so skip one
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = (patIdxTmp-patIdxStart-1);
+ int strLength = (strIdxEnd-strIdxStart+1);
+ int foundIdx = -1;
+strLoop:
+ for (int i = 0; i <= strLength - patLength; i++) {
+ for (int j = 0; j < patLength; j++) {
+ String subPat = (String)patDirs.elementAt(patIdxStart+j+1);
+ String subStr = (String)strDirs.elementAt(strIdxStart+i+j);
+ if (!match(subPat,subStr, isCaseSensitive)) {
+ continue strLoop;
+ }
+ }
+
+ foundIdx = strIdxStart+i;
+ break;
+ }
+
+ if (foundIdx == -1) {
+ return false;
+ }
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx+patLength;
+ }
+
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (!patDirs.elementAt(i).equals("**")) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Tests whether or not a string matches against a pattern.
+ * The pattern may contain two special characters:<br>
+ * '*' means zero or more characters<br>
+ * '?' means one and only one character
+ *
+ * @param pattern The pattern to match against.
+ * Must not be <code>null</code>.
+ * @param str The string which must be matched against the pattern.
+ * Must not be <code>null</code>.
+ *
+ * @return <code>true</code> if the string matches against the pattern,
+ * or <code>false</code> otherwise.
+ */
+ public static boolean match(String pattern, String str) {
+ return match(pattern, str, true);
+ }
+
+ /**
+ * Tests whether or not a string matches against a pattern.
+ * The pattern may contain two special characters:<br>
+ * '*' means zero or more characters<br>
+ * '?' means one and only one character
+ *
+ * @param pattern The pattern to match against.
+ * Must not be <code>null</code>.
+ * @param str The string which must be matched against the pattern.
+ * Must not be <code>null</code>.
+ * @param isCaseSensitive Whether or not matching should be performed
+ * case sensitively.
+ *
+ *
+ * @return <code>true</code> if the string matches against the pattern,
+ * or <code>false</code> otherwise.
+ */
+ public static boolean match(String pattern, String str,
+ boolean isCaseSensitive) {
+ char[] patArr = pattern.toCharArray();
+ char[] strArr = str.toCharArray();
+ int patIdxStart = 0;
+ int patIdxEnd = patArr.length-1;
+ int strIdxStart = 0;
+ int strIdxEnd = strArr.length-1;
+ char ch;
+
+ boolean containsStar = false;
+ for (int i = 0; i < patArr.length; i++) {
+ if (patArr[i] == '*') {
+ containsStar = true;
+ break;
+ }
+ }
+
+ if (!containsStar) {
+ // No '*'s, so we make a shortcut
+ if (patIdxEnd != strIdxEnd) {
+ return false; // Pattern and string do not have the same size
+ }
+ for (int i = 0; i <= patIdxEnd; i++) {
+ ch = patArr[i];
+ if (ch != '?') {
+ if (isCaseSensitive && ch != strArr[i]) {
+ return false;// Character mismatch
+ }
+ if (!isCaseSensitive && Character.toUpperCase(ch) !=
+ Character.toUpperCase(strArr[i])) {
+ return false; // Character mismatch
+ }
+ }
+ }
+ return true; // String matches against pattern
+ }
+
+ if (patIdxEnd == 0) {
+ return true; // Pattern contains only '*', which matches anything
+ }
+
+ // Process characters before first star
+ while((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
+ if (ch != '?') {
+ if (isCaseSensitive && ch != strArr[strIdxStart]) {
+ return false;// Character mismatch
+ }
+ if (!isCaseSensitive && Character.toUpperCase(ch) !=
+ Character.toUpperCase(strArr[strIdxStart])) {
+ return false;// Character mismatch
+ }
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (patArr[i] != '*') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Process characters after last star
+ while((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
+ if (ch != '?') {
+ if (isCaseSensitive && ch != strArr[strIdxEnd]) {
+ return false;// Character mismatch
+ }
+ if (!isCaseSensitive && Character.toUpperCase(ch) !=
+ Character.toUpperCase(strArr[strIdxEnd])) {
+ return false;// Character mismatch
+ }
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (patArr[i] != '*') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // process pattern between stars. padIdxStart and patIdxEnd point
+ // always to a '*'.
+ while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+ int patIdxTmp = -1;
+ for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
+ if (patArr[i] == '*') {
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if (patIdxTmp == patIdxStart+1) {
+ // Two stars next to each other, skip the first one.
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = (patIdxTmp-patIdxStart-1);
+ int strLength = (strIdxEnd-strIdxStart+1);
+ int foundIdx = -1;
+ strLoop:
+ for (int i = 0; i <= strLength - patLength; i++) {
+ for (int j = 0; j < patLength; j++) {
+ ch = patArr[patIdxStart+j+1];
+ if (ch != '?') {
+ if (isCaseSensitive && ch != strArr[strIdxStart+i+j]) {
+ continue strLoop;
+ }
+ if (!isCaseSensitive && Character.toUpperCase(ch) !=
+ Character.toUpperCase(strArr[strIdxStart+i+j])) {
+ continue strLoop;
+ }
+ }
+ }
+
+ foundIdx = strIdxStart+i;
+ break;
+ }
+
+ if (foundIdx == -1) {
+ return false;
+ }
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx+patLength;
+ }
+
+ // All characters in the string are used. Check if only '*'s are left
+ // in the pattern. If so, we succeeded. Otherwise failure.
+ for (int i = patIdxStart; i <= patIdxEnd; i++) {
+ if (patArr[i] != '*') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Breaks a path up into a Vector of path elements, tokenizing on
+ * <code>File.separator</code>.
+ *
+ * @param path Path to tokenize. Must not be <code>null</code>.
+ *
+ * @return a Vector of path elements from the tokenized path
+ */
+ public static Vector tokenizePath (String path) {
+ Vector ret = new Vector();
+ StringTokenizer st = new StringTokenizer(path,File.separator);
+ while (st.hasMoreTokens()) {
+ ret.addElement(st.nextToken());
+ }
+ return ret;
+ }
+
+ /**
+ * Helper method which corrects paths to use forward slashes.
+ *
+ * @param pattern the path pattern which needs correcting
+ * @return corrected pattern
+ */
+ public static String fixPath(String pattern) {
+ return pattern.replace('/',File.separatorChar).replace('\\',
+ File.separatorChar);
+ }
+
+ /**
+ * Returns dependency information on these two files. If src has been
+ * modified later than target, it returns true. If target doesn't exist,
+ * it likewise returns true. Otherwise, target is newer than src and
+ * is not out of date, thus the method returns false. It also returns
+ * false if the src file doesn't even exist, since how could the
+ * target then be out of date.
+ *
+ * @param src the original file
+ * @param target the file being compared against
+ * @param granularity the amount in seconds of slack we will give in
+ * determining out of dateness
+ * @return whether the target is out of date
+ */
+ public static boolean isOutOfDate(File src, File target, int granularity) {
+ if (!src.exists()) {
+ return false;
+ }
+ if (!target.exists()) {
+ return true;
+ }
+ if ((src.lastModified() - granularity) > target.lastModified()) {
+ return true;
+ }
+ return false;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java b/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java
new file mode 100644
index 000000000..3ed87a44b
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java
@@ -0,0 +1,313 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Selector that filters files based on their size.
+ *
+ * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @since 1.5
+ */
+public class SizeSelector extends BaseExtendSelector {
+
+ private long size = -1;
+ private long multiplier = 1;
+ private long sizelimit = -1;
+ private int cmp = 0;
+ public final static String SIZE_KEY = "millis";
+ public final static String UNITS_KEY = "datetime";
+ public final static String WHEN_KEY = "when";
+
+ public SizeSelector() {
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("{sizeselector size: ");
+ buf.append(sizelimit);
+ buf.append("compare: ");
+ if (cmp == 0) {
+ buf.append("less");
+ }
+ else if (cmp == 1) {
+ buf.append("more");
+ } else {
+ buf.append("equal");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * A size selector needs to know what size to base its selecting on.
+ * This will be further modified by the multiplier to get an
+ * actual size limit.
+ *
+ * @param size the size to select against expressed in units
+ */
+ public void setSize(long size) {
+ this.size = size;
+ if ((multiplier != 0) && (size > -1)) {
+ sizelimit = size * multiplier;
+ }
+ }
+
+ /**
+ * Sets the units to use for the comparison. This is a little
+ * complicated because common usage has created standards that
+ * play havoc with capitalization rules. Thus, some people will
+ * use "K" for indicating 1000's, when the SI standard calls for
+ * "k". Others have tried to introduce "K" as a multiple of 1024,
+ * but that falls down when you reach "M", since "m" is already
+ * defined as 0.001.
+ * <p>
+ * To get around this complexity, a number of standards bodies
+ * have proposed the 2^10 standard, and at least one has adopted
+ * it. But we are still left with a populace that isn't clear on
+ * how capitalization should work.
+ * <p>
+ * We therefore ignore capitalization as much as possible.
+ * Completely mixed case is not possible, but all upper and lower
+ * forms are accepted for all long and short forms. Since we have
+ * no need to work with the 0.001 case, this practice works here.
+ * <p>
+ * This function translates all the long and short forms that a
+ * unit prefix can occur in and translates them into a single
+ * multiplier.
+ *
+ * @param units The units to compare the size to, using an
+ * EnumeratedAttribute
+ */
+ public void setUnits(ByteUnits units) {
+ int i = units.getIndex();
+ multiplier = 0;
+ if ((i > -1) && (i < 4)) {
+ multiplier = 1000;
+ }
+ else if ((i > 3) && (i < 9)) {
+ multiplier = 1024;
+ }
+ else if ((i > 8) && (i < 13)) {
+ multiplier = 1000000;
+ }
+ else if ((i > 12) && (i < 18)) {
+ multiplier = 1048576;
+ }
+ else if ((i > 17) && (i < 22)) {
+ multiplier = 1000000000L;
+ }
+ else if ((i > 21) && (i < 27)) {
+ multiplier = 1073741824L;
+ }
+ else if ((i > 26) && (i < 31)) {
+ multiplier = 1000000000000L;
+ }
+ else if ((i > 30) && (i < 36)) {
+ multiplier = 1099511627776L;
+ }
+ if ((multiplier > 0) && (size > -1)) {
+ sizelimit = size * multiplier;
+ }
+ }
+
+ /**
+ * This specifies when the file should be selected, whether it be
+ * when the file matches a particular size, when it is smaller,
+ * or whether it is larger.
+ *
+ * @param cmp The comparison to perform, an EnumeratedAttribute
+ */
+ public void setWhen(SizeComparisons cmp) {
+ this.cmp = cmp.getIndex();
+ }
+
+ /**
+ * When using this as a dynamic selector, this method will be called.
+ * It translates each parameter into the appropriate setXXX() call.
+ *
+ * @param parameters the complete set of parameters for this selector
+ */
+ public void setParameters(Parameter[] parameters) {
+ super.setParameters(parameters);
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ String paramname = parameters[i].getName();
+ if (SIZE_KEY.equalsIgnoreCase(paramname)) {
+ try {
+ setSize(new Long(parameters[i].getValue()
+ ).longValue());
+ } catch (NumberFormatException nfe) {
+ setError("Invalid size setting "
+ + parameters[i].getValue());
+ }
+ }
+ else if (UNITS_KEY.equalsIgnoreCase(paramname)) {
+ ByteUnits units = new ByteUnits();
+ units.setValue(parameters[i].getValue());
+ setUnits(units);
+ }
+ else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
+ SizeComparisons cmp = new SizeComparisons();
+ cmp.setValue(parameters[i].getValue());
+ setWhen(cmp);
+ }
+ else {
+ setError("Invalid parameter " + paramname);
+ }
+ }
+ }
+ }
+
+ /**
+ * <p>Checks to make sure all settings are kosher. In this case, it
+ * means that the size attribute has been set (to a positive value),
+ * that the multiplier has a valid setting, and that the size limit
+ * is valid. Since the latter is a calculated value, this can only
+ * fail due to a programming error.
+ * </p>
+ * <p>If a problem is detected, the setError() method is called.
+ * </p>
+ */
+ public void verifySettings() {
+ if (size < 0) {
+ setError("The size attribute is required, and must be positive");
+ }
+ else if (multiplier < 1) {
+ setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti");
+ }
+ else if (sizelimit < 0) {
+ setError("Internal error: Code is not setting sizelimit correctly");
+ }
+ }
+
+ /**
+ * The heart of the matter. This is where the selector gets to decide
+ * on the inclusion of a file in a particular fileset.
+ *
+ * @param basedir A java.io.File object for the base directory
+ * @param filename The name of the file to check
+ * @param file A File object for this filename
+ * @return whether the file should be selected or not
+ */
+ public boolean isSelected(File basedir, String filename, File file) {
+
+ // throw BuildException on error
+ validate();
+
+ // Directory size never selected for
+ if (file.isDirectory()) {
+ return true;
+ }
+ if (cmp == 0) {
+ return (file.length() < sizelimit);
+ }
+ else if (cmp == 1) {
+ return (file.length() > sizelimit);
+ }
+ else {
+ return (file.length() == sizelimit);
+ }
+ }
+
+
+
+ /**
+ * Enumerated attribute with the values for units.
+ * <p>
+ * This treats the standard SI units as representing powers of ten,
+ * as they should. If you want the powers of 2 that approximate
+ * the SI units, use the first two characters followed by a
+ * <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>,
+ * 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30)
+ * becomes <code>gibi</code>, and so on. The symbols are also
+ * accepted, and these are the first letter capitalized followed
+ * by an <code>i</code>. <code>Ki</code>, <code>Mi</code>,
+ * <code>Gi</code>, and so on. Capitalization variations on these
+ * are also accepted.
+ * <p>
+ * This binary prefix system is approved by the IEC and appears on
+ * its way for approval by other agencies, but it is not an SI
+ * standard. It disambiguates things for us, though.
+ */
+ public static class ByteUnits extends EnumeratedAttribute {
+ public String[] getValues() {
+ return new String[] {"K", "k", "kilo", "KILO",
+ "Ki", "KI", "ki", "kibi", "KIBI",
+ "M", "m", "mega", "MEGA",
+ "Mi", "MI", "mi", "mebi", "MEBI",
+ "G", "g", "giga", "GIGA",
+ "Gi", "GI", "gi", "gibi", "GIBI",
+ "T", "t", "tera", "TERA",
+ /* You wish! */ "Ti", "TI", "ti", "tebi", "TEBI"
+ };
+ }
+ }
+
+ /**
+ * Enumerated attribute with the values for size comparison.
+ */
+ public static class SizeComparisons extends EnumeratedAttribute {
+ public String[] getValues() {
+ return new String[] {"less", "more", "equal"};
+ }
+ }
+
+}
+