diff --git a/WHATSNEW b/WHATSNEW index e0ecaafc2..6b9a0201a 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -9,6 +9,8 @@ Other changes: * has a new srcfile attribute that can make it read properties files and output them instead of Ant's properties. +* will now resolve filters recursively. + Changes from Ant 1.4.1 to Ant 1.5 ================================= diff --git a/docs/manual/CoreTypes/filterset.html b/docs/manual/CoreTypes/filterset.html index a4b3fc00c..a0a8b3cff 100644 --- a/docs/manual/CoreTypes/filterset.html +++ b/docs/manual/CoreTypes/filterset.html @@ -19,6 +19,7 @@ children of endtoken attributes to define what to match.

Filtersets are used for doing replacements in tasks such as <copy>, etc.

+

Nested filters are possible and a message will be given in case a value in a filter chain is called for a second time and thus causing an infinite loop. The originating token will be passed back when an infinite loop occurs.

Filterset

diff --git a/src/main/org/apache/tools/ant/types/FilterSet.java b/src/main/org/apache/tools/ant/types/FilterSet.java index 75beed3d7..1e2ed7998 100644 --- a/src/main/org/apache/tools/ant/types/FilterSet.java +++ b/src/main/org/apache/tools/ant/types/FilterSet.java @@ -75,6 +75,7 @@ import org.apache.tools.ant.Project; * A filter set may have begintoken and endtokens defined. * * @author Michael McCallum + * @author Martin van den Bemt */ public class FilterSet extends DataType implements Cloneable { @@ -354,6 +355,10 @@ public class FilterSet extends DataType implements Cloneable { b.append(line.substring(i, index)); if (tokens.containsKey(token)) { value = (String) tokens.get(token); + if (!value.equals(token)) { + // we have another token, let's parse it. + value = replaceTokens(value, token); + } log("Replacing: " + beginToken + token + endToken + " -> " + value, Project.MSG_VERBOSE); b.append(value); @@ -376,6 +381,54 @@ public class FilterSet extends DataType implements Cloneable { } } + /** Contains a list of parsed tokens */ + private Vector passedTokens; + /** if a ducplicate token is found, this is set to true */ + private boolean duplicateToken = false; + + /** + * This parses tokens which point to tokens. + * It also maintains a list of currently used tokens, so we cannot + * get into an infinite loop + * @param value the value / token to parse + * @param parent the parant token (= the token it was parsed from) + */ + private String replaceTokens(String line, String parent) + throws BuildException + { + if (passedTokens == null) { + passedTokens = new Vector(); + } + if (passedTokens.contains(parent) && !duplicateToken) { + duplicateToken = true; + StringBuffer sb = new StringBuffer(); + sb.append("Inifinite loop in tokens. Currently known tokens : "); + sb.append(passedTokens); + sb.append("\nProblem token : "+getBeginToken()+parent+getEndToken()); + sb.append(" called from "+getBeginToken()+passedTokens.lastElement()); + sb.append(getEndToken()); + System.out.println(sb.toString()); + return parent; + } + passedTokens.addElement(parent); + String value = this.replaceTokens(line); + if (value.indexOf(getBeginToken()) == -1 && !duplicateToken) { + duplicateToken = false; + passedTokens = null; + } else if(duplicateToken) { + // should always be the case... + if (passedTokens.size() > 0) { + value = (String) passedTokens.lastElement(); + passedTokens.removeElementAt(passedTokens.size()-1); + if (passedTokens.size() == 0) { + value = getBeginToken()+value+getEndToken(); + duplicateToken = false; + } + } + } + return value; + } + /** * Create a new filter * diff --git a/src/testcases/org/apache/tools/ant/types/FilterSetTest.java b/src/testcases/org/apache/tools/ant/types/FilterSetTest.java index da1311ccd..c31dd182e 100644 --- a/src/testcases/org/apache/tools/ant/types/FilterSetTest.java +++ b/src/testcases/org/apache/tools/ant/types/FilterSetTest.java @@ -67,6 +67,7 @@ import java.io.*; * FilterSet testing * * @author Conor MacNeill + * @author Martin van den Bemt */ public class FilterSetTest extends BuildFileTest { @@ -102,6 +103,42 @@ public class FilterSetTest extends BuildFileTest { "src/etc/testcases/types/dest3.txt")); } + /** + * This will test the recursive FilterSet. Which means that if + * the filter value @test@ contains another filter value, it will + * actually resolve. + */ + public void testRecursive() { + System.out.println("testRecursive"); + String result = "it works line"; + String line="@test@ line"; + FilterSet fs = new FilterSet(); + fs.addFilter("test", "@test1@"); + fs.addFilter("test1","@test2@"); + fs.addFilter("test2", "it works"); + fs.setBeginToken("@"); + fs.setEndToken("@"); + assertEquals(result, fs.replaceTokens(line)); + } + + /** + * Test to see what happens when the resolving occurs in an + * infinite loop. + */ + public void testInfinite() { + System.out.println("testInfinite"); + String result = "@test@ line testvalue"; + String line = "@test@ line @test3@"; + FilterSet fs = new FilterSet(); + fs.addFilter("test", "@test1@"); + fs.addFilter("test1","@test2@"); + fs.addFilter("test2", "@test@"); + fs.addFilter("test3", "testvalue"); + fs.setBeginToken("@"); + fs.setEndToken("@"); + assertEquals(result, fs.replaceTokens(line)); + } + private boolean compareFiles(String name1, String name2) { File file1 = new File(name1); File file2 = new File(name2);