PR: 18312 Submitted by: peter.reilly@corvil.com (peter reilly) git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274449 13f79535-47bb-0310-9956-ffa450edef68master
@@ -99,6 +99,9 @@ Fixed bugs: | |||
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. | |||
@@ -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*"/> | |||
@@ -101,6 +101,8 @@ nested elements.<BR> | |||
<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 @@ that represent comments as specified by the user. | |||
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 "/> | |||
@@ -786,6 +788,480 @@ lines 49-58 are extracted) | |||
</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> | |||
<P align=center>Copyright © 2002-2003 Apache Software Foundation. All rights | |||
@@ -0,0 +1,34 @@ | |||
<?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> |
@@ -0,0 +1,314 @@ | |||
<?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> |
@@ -0,0 +1,918 @@ | |||
/* | |||
* 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 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.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; | |||
} | |||
} |
@@ -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.StripLineBreaks; | |||
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(); | |||
@@ -145,6 +157,69 @@ public final class FilterChain extends DataType implements Cloneable { | |||
filterReaders.addElement(escapeUnicode); | |||
} | |||
/** | |||
* @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 @@ public final class FilterChain extends DataType implements Cloneable { | |||
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); | |||
} | |||
} |
@@ -16,3 +16,5 @@ extensionSet=org.apache.tools.ant.taskdefs.optional.extension.ExtensionSet | |||
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 | |||
@@ -0,0 +1,269 @@ | |||
/* | |||
* 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 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.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; | |||
} | |||
} |
@@ -0,0 +1,167 @@ | |||
/* | |||
* 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 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.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; | |||
} | |||
}; | |||
} | |||
} | |||
} |
@@ -0,0 +1,319 @@ | |||
/* | |||
* 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 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.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); | |||
} | |||
} | |||
} |