umagesh 2003/04/14 11:02:24
Modified: . WHATSNEW build.xml
docs/manual/CoreTypes filterchain.html
src/main/org/apache/tools/ant/types FilterChain.java
defaults.properties
Added: src/etc/testcases/filters dynamicfilter.xml tokenfilter.xml
src/main/org/apache/tools/ant/filters TokenFilter.java
src/main/org/apache/tools/ant/types/optional
ScriptFilter.java
src/testcases/org/apache/tools/ant/filters
DynamicFilterTest.java TokenFilterTest.java
Log:
New tokenfilter for filterchain
PR: 18312
Submitted by: [EMAIL PROTECTED] (peter reilly)
Revision Changes Path
1.398 +3 -0 ant/WHATSNEW
Index: WHATSNEW
===================================================================
RCS file: /home/cvs/ant/WHATSNEW,v
retrieving revision 1.397
retrieving revision 1.398
diff -u -r1.397 -r1.398
--- WHATSNEW 14 Apr 2003 15:41:38 -0000 1.397
+++ WHATSNEW 14 Apr 2003 18:02:23 -0000 1.398
@@ -99,6 +99,9 @@
Other changes:
--------------
+* A new filter reader namely tokenfilter has been added. Bugzilla
+ Report 18312.
+
* A new attribute named skip is added to the TailFilter and
HeadFilter filter readers.
1.364 +4 -1 ant/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/ant/build.xml,v
retrieving revision 1.363
retrieving revision 1.364
diff -u -r1.363 -r1.364
--- build.xml 10 Apr 2003 06:47:24 -0000 1.363
+++ build.xml 14 Apr 2003 18:02:23 -0000 1.364
@@ -202,7 +202,10 @@
<filename name="${ant.package}/listener/CommonsLoggingListener*"/>
</selector>
<selector id="needs.bsf">
- <filename name="${optional.package}/Script*"/>
+ <or>
+ <filename name="${optional.package}/Script*"/>
+ <filename name="${optional.type.package}/Script*"/>
+ </or>
</selector>
<selector id="needs.stylebook">
<filename name="${optional.package}/StyleBook*"/>
1.7 +477 -1 ant/docs/manual/CoreTypes/filterchain.html
Index: filterchain.html
===================================================================
RCS file: /home/cvs/ant/docs/manual/CoreTypes/filterchain.html,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- filterchain.html 14 Apr 2003 15:37:44 -0000 1.6
+++ filterchain.html 14 Apr 2003 18:02:23 -0000 1.7
@@ -101,6 +101,8 @@
<a href="#striplinecomments">StripLineComments</a><BR>
<a href="#tabstospaces">TabsToSpaces</a><BR>
<a href="#tailfilter">TailFilter</a><BR>
+<a href="#deletecharacters">DeleteCharacters</a><BR>
+<a href="#tokenfilter">TokenFilter</a><BR>
<H3><a name="filterreader">FilterReader</a></H3>
@@ -552,7 +554,7 @@
This removes all lines that begin with #, --, REM, rem and //
<BLOCKQUOTE><PRE>
<filterreader
classname="org.apache.tools.ant.filters.StripLineComments">
- <param type="comment" value="#"/>
+ <param type="comment" value="e;#"/>
<param type="comment" value="--"/>
<param type="comment" value="REM "/>
<param type="comment" value="rem "/>
@@ -785,6 +787,480 @@
</filterchain>
</loadfile>
</PRE></BLOCKQUOTE>
+
+<H3><a name="deletecharacters">DeleteCharacters</a></H3>
+
+ <p>This filter deletes specified characters.</p>
+ <p><em>since Ant 1.6</em></p>
+ <p>This filter is only available in the convenience form.</p>
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Parameter Name</B></TD>
+ <TD vAlign=top><B>Parameter Value</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>chars</TD>
+ <TD vAlign=top>
+ The characters to delete. This attribute is
+ <a href="#backslash">backslash enabled</a>.
+ </TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+</TABLE>
+<P>
+<H4>Examples:</H4>
+
+Delete tabs and returns from the data.
+<BLOCKQUOTE><PRE>
+<deletecharacters chars="\t\r"/>
+</PRE></BLOCKQUOTE>
+
+
+<H3><a name="tokenfilter">TokenFilter</a></H3>
+This filter tokenizes the inputstream into strings and passes these
+strings to filters of strings. Unlike the other filterreaders, this does
+not support params, only convenience methods are implemented.
+The tokenizer and the string filters are defined by nested elements.
+<P><em>since Ant 1.6</em></p>
+<P>
+Only one tokenizer element may be used, the LineTokenizer is the
+default if none are specified. A tokenizer
+splits the input into token strings and trailing delimiter strings.
+<P>
+There may be zero or more string filters. A string filter processes
+a token and either returns a string or a null.
+It the string is not null it is passed to the next filter. This
+proceeds until all the filters are called.
+If a string is returned after all the filters, the string is
+outputs with its associated token delimitier
+(if one is present).
+The trailing delimiter may be overridden by the <i>delimOutput</i>
+attribute.
+<P>
+<a name="backslash"><em>blackslash interpretation</em></a>
+A number of attributes (including <i>delimOutput</i>) interpret
+backslash escapes. The following are understood: \n, \r, \f, \t
+and \\.
+
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>delimOutput</TD>
+ <TD vAlign=top>
+ This overrides the tokendelimiter
+ returned by the tokenizer if it is not empty. This
+ attribute is backslash enabled.
+</TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+</TABLE>
+<P>
+
+ The following tokenizers are provided by the default distribution.
+ <p>
+ <a href="#linetokenizer">LineTokenizer</a><br>
+ <a href="#filetokenizer">FileTokenizer</a><br>
+ <a href="#stringtokenizer">StringTokenizer</a><br>
+ </p>
+
+ The following string filters are provided by the default distribution.
+ <p>
+ <a href="#replacestring">ReplaceString</a><br>
+ <a href="#containsstring">ContainsString</a><br>
+ <a href="#replaceregex">ReplaceRegex</a><br>
+ <a href="#containsregex">ContainsRegex</a><br>
+ <a href="#trim">Trim</a><br>
+ <a href="#ignoreblank">IgnoreBlank</a><br>
+ <a href="#filterdeletecharacters">DeleteCharacters</a><br>
+ </p>
+
+ The following string filters are provided by the optional distribution.
+ <p>
+ <a href="#scriptfilter">ScriptFilter</a><br>
+ </p>
+
+Some of the filters may be used directly within a filter chain. In this
+case a tokenfilter is created implicitly. An extra attribute "byline"
+is added to the filter to specify whether to use a linetokenizer
+(byline="true") or a filetokenizer (byline="false"). The default
+is "true".
+<P>
+
+<p><b><em><a name="linetokenizer">LineTokenizer</a></em></b></p>
+This tokenizer splits the input into lines.
+The tokenizer delimits lines
+by "\r", "\n" or "\r\n".
+This is the default tokenizer.
+<H4>Examples:</H4>
+
+Convert input current line endings to unix style line endings.
+<em>This currently has no effect when used in the copy task.</em>
+<BLOCKQUOTE><PRE>
+<tokenfilter delimoutput="\n"/>
+</PRE></BLOCKQUOTE>
+
+
+Remove blank lines.
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <ignoreblank/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="filetokenizer">FileTokenizer</a></em></b></p>
+This tokenizer treats <b>all</b> the input as a token. So be
+careful not to use this on very large input.
+<H4>Examples:</H4>
+
+Replace the first occurance of package with //package.
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <filetokenizer/>
+ <replaceregex pattern="([\n\r]+[ \t]*|^[ \t]*)package"
+ flags="s"
+ replace="\1//package"/>
+</tokenfilter>
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="stringtokenizer">StringTokenizer</a></em></b></p>
+This tokenizer is based on java.util.StringTokenizer.
+It splits up the input into strings separated by white space, or
+by a specified list of delimiting characters.
+If the stream starts with delimiter characters, the first
+token will be the empty string (unless the <i>delimsaretokens</i>
+attribute is used).
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>delims</TD>
+ <TD vAlign=top>The delimiter characters. White space
+ is used if this is not set. (White space is defined
+ in this case by java.lang.Character.isWhitespace()).
+ </TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+ <tr>
+ <td valign="top">delimsaretokens</td>
+ <td valign="top">If this is true,
+ each delimiter character is returned as a token</td>
+ <td valign="top" align="center">No</td>
+ </tr>
+ <tr>
+ <td valign="top">suppressdelims</td>
+ <td valign="top">If this is true, delimiters are not returned. </td>
+ <td valign="top" align="center">No</td>
+ </tr>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Surround each non space token with a "[]".
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <stringtokenizer/>
+ <replaceregex pattern="(.+)" replace="[\1]"/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="replacestring">ReplaceString</a></em></b></p>
+This is a simple filter to replace strings.
+This filter may be used directly within a filterchain.
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>from</TD>
+ <TD vAlign=top>The string that must be replaced.</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+ <tr>
+ <td valign="top">to</td>
+ <td valign="top">The new value for the replaced string. When omitted
+ an empty string is used.
+ </td>
+ <td valign="top" align="center">No</td>
+ </tr>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Replace "sun" with "moon".
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <replacestring from="sun" to="moon"/>
+</tokenfilter>
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="containsstring">ContainsString</a></em></b></p>
+This is a simple filter to filter tokens that contains
+a specified string.
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>contains</TD>
+ <TD vAlign=top>The string that the token must contain.</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Include only lines that contain "foo";
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <containsstring contains="foo"/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="replaceregex">ReplaceRegex</a></em></b></p>
+This string filter replaces regular expressions. See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation on regular expressions.
+This filter may be used directly within a filterchain.
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>pattern</TD>
+ <TD vAlign=top>The regular expression pattern to match in
+ the token.</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>replace</TD>
+ <TD vAlign=top>The substitution pattern to replace the matched
+ regular expression. When omitted an empty string is used.</TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>flags</TD>
+ <TD vAlign=top>See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation of regex flags.</TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Replace all occurances of "hello" with "world", ignoring case.
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <replaceregex pattern="hello" replace="world" flags="gi"/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="containsregex">ContainsRegex</a></em></b></p>
+This filters strings that match regular expressions.
+The filter may optionally replace the matched regular expression.
+See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation on regular expressions.
+This filter may be used directly within a filterchain.
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>pattern</TD>
+ <TD vAlign=top>The regular expression pattern to match in
+ the token.</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>replace</TD>
+ <TD vAlign=top>The substitution pattern to replace the matched
+ regular expression. When omitted the orignal token is returned.
+ </TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>flags</TD>
+ <TD vAlign=top>See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation of regex flags.</TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Filter lines that contain "hello" or "world", ignoring case.
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <containsregex pattern="(hello|world)" flags="i"/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+This example replaces lines like "SUITE(TestSuite, bits);" with
+"void register_bits();" and removes other lines.
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <containsregex
+ pattern="^ *SUITE\(.*,\s*(.*)\s*\).*"
+ replace="void register_\1();"/>
+</tokenfilter>
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="trim">Trim</a></em></b></p>
+This filter trims whitespace from the start and end of
+tokens.
+This filter may be used directly within a filterchain.
+<p><b><em><a name="ignoreblank">IgnoreBlank</a></em></b></p>
+This filter removes empty tokens.
+This filter may be used directly within a filterchain.
+<p><b><em><a name="filterdeletecharacters">DeleteCharacters</a></em></b></p>
+This filter deletes specified characters from tokens.
+
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>chars</TD>
+ <TD vAlign=top>The characters to delete. This attribute
+ is backslash enabled.</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Delete tabs from lines, trim the lines and removes empty lines.
+
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <deletecharacters chars="\t"/>
+ <trim/>
+ <ignoreblank/>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<p><b><em><a name="scriptfilter">ScriptFilter</a></em></b></p>
+This is an optional filter that executes a script in a
+<a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+supported language.</p>
+See the <a href="../OptionalTasks/script.html">Script</a> task for
+an explanation of scripts and dependencies.
+</p>
+<p>
+The script is provided with an object <i>self</i> that has
+getToken() and setToken(String) methods.
+</p>
+
+This filter may be used directly within a filterchain.<p>
+<TABLE cellSpacing=0 cellPadding=2 border=1>
+ <TR>
+ <TD vAlign=top><B>Attribute</B></TD>
+ <TD vAlign=top><B>Description</B></TD>
+ <TD vAlign=top align="center"><B>Required</B></TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>language</TD>
+ <TD vAlign=top> The programming language the script is written in.
+Must be a supported Apache BSF language</TD>
+ <TD vAlign=top align="center">Yes</TD>
+ </TR>
+ <TR>
+ <TD vAlign=top>src</TD>
+ <TD vAlign=top>The location of the script as a file, if not inline
+ </TD>
+ <TD vAlign=top align="center">No</TD>
+ </TR>
+ <TR>
+</TABLE>
+
+<H4>Examples:</H4>
+
+Convert to uppercase.
+<BLOCKQUOTE><PRE>
+<tokenfilter>
+ <scriptfilter language="javascript">
+ self.setToken(self.getToken().toUpperCase());
+ </scriptfilter>
+</tokenfilter>
+
+</PRE></BLOCKQUOTE>
+
+<H4>Custom tokenizers and string filters</H4>
+
+Custom string filters and tokenizers may be plugged in by
+extending the interfaces org.apache.tools.ant.filters.TokenFilter.Filter
+and org.apache.tools.ant.filters.TokenFilter.Tokenizer respectly.
+
+They are defined the build file using <typedef/>. For
+example a string filter that capitalizes words may be declared as:
+<blockquote><pre>
+package my.customant;
+import org.apache.tools.ant.filters.TokenFilter;
+
+public class Capitalize
+ implements TokenFilter.Filter
+{
+ public String filter(String token) {
+ if (token.length() == 0)
+ return token;
+ return token.substring(0, 1).toUpperCase() +
+ token.substring(1);
+ }
+}
+</pre></blockquote>
+
+This may be used as follows:
+<blockquote><pre>
+ <typedef type="capitalize" classname="my.customant.Capitalize"
+ classpath="my.customant.path"/>
+ <copy file="input" tofile="output">
+ <filterchain>
+ <tokenfilter>
+ <stringtokenizer/>
+ <capitalize/>
+ </tokenfilter>
+ </filterchain>
+ </copy>
+</pre></blockquote>
<HR>
1.1 ant/src/etc/testcases/filters/dynamicfilter.xml
Index: dynamicfilter.xml
===================================================================
<?xml version="1.0"?>
<project default="cleanup" basedir=".">
<target name="init">
<mkdir dir="result" />
</target>
<target name="cleanup">
<delete dir="result"/>
</target>
<target name="dynamicfilter">
<path id="test-classes">
<pathelement location="../../../../build/testcases" />
<pathelement path="${java.class.path}" />
</path>
<typedef
name="customfilter"
classname="org.apache.tools.ant.filters.DynamicFilterTest$CustomFilter">
<classpath refid="test-classes"/>
</typedef>
<concat destfile="result/input">
hello world
</concat>
<copy file="result/input" tofile="result/dynamicfilter">
<filterchain>
<customfilter replace="o" with="O"/>
</filterchain>
</copy>
</target>
</project>
1.1 ant/src/etc/testcases/filters/tokenfilter.xml
Index: tokenfilter.xml
===================================================================
<?xml version="1.0"?>
<project default="cleanup" basedir=".">
<target name="init">
<mkdir dir="result" />
</target>
<target name="cleanup">
<delete dir="result"/>
</target>
<target name="tokenfilter">
<copy file="input/linecontains.test" tofile="result/file1">
<filterchain>
<tokenfilter/>
</filterchain>
</copy>
</target>
<target name="trimignore">
<concat destfile="result/input">
Hello
World
</concat>
<copy file="result/input" tofile="result/output" overwrite="yes">
<filterchain>
<tokenfilter delimoutput="-">
<trim/>
<ignoreblank/>
</tokenfilter>
</filterchain>
</copy>
<concat>
<filelist dir="." files="result/output"/>
</concat>
</target>
<target name="trimfile">
<concat destfile="result/trimfile">
This is the contents of the trimmed file.
This is the second line.
<filterchain>
<trim byline="no"/>
</filterchain>
</concat>
</target>
<target name="trimfilebyline">
<concat destfile="result/trimfilebyline">
This is the contents of the trimmed file.
This is the second line.
<filterchain>
<trim/>
<tokenfilter delimoutput="\n"/>
</filterchain>
</concat>
</target>
<target name="filterreplacestring">
<concat destfile="result/filterreplacestring">
This is foo bar
<filterchain>
<replacestring from="foo" to="the"/>
<replacestring from="bar" to="moon"/>
</filterchain>
</concat>
</target>
<target name="stringtokenizer">
<concat destfile="result/input">
This is a number
of words
</concat>
<copy file="result/input" tofile="result/output" overwrite="yes">
<filterchain>
<tokenfilter delimoutput="#">
<stringtokenizer/>
</tokenfilter>
</filterchain>
</copy>
<concat>
<filelist dir="." files="result/output"/>
</concat>
</target>
<target name="unixlineoutput">
<concat destfile="result/unixlineoutput">
This is a number
of words
<filterchain>
<tokenfilter delimoutput="\n">
<stringtokenizer/>
</tokenfilter>
</filterchain>
</concat>
</target>
<target name="doslineoutput">
<concat destfile="result/doslineoutput">
This is a number
of words
<filterchain>
<tokenfilter delimoutput="\r\n">
<stringtokenizer/>
</tokenfilter>
</filterchain>
</concat>
</target>
<target name="filetokenizer">
<concat destfile="result/input">
This is a number
of words
</concat>
<copy file="result/input" tofile="result/filetokenizer">
<filterchain>
<tokenfilter>
<filetokenizer/>
<trim/>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="replacestring">
<concat destfile="result/replacestring">
this is the sun
<filterchain>
<tokenfilter>
<replacestring from="sun" to="moon"/>
</tokenfilter>
</filterchain>
</concat>
</target>
<target name="containsstring">
<concat destfile="result/input">
this is a line contains foo
this line does not
</concat>
<copy file="result/input" tofile="result/containsstring">
<filterchain>
<tokenfilter>
<containsstring contains="foo"/>
</tokenfilter>
</filterchain>
</copy>
</target>
<!-- need to check for existance of regex -->
<target name="replaceregex">
<concat destfile="result/input">
hello Hello HELLO hello
cat Cat cat
Sun Sun Sun
WhiteSpace tab
This is a line with digits - 1234 -- there
</concat>
<copy file="result/input" tofile="result/replaceregex">
<filterchain>
<tokenfilter>
<replaceregex pattern="hello" replace="world" flags="gi"/>
<replaceregex pattern="cat" replace="dog" flags="g"/>
<replaceregex pattern="sun" replace="moon" flags="i"/>
<replaceregex pattern="WhiteSpace[ \t]+tab"
replace="found WhiteSpace"/>
<replaceregex pattern="This is a line with dig.* ([0-9]+).*"
replace="Found digits [\1]"/>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="filterreplaceregex">
<concat destfile="result/filterreplaceregex">
hello Hello HELLO hello
<filterchain>
<replaceregex pattern="hello" replace="world" flags="gi"/>
</filterchain>
</concat>
</target>
<!-- need to check for existance of regex -->
<target name="containsregex">
<concat destfile="result/input">
hello world
this is the moon
World here
</concat>
<copy file="result/input" tofile="result/containsregex">
<filterchain>
<tokenfilter>
<containsregex pattern="(hello|world)" flags="i"/>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="filtercontainsregex">
<concat destfile="result/filtercontainsregex">
hello world
this is the moon
World here
<filterchain>
<tokenfilter>
<containsregex pattern="(hello|world)" flags="i"/>
</tokenfilter>
</filterchain>
</concat>
</target>
<!-- need to check for existance of regex -->
<target name="containsregex2">
<concat destfile="result/input">
SUITE(TestSuite, bits);
here
</concat>
<copy file="result/input" tofile="result/containsregex2">
<filterchain>
<tokenfilter>
<containsregex
pattern="^ *SUITE\(.*,\s*(.*)\s*\).*"
replace="void register_\1();"/>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="deletecharacters">
<concat destfile="result/deletechars">
This is some ### s
some ****
<filterchain>
<tokenfilter>
<deletecharacters chars="#"/>
</tokenfilter>
<deletecharacters chars="*"/>
</filterchain>
</concat>
</target>
<target name="scriptfilter">
<concat destfile="result/input">
hello world
</concat>
<copy file="result/input" tofile="result/scriptfilter">
<filterchain>
<tokenfilter>
<scriptfilter language="javascript">
self.setToken(self.getToken().toUpperCase());
</scriptfilter>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="scriptfilter2">
<concat destfile="result/input">
hello moon
</concat>
<copy file="result/input" tofile="result/scriptfilter2">
<filterchain>
<scriptfilter language="javascript">
self.setToken(self.getToken().toUpperCase());
</scriptfilter>
</filterchain>
</copy>
</target>
<target name="customtokenfilter">
<path id="test-classes">
<pathelement location="../../../../build/testcases" />
<pathelement path="${java.class.path}" />
</path>
<typedef
name="capitalize"
classname="org.apache.tools.ant.filters.TokenFilterTest$Capitalize">
<classpath refid="test-classes"/>
</typedef>
<concat destfile="result/input">
hello world
</concat>
<copy file="result/input" tofile="result/custom">
<filterchain>
<tokenfilter>
<stringtokenizer/>
<capitalize/>
</tokenfilter>
</filterchain>
</copy>
</target>
<target name="hasscript">
<script language="beanshell">
i = 1;
</script>
</target>
<target name="hasregex">
<concat destfile="result/replaceregexp">
hello world
</concat>
<replaceregexp file="result/replaceregexp"
match="hello( )world"
replace="bye\1world"/>
</target>
</project>
1.1
ant/src/main/org/apache/tools/ant/filters/TokenFilter.java
Index: TokenFilter.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 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 "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 [EMAIL PROTECTED]
*
* 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.filters;
import java.io.IOException;
import java.io.Reader;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicConfigurator;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Parameter;
import org.apache.tools.ant.types.RegularExpression;
import org.apache.tools.ant.types.Substitution;
import org.apache.tools.ant.util.regexp.Regexp;
/**
* This splits up input into tokens and passes
* the tokens to a sequence of filters.
*
* @author Peter Reilly
* @since Ant 1.6
* @see BaseFilterReader
* @see ChainableReader
* @see DynamicConfigurator
*/
public class TokenFilter
extends BaseFilterReader
implements ChainableReader, DynamicConfigurator
{
/**
* input stream tokenizers implement this interface
*/
public interface Tokenizer {
/**
* get the next token from the input stream
* @param in the input stream
* @return the next token, or null for the end
* of the stream
*/
public String getToken(Reader in)
throws IOException;
/**
* return the string between tokens, after the
* previous token.
* @return the intra-token string
*/
public String getPostToken();
}
/**
* string filters implement this interface
*/
public interface Filter {
/**
* filter and/of modify a string
*
* @param filter the string to filter
* @return the modified string or null if the
* string did not pass the filter
*/
public String filter(String string);
}
/** string filters */
private Vector filters = new Vector();
/** the tokenizer to use on the input stream */
private Tokenizer tokenizer = null;
/** the output token termination */
private String delimOutput = null;
/** the current string token from the input stream */
private String line = null;
/** the position in the current string token */
private int linePos = 0;
/**
* Constructor for "dummy" instances.
*
* @see BaseFilterReader#BaseFilterReader()
*/
public TokenFilter() {
super();
}
/**
* Creates a new filtered reader.
*
* @param in A Reader object providing the underlying stream.
* Must not be <code>null</code>.
*/
public TokenFilter(final Reader in) {
super(in);
}
/**
* Returns the next character in the filtered stream, only including
* lines from the original stream which match all of the specified
* regular expressions.
*
* @return the next character in the resulting stream, or -1
* if the end of the resulting stream has been reached
*
* @exception IOException if the underlying stream throws an IOException
* during reading
*/
public int read() throws IOException {
if (tokenizer == null)
tokenizer = new LineTokenizer();
while (line == null || line.length() == 0) {
line = tokenizer.getToken(in);
if (line == null)
return -1;
for (Enumeration e = filters.elements(); e.hasMoreElements();)
{
Filter filter = (Filter) e.nextElement();
line = filter.filter(line);
if (line == null)
break;
}
linePos = 0;
if (line != null) {
if (tokenizer.getPostToken().length() != 0) {
if (delimOutput != null)
line = line + delimOutput;
else
line = line + tokenizer.getPostToken();
}
}
}
int ch = line.charAt(linePos);
linePos ++;
if (linePos == line.length())
line = null;
return ch;
}
/**
* Creates a new TokenFilter using the passed in
* Reader for instantiation.
*
* @param reader A Reader object providing the underlying stream.
*
* @return a new filter based on this configuration
*/
public final Reader chain(final Reader reader) {
TokenFilter newFilter = new TokenFilter(reader);
newFilter.filters = filters;
newFilter.tokenizer = tokenizer;
newFilter.delimOutput = delimOutput;
newFilter.setProject(getProject());
return newFilter;
}
/**
* set the output delimitor.
* @param delimOutput replaces the delim string returned by the
* tokenizer, it it present.
*/
public void setDelimOutput(String delimOutput) {
this.delimOutput = resolveBackSlash(delimOutput);
}
// -----------------------------------------
// Predefined tokenizers
// -----------------------------------------
/**
* add a line tokenizer - this is the default.
*/
public void addLineTokenizer(LineTokenizer tokenizer) {
if (this.tokenizer != null)
throw new BuildException("Only one tokenizer allowed");
this.tokenizer = tokenizer;
}
/**
* add a string tokenizer
*/
public void addStringTokenizer(StringTokenizer tokenizer) {
if (this.tokenizer != null)
throw new BuildException("Only one tokenizer allowed");
this.tokenizer = tokenizer;
}
/**
* add a file tokenizer
*/
public void addFileTokenizer(FileTokenizer tokenizer) {
if (this.tokenizer != null)
throw new BuildException("Only one tokenizer allowed");
this.tokenizer = tokenizer;
}
// -----------------------------------------
// Predefined filters
// -----------------------------------------
/** replace string filter */
public void addReplaceString(ReplaceString filter) {
filters.addElement(filter);
}
/** contains string filter */
public void addContainsString(ContainsString filter) {
filters.addElement(filter);
}
/** replace regex filter */
public void addReplaceRegex(ReplaceRegex filter) {
filters.addElement(filter);
}
/** contains regex filter */
public void addContainsRegex(ContainsRegex filter) {
filters.addElement(filter);
}
/** trim filter */
public void addTrim(Trim filter) {
filters.addElement(filter);
}
/** ignore blank filter */
public void addIgnoreBlank(IgnoreBlank filter) {
filters.addElement(filter);
}
/** delete chars */
public void addDeleteCharacters(DeleteCharacters filter) {
filters.addElement(filter);
}
public void add(Filter filter) {
filters.addElement(filter);
}
/**
* create the named datatype and check if it
* is a filter or a tokenizer
*
* @throws BuildException if unknown datatype or incorrect datatype
*/
public Object createDynamicElement(String name)
{
if (getProject() == null)
throw new BuildException(
"createDynamicElement.TokenFilter" +
" - Unable to get the project");
Object obj = getProject().createDataType(name);
if (obj == null)
throw new BuildException("Unknown type " + name);
if (obj instanceof Filter)
filters.addElement(obj);
else if (obj instanceof Tokenizer) {
if (this.tokenizer != null)
throw new BuildException("Only one tokenizer allowed");
tokenizer = (Tokenizer) obj;
}
else
throw new BuildException(
"type " + name + " is not a TokenFilter.Filter or " +
"TokenFiler.Tokenizer");
return obj;
}
/**
* Needed for dynamic element support.
*
* @throws BuildException always
*/
public void setDynamicAttribute(String name, String value) {
throw new BuildException("Unknown attribute " + name);
}
// --------------------------------------------
//
// Tokenizer Classes
//
// --------------------------------------------
/**
* class to read the complete input into a string
*/
public static class FileTokenizer
implements Tokenizer
{
/**
* Get the complete input as a string
*
* @return the complete input
*/
public String getToken(Reader in)
throws IOException
{
StringBuffer output = new StringBuffer();
char[] buffer = new char[8192];
while (true) {
int nread = in.read(buffer, 0, 8192);
if (nread == -1)
break;
output.append(buffer, 0, nread);
}
if (output.length() == 0)
return null;
return output.toString();
}
/**
* Return an empty string
*
* @return an empty string
*/
public String getPostToken() {
return "";
}
}
/**
* class to tokenize the input as lines seperated
* by \r (mac style), \r\n (dos/windows style) or \n (unix style)
*/
public static class LineTokenizer
implements Tokenizer
{
String lineEnd = "";
int pushed = -2;
public String getToken(Reader in)
throws IOException
{
int ch = -1;
if (pushed != -2) {
ch = pushed;
pushed = -2;
}
else
ch = in.read();
if (ch == -1) {
return null;
}
lineEnd = "";
StringBuffer line = new StringBuffer();
int state = 0;
while (ch != -1) {
if (state == 0) {
if (ch == '\r') {
state = 1;
}
else if (ch == '\n') {
lineEnd = "\n";
break;
}
else {
line.append((char) ch);
}
}
else {
state = 0;
if (ch == '\n') {
lineEnd = "\r\n";
}
else {
pushed = ch;
lineEnd = "\r";
}
break;
}
ch = in.read();
}
if (ch == -1 && state == 1) {
lineEnd = "\r";
}
return line.toString();
}
public String getPostToken() {
return lineEnd;
}
}
/**
* class to tokenize the input as areas seperated
* by white space, or by a specified list of
* delim characters. Behaves like java.util.StringTokenizer.
* if the stream starts with delim characters, the first
* token will be an empty string (unless the treat tokens
* as delims flag is set).
*/
public static class StringTokenizer
implements Tokenizer
{
private String intraString = "";
private int pushed = -2;
private char[] delims = null;
private boolean delimsAreTokens = false;
private boolean suppressDelims = false;
public void setDelims(String delims) {
this.delims = resolveBackSlash(delims).toCharArray();
}
public void setDelimsAreTokens(boolean delimsAreTokens) {
this.delimsAreTokens = delimsAreTokens;
}
public void setSuppressDelims(boolean suppressDelims) {
this.suppressDelims = suppressDelims;
}
public String getToken(Reader in)
throws IOException
{
int ch = -1;
if (pushed != -2) {
ch = pushed;
pushed = -2;
}
else
ch = in.read();
if (ch == -1) {
return null;
}
boolean inToken = true;
intraString = "";
StringBuffer word = new StringBuffer();
StringBuffer padding = new StringBuffer();
while (ch != -1) {
char c = (char) ch;
boolean isDelim = isDelim(c);
if (inToken) {
if (isDelim) {
if (delimsAreTokens) {
if (word.length() == 0) {
word.append(c);
}
else {
pushed = ch;
}
break;
}
padding.append(c);
inToken = false;
}
else
word.append(c);
}
else {
if (isDelim) {
padding.append(c);
}
else {
pushed = ch;
break;
}
}
ch = in.read();
}
intraString = padding.toString();
return word.toString();
}
public String getPostToken() {
if (suppressDelims)
return "";
return intraString;
}
private boolean isDelim(char ch) {
if (delims == null)
return Character.isWhitespace(ch);
for (int i = 0; i < delims.length; ++i)
if (delims[i] == ch)
return true;
return false;
}
}
// --------------------------------------------
//
// Filter classes
//
// --------------------------------------------
public static abstract class ChainableReaderFilter
implements ChainableReader, Filter
{
private boolean byLine = true;
public void setByLine(boolean byLine) {
this.byLine = byLine;
}
public Reader chain(Reader reader) {
TokenFilter tokenFilter = new TokenFilter(reader);
if (!byLine)
tokenFilter.addFileTokenizer(new FileTokenizer());
tokenFilter.add(this);
return tokenFilter;
}
}
/**
* Simple replace string filter.
*/
public static class ReplaceString
extends ChainableReaderFilter
{
private String from;
private String to;
public void setFrom(String from) {
this.from = from;
}
public void setTo(String to) {
this.to = to;
}
/**
* CAP from the Replace task
*/
public String filter(String line) {
if (from == null)
throw new BuildException("Missing from in stringreplace");
StringBuffer ret = new StringBuffer();
int start = 0;
int found = line.indexOf(from);
while (found >= 0) {
// write everything up to the from
if (found > start) {
ret.append(line.substring(start, found));
}
// write the replacement to
if (to != null) {
ret.append(to);
}
// search again
start = found + from.length();
found = line.indexOf(line, start);
}
// write the remaining characters
if (line.length() > start) {
ret.append(line.substring(start, line.length()));
}
return ret.toString();
}
}
/**
* Simple filter to filter lines contains strings
*/
public static class ContainsString
implements Filter
{
private String contains;
public void setContains(String contains) {
this.contains = contains;
}
public String filter(String line) {
if (contains == null)
throw new BuildException("Missing contains in
containsstring");
if (line.indexOf(contains) > -1)
return line;
return null;
}
}
/**
* filter to replace regex.
*/
public static class ReplaceRegex
extends ChainableReaderFilter
{
private String from;
private String to;
private Project project;
private RegularExpression regularExpression;
private Substitution substitution;
private boolean initialized = false;
private String flags = "";
private int options;
private Regexp regexp;
public void setPattern(String from) {
this.from = from;
}
public void setReplace(String to) {
this.to = to;
}
public void setProject(Project p) {
this.project = p;
}
public void setFlags(String flags) {
this.flags = flags;
}
private void initialize() {
if (initialized)
return;
options = convertRegexOptions(flags);
if (from == null)
throw new BuildException("Missing pattern in replaceregex");
regularExpression = new RegularExpression();
regularExpression.setPattern(from);
regexp = regularExpression.getRegexp(project);
if (to == null)
to = "";
substitution = new Substitution();
substitution.setExpression(to);
}
public String filter(String line) {
initialize();
if (!regexp.matches(line, options)) {
return line;
}
return regexp.substitute(
line, substitution.getExpression(project), options);
}
}
/**
* filter to filter tokens matching regular expressions.
*/
public static class ContainsRegex
extends ChainableReaderFilter
{
private String from;
private String to;
private Project project;
private RegularExpression regularExpression;
private Substitution substitution;
private boolean initialized = false;
private String flags = "";
private int options;
private Regexp regexp;
public void setPattern(String from) {
this.from = from;
}
public void setReplace(String to) {
this.to = to;
}
public void setProject(Project p) {
this.project = p;
}
public void setFlags(String flags) {
this.flags = flags;
}
private void initialize() {
if (initialized)
return;
options = convertRegexOptions(flags);
if (from == null)
throw new BuildException("Missing from in containsregex");
regularExpression = new RegularExpression();
regularExpression.setPattern(from);
regexp = regularExpression.getRegexp(project);
if (to == null)
return;
substitution = new Substitution();
substitution.setExpression(to);
}
public String filter(String line) {
initialize();
if (!regexp.matches(line, options)) {
return null;
}
if (substitution == null)
return line;
return regexp.substitute(
line, substitution.getExpression(project), options);
}
}
/** Filter to trim white space */
public static class Trim
extends ChainableReaderFilter
{
public String filter(String line) {
return line.trim();
}
}
/** Filter remove empty tokens */
public static class IgnoreBlank
extends ChainableReaderFilter
{
public String filter(String line) {
if (line.trim().length() == 0)
return null;
return line;
}
}
/**
* Filter to delete characters
*/
public static class DeleteCharacters
implements Filter, ChainableReader
{
// Attributes
/** the list of characters to remove from the input */
private String deleteChars = "";
/** Set the list of characters to delete */
public void setChars(String deleteChars) {
this.deleteChars = resolveBackSlash(deleteChars);
}
/** remove characters from a string */
public String filter(String string) {
StringBuffer output = new StringBuffer(string.length());
for (int i = 0; i < string.length(); ++i) {
char ch = string.charAt(i);
if (! isDeleteCharacter(ch))
output.append(ch);
}
return output.toString();
}
/**
* factory method to provide a reader that removes
* the characters from a reader as part of a filter
* chain
*/
public Reader chain(Reader reader) {
return new BaseFilterReader(reader) {
public int read()
throws IOException
{
while (true) {
int c = in.read();
if (c == -1)
return c;
if (! isDeleteCharacter((char) c))
return c;
}
}
};
}
/** check if the character c is to be deleted */
private boolean isDeleteCharacter(char c) {
for (int d = 0; d < deleteChars.length(); ++d) {
if (deleteChars.charAt(d) == c) {
return true;
}
}
return false;
}
}
// --------------------------------------------------------
// static utility methods - could be placed somewhere else
// --------------------------------------------------------
/**
* xml does not do "c" like interpetation of strings.
* i.e. \n\r\t etc.
* this methid processes \n, \r, \t, \f, \\
* also subs \s -> " \n\r\t\f"
* a trailing '\' will be ignored
*
* @param input raw string with possible embedded '\'s
* @return converted string
*/
public static String resolveBackSlash(String input) {
StringBuffer b = new StringBuffer();
boolean backSlashSeen = false;
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);
if (! backSlashSeen) {
if (c == '\\')
backSlashSeen = true;
else
b.append(c);
}
else {
switch (c) {
case '\\':
b.append((char) '\\');
break;
case 'n':
b.append((char) '\n');
break;
case 'r':
b.append((char) '\r');
break;
case 't':
b.append((char) '\t');
break;
case 'f':
b.append((char) '\f');
break;
case 's':
b.append(" \t\n\r\f");
break;
default:
b.append(c);
}
backSlashSeen = false;
}
}
return b.toString();
}
/**
* convert regex option flag characters to regex options
* <dl>
* <li>g - Regexp.REPLACE_ALL</li>
* <li>i - Regexp.MATCH_CASE_INSENSITIVE</li>
* <li>m - Regexp.MATCH_MULTILINE</li>
* <li>s - Regexp.MATCH_SINGLELINE</li>
* </dl>
*/
public static int convertRegexOptions(String flags) {
if (flags == null)
return 0;
int options = 0;
if (flags.indexOf('g') != -1)
options |= Regexp.REPLACE_ALL;
if (flags.indexOf('i') != -1)
options |= Regexp.MATCH_CASE_INSENSITIVE;
if (flags.indexOf('m') != -1)
options |= Regexp.MATCH_MULTILINE;
if (flags.indexOf('s') != -1)
options |= Regexp.MATCH_SINGLELINE;
return options;
}
}
1.10 +110 -1 ant/src/main/org/apache/tools/ant/types/FilterChain.java
Index: FilterChain.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/FilterChain.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- FilterChain.java 14 Mar 2003 13:45:16 -0000 1.9
+++ FilterChain.java 14 Apr 2003 18:02:24 -0000 1.10
@@ -54,7 +54,13 @@
package org.apache.tools.ant.types;
import java.util.Vector;
+import java.io.StringWriter;
+import java.io.Reader;
+import java.io.IOException;
+
import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.filters.ChainableReader;
import org.apache.tools.ant.filters.ClassConstants;
import org.apache.tools.ant.filters.EscapeUnicode;
import org.apache.tools.ant.filters.ExpandProperties;
@@ -68,13 +74,19 @@
import org.apache.tools.ant.filters.StripLineComments;
import org.apache.tools.ant.filters.TabsToSpaces;
import org.apache.tools.ant.filters.TailFilter;
+import org.apache.tools.ant.filters.TokenFilter;
+import org.apache.tools.ant.filters.BaseFilterReader;
+import org.apache.tools.ant.taskdefs.Concat;
+
/**
* FilterChain may contain a chained set of filter readers.
*
* @author Magesh Umasankar
*/
-public final class FilterChain extends DataType implements Cloneable {
+public final class FilterChain extends DataType
+ implements Cloneable, DynamicConfigurator
+{
private Vector filterReaders = new Vector();
@@ -146,6 +158,69 @@
}
/**
+ * @since Ant 1.6
+ */
+ public final void addTokenFilter(final TokenFilter tokenFilter) {
+ filterReaders.addElement(tokenFilter);
+ }
+
+ /**
+ * delete characters filter
+ * @since Ant 1.6
+ */
+ public void addDeleteCharacters(TokenFilter.DeleteCharacters filter) {
+ filterReaders.addElement(filter);
+ }
+
+ /**
+ * containsregex
+ * @since Ant 1.6
+ */
+ public void addContainsRegex(TokenFilter.ContainsRegex filter)
+ {
+ filterReaders.addElement(filter);
+ }
+
+ /**
+ * replaceregex
+ * @since Ant 1.6
+ */
+ public void addReplaceRegex(TokenFilter.ReplaceRegex filter)
+ {
+ filterReaders.addElement(filter);
+ }
+
+ /**
+ * trim
+ * @since Ant 1.6
+ */
+ public void addTrim(TokenFilter.Trim filter)
+ {
+ filterReaders.addElement(filter);
+ }
+
+ /**
+ * replacestring
+ * @since Ant 1.6
+ */
+ public void addReplaceString(
+ TokenFilter.ReplaceString filter)
+ {
+ filterReaders.addElement(filter);
+ }
+
+ /**
+ * ignoreBlank
+ * @since Ant 1.6
+ */
+ public void addIgnoreBlank(
+ TokenFilter.IgnoreBlank filter)
+ {
+ filterReaders.addElement(filter);
+ }
+
+
+ /**
* Makes this instance in effect a reference to another FilterChain
* instance.
*
@@ -171,4 +246,38 @@
super.setRefid(r);
}
+
+ /**
+ * create the named datatype and check if it
+ * is a filter.
+ *
+ * @throws BuildException if unknown datatype or incorrect datatype
+ * @since Ant 1.6
+ */
+
+ public Object createDynamicElement(String name)
+ {
+ if (getProject() == null)
+ throw new BuildException("Unable to get the project");
+
+ Object obj = getProject().createDataType(name);
+ if (obj == null)
+ throw new BuildException("Unknown type " + name);
+ if (! (obj instanceof ChainableReader))
+ throw new BuildException(
+ "type " + name + " is not a filterreader");
+ filterReaders.addElement(obj);
+ return obj;
+ }
+
+ /**
+ * Needed for dynamic element support.
+ *
+ * @throws BuildException always
+ */
+
+ public void setDynamicAttribute(String name, String value) {
+ throw new BuildException("Unknown attribute " + name);
+ }
+
}
1.16 +2 -0
ant/src/main/org/apache/tools/ant/types/defaults.properties
Index: defaults.properties
===================================================================
RCS file:
/home/cvs/ant/src/main/org/apache/tools/ant/types/defaults.properties,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- defaults.properties 1 Jun 2002 12:26:41 -0000 1.15
+++ defaults.properties 14 Apr 2003 18:02:24 -0000 1.16
@@ -16,3 +16,5 @@
extension=org.apache.tools.ant.taskdefs.optional.extension.ExtensionAdapter
libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet
selector=org.apache.tools.ant.types.selectors.SelectSelector
+scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter
+
1.1
ant/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java
Index: ScriptFilter.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 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 "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 [EMAIL PROTECTED]
*
* 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.optional;
import org.apache.tools.ant.filters.TokenFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
/**
* Most of this is CAP (Cut And Paste) from the Script task
* ScriptFilter class, implements TokenFilter.Filter
* for scripts to use.
* This provides the same beans as the Script Task
* to a script.
* The script is meant to use get self.token and
* set self.token in the reply.
*/
public class ScriptFilter
extends TokenFilter.ChainableReaderFilter
{
/** The current project - set by ant reflection */
private Project project;
/** The language - attribute of element */
private String language;
/** The script - inline text or external file */
private String script = "";
/** The beans - see ScriptTask */
private Hashtable beans = new Hashtable();
/** Has this object been initialized ? */
private boolean initialized = false;
/** the BSF manager */
private BSFManager manager;
/** the token used by the script */
private String token;
/** Called by ant reflection to set the project */
public void setProject(Project project) {
this.project = project;
}
/** this is provided to allow easier CAP from the ScriptTask */
private Project getProject() {
return project;
}
/**
* Defines the language (required).
*
* @param msg Sets the value for the script variable.
*/
public void setLanguage(String language) {
this.language = language;
}
/**
* Add a list of named objects to the list to be exported to the script
* CAP from taskdefs.optional.Script
*/
private void addBeans(Hashtable dictionary) {
for (Enumeration e = dictionary.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
boolean isValid = key.length() > 0 &&
Character.isJavaIdentifierStart(key.charAt(0));
for (int i = 1; isValid && i < key.length(); i++) {
isValid = Character.isJavaIdentifierPart(key.charAt(i));
}
try {
if (isValid) {
beans.put(key, dictionary.get(key));
}
}
catch (Throwable t) {
throw new BuildException(t);
//System.err.println("What the helll");
}
}
}
/**
* Initialize, mostly CAP from taskdefs.option.Script#execute()
*
* @exception BuildException if someting goes wrong
*/
private void init() throws BuildException {
if (initialized)
return;
initialized = true;
if (language == null)
throw new BuildException(
"scriptfilter: language is not defined");
try {
addBeans(getProject().getProperties());
addBeans(getProject().getUserProperties());
addBeans(getProject().getTargets());
addBeans(getProject().getReferences());
beans.put("project", getProject());
beans.put("self", this);
manager = new BSFManager ();
for (Enumeration e = beans.keys() ; e.hasMoreElements() ;) {
String key = (String) e.nextElement();
Object value = beans.get(key);
manager.declareBean(key, value, value.getClass());
}
}
catch (BSFException e) {
Throwable t = e;
Throwable te = e.getTargetException();
if (te != null) {
if (te instanceof BuildException) {
throw (BuildException) te;
} else {
t = te;
}
}
throw new BuildException(t);
}
}
/**
* The current token
*
* @param token the string filtered by the script
*/
public void setToken(String token) {
this.token = token;
}
/**
* The current token
*
* @return the string filtered by the script
*/
public String getToken() {
return token;
}
/**
* Called filter the token.
* This sets the token in this object, calls
* the script and returns the token.
*
* @param token the token to be filtered
* @return the filtered token
*/
public String filter(String token) {
init();
setToken(token);
try {
manager.exec(language, "<ANT>", 0, 0, script);
return getToken();
}
catch (BSFException be) {
Throwable t = be;
Throwable te = be.getTargetException();
if (te != null) {
if (te instanceof BuildException) {
throw (BuildException) te;
} else {
t = te;
}
}
throw new BuildException(t);
}
}
/**
* Load the script from an external file ; optional.
*
* @param msg Sets the value for the script variable.
*/
public void setSrc(String fileName) {
File file = new File(fileName);
if (!file.exists()) {
throw new BuildException("file " + fileName + " not found.");
}
int count = (int) file.length();
byte data[] = new byte[count];
try {
FileInputStream inStream = new FileInputStream(file);
inStream.read(data);
inStream.close();
} catch (IOException e) {
throw new BuildException(e);
}
script += new String(data);
}
/**
* The script text.
*
* @param msg Sets the value for the script variable.
*/
public void addText(String text) {
this.script += text;
}
}
1.1
ant/src/testcases/org/apache/tools/ant/filters/DynamicFilterTest.java
Index: DynamicFilterTest.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 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 "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 [EMAIL PROTECTED]
*
* 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.filters;
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.io.IOException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.util.FileUtils;
/**
* @author Peter Reilly
*/
public class DynamicFilterTest extends BuildFileTest {
public DynamicFilterTest(String name) {
super(name);
}
public void setUp() {
configureProject("src/etc/testcases/filters/dynamicfilter.xml");
executeTarget("init");
}
public void tearDown() {
executeTarget("cleanup");
}
public void testCustomFilter() throws IOException {
expectFileContains("dynamicfilter", "result/dynamicfilter",
"hellO wOrld");
}
// ------------------------------------------------------
// Helper methods
// -----------------------------------------------------
private void assertStringContains(String string, String contains) {
assertTrue("[" + string + "] does not contain [" + contains +"]",
string.indexOf(contains) > -1);
}
private void assertStringNotContains(String string, String contains) {
assertTrue("[" + string + "] does contain [" + contains +"]",
string.indexOf(contains) == -1);
}
private String getFileString(String filename)
throws IOException
{
Reader r = null;
try {
r = new FileReader(getProject().resolveFile(filename));
return FileUtils.newFileUtils().readFully(r);
}
finally {
try {r.close();} catch (Throwable ignore) {}
}
}
private String getFileString(String target, String filename)
throws IOException
{
executeTarget(target);
return getFileString(filename);
}
private void expectFileContains(String name, String contains)
throws IOException
{
String content = getFileString(name);
assertTrue(
"expecting file " + name + " to contain " + contains +
" but got " + content, content.indexOf(contains) > -1);
}
private void expectFileContains(
String target, String name, String contains)
throws IOException
{
executeTarget(target);
expectFileContains(name, contains);
}
public static class CustomFilter implements ChainableReader {
char replace = 'x';
char with = 'y';
public void setReplace(char replace) {
this.replace = replace;
}
public void setWith(char with) {
this.with = with;
}
public Reader chain(final Reader rdr) {
return new BaseFilterReader(rdr) {
public int read()
throws IOException
{
int c = in.read();
if (c == replace)
return with;
else
return c;
}
};
}
}
}
1.1
ant/src/testcases/org/apache/tools/ant/filters/TokenFilterTest.java
Index: TokenFilterTest.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 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 "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 [EMAIL PROTECTED]
*
* 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.filters;
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.io.IOException;
import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.util.FileUtils;
/**
* @author Peter Reilly
*/
public class TokenFilterTest extends BuildFileTest {
public TokenFilterTest(String name) {
super(name);
}
public void setUp() {
configureProject("src/etc/testcases/filters/tokenfilter.xml");
executeTarget("init");
}
public void tearDown() {
//executeTarget("cleanup");
}
/** make sure tokenfilter exists */
public void testTokenfilter() throws IOException {
executeTarget("tokenfilter");
}
public void testTrimignore() throws IOException {
expectLogContaining("trimignore", "Hello-World");
}
public void testStringTokenizer() throws IOException {
expectLogContaining(
"stringtokenizer", "#This#is#a#number#of#words#");
}
public void testUnixLineOutput() throws IOException {
expectFileContains(
"unixlineoutput", "result/unixlineoutput",
"\nThis\nis\na\nnumber\nof\nwords\n");
}
public void testDosLineOutput() throws IOException {
expectFileContains(
"doslineoutput", "result/doslineoutput",
"\r\nThis\r\nis\r\na\r\nnumber\r\nof\r\nwords\r\n");
}
public void testFileTokenizer() throws IOException {
String contents = getFileString(
"filetokenizer", "result/filetokenizer");
assertStringContains(contents, " of words");
assertStringNotContains(contents, " This is");
}
public void testReplaceString() throws IOException {
expectFileContains(
"replacestring", "result/replacestring",
"this is the moon");
}
public void testContainsString() throws IOException {
String contents = getFileString(
"containsstring", "result/containsstring");
assertStringContains(contents, "this is a line contains foo");
assertStringNotContains(contents, "this line does not");
}
public void testReplaceRegex() throws IOException {
if (! hasRegex("testReplaceRegex"))
return;
String contents = getFileString(
"replaceregex", "result/replaceregex");
assertStringContains(contents, "world world world world");
assertStringContains(contents, "dog Cat dog");
assertStringContains(contents, "moon Sun Sun");
assertStringContains(contents, "found WhiteSpace");
assertStringContains(contents, "Found digits [1234]");
assertStringNotContains(contents, "This is a line with digits");
}
public void testFilterReplaceRegex() throws IOException {
if (! hasRegex("testFilterReplaceRegex"))
return;
String contents = getFileString(
"filterreplaceregex", "result/filterreplaceregex");
assertStringContains(contents, "world world world world");
}
public void testTrimFile() throws IOException {
String contents = getFileString(
"trimfile", "result/trimfile");
assertTrue("no ws at start", contents.startsWith("This is th"));
assertTrue("no ws at end", contents.endsWith("second line."));
assertStringContains(contents, " This is the second");
}
public void testTrimFileByLine() throws IOException {
String contents = getFileString(
"trimfilebyline", "result/trimfilebyline");
assertFalse("no ws at start", contents.startsWith("This is th"));
assertFalse("no ws at end", contents.endsWith("second line."));
assertStringNotContains(contents, " This is the second");
assertStringContains(contents, "file.\nThis is the second");
}
public void testFilterReplaceString() throws IOException {
String contents = getFileString(
"filterreplacestring", "result/filterreplacestring");
assertStringContains(contents, "This is the moon");
}
public void testContainsRegex() throws IOException {
if (! hasRegex("testContainsRegex"))
return;
String contents = getFileString(
"containsregex", "result/containsregex");
assertStringContains(contents, "hello world");
assertStringNotContains(contents, "this is the moon");
assertStringContains(contents, "World here");
}
public void testFilterContainsRegex() throws IOException {
if (! hasRegex("testFilterContainsRegex"))
return;
String contents = getFileString(
"filtercontainsregex", "result/filtercontainsregex");
assertStringContains(contents, "hello world");
assertStringNotContains(contents, "this is the moon");
assertStringContains(contents, "World here");
}
public void testContainsRegex2() throws IOException {
if (! hasRegex("testContainsRegex2"))
return;
String contents = getFileString(
"containsregex2", "result/containsregex2");
assertStringContains(contents, "void register_bits();");
}
public void testDeleteCharacters() throws IOException {
String contents = getFileString(
"deletecharacters", "result/deletechars");
assertStringNotContains(contents, "#");
assertStringNotContains(contents, "*");
assertStringContains(contents, "This is some ");
}
public void testScriptFilter() throws IOException {
if (! hasScript("testScriptFilter"))
return;
expectFileContains("scriptfilter", "result/scriptfilter",
"HELLO WORLD");
}
public void testScriptFilter2() throws IOException {
if (! hasScript("testScriptFilter"))
return;
expectFileContains("scriptfilter2", "result/scriptfilter2",
"HELLO MOON");
}
public void testCustomTokenFilter() throws IOException {
expectFileContains("customtokenfilter", "result/custom",
"Hello World");
}
// ------------------------------------------------------
// Helper methods
// -----------------------------------------------------
private boolean hasScript(String test) {
try {
executeTarget("hasscript");
}
catch (Throwable ex) {
System.out.println(
test + ": skipped - script not present ");
ex.printStackTrace(System.out);
return false;
}
return true;
}
private boolean hasRegex(String test) {
try {
executeTarget("hasregex");
expectFileContains("result/replaceregexp", "bye world");
}
catch (Throwable ex) {
System.out.println(test + ": skipped - regex not present "
+ ex);
return false;
}
return true;
}
private void assertStringContains(String string, String contains) {
assertTrue("[" + string + "] does not contain [" + contains +"]",
string.indexOf(contains) > -1);
}
private void assertStringNotContains(String string, String contains) {
assertTrue("[" + string + "] does contain [" + contains +"]",
string.indexOf(contains) == -1);
}
private String getFileString(String filename)
throws IOException
{
Reader r = null;
try {
r = new FileReader(getProject().resolveFile(filename));
return FileUtils.newFileUtils().readFully(r);
}
finally {
try {r.close();} catch (Throwable ignore) {}
}
}
private String getFileString(String target, String filename)
throws IOException
{
executeTarget(target);
return getFileString(filename);
}
private void expectFileContains(String name, String contains)
throws IOException
{
String content = getFileString(name);
assertTrue(
"expecting file " + name + " to contain " + contains +
" but got " + content, content.indexOf(contains) > -1);
}
private void expectFileContains(
String target, String name, String contains)
throws IOException
{
executeTarget(target);
expectFileContains(name, contains);
}
public static class Capitalize
implements TokenFilter.Filter
{
public String filter(String token) {
if (token.length() == 0)
return token;
return token.substring(0, 1).toUpperCase() +
token.substring(1);
}
}
}