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: | 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 | * A new attribute named skip is added to the TailFilter and | ||||
HeadFilter filter readers. | HeadFilter filter readers. | ||||
@@ -202,7 +202,10 @@ | |||||
<filename name="${ant.package}/listener/CommonsLoggingListener*"/> | <filename name="${ant.package}/listener/CommonsLoggingListener*"/> | ||||
</selector> | </selector> | ||||
<selector id="needs.bsf"> | <selector id="needs.bsf"> | ||||
<filename name="${optional.package}/Script*"/> | |||||
<or> | |||||
<filename name="${optional.package}/Script*"/> | |||||
<filename name="${optional.type.package}/Script*"/> | |||||
</or> | |||||
</selector> | </selector> | ||||
<selector id="needs.stylebook"> | <selector id="needs.stylebook"> | ||||
<filename name="${optional.package}/StyleBook*"/> | <filename name="${optional.package}/StyleBook*"/> | ||||
@@ -101,6 +101,8 @@ nested elements.<BR> | |||||
<a href="#striplinecomments">StripLineComments</a><BR> | <a href="#striplinecomments">StripLineComments</a><BR> | ||||
<a href="#tabstospaces">TabsToSpaces</a><BR> | <a href="#tabstospaces">TabsToSpaces</a><BR> | ||||
<a href="#tailfilter">TailFilter</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> | <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 // | This removes all lines that begin with #, --, REM, rem and // | ||||
<BLOCKQUOTE><PRE> | <BLOCKQUOTE><PRE> | ||||
<filterreader classname="org.apache.tools.ant.filters.StripLineComments"> | <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="--"/> | ||||
<param type="comment" value="REM "/> | <param type="comment" value="REM "/> | ||||
<param type="comment" value="rem "/> | <param type="comment" value="rem "/> | ||||
@@ -786,6 +788,480 @@ lines 49-58 are extracted) | |||||
</loadfile> | </loadfile> | ||||
</PRE></BLOCKQUOTE> | </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> | <HR> | ||||
<P align=center>Copyright © 2002-2003 Apache Software Foundation. All rights | <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; | package org.apache.tools.ant.types; | ||||
import java.util.Vector; | 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.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.ClassConstants; | ||||
import org.apache.tools.ant.filters.EscapeUnicode; | import org.apache.tools.ant.filters.EscapeUnicode; | ||||
import org.apache.tools.ant.filters.ExpandProperties; | 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.StripLineComments; | ||||
import org.apache.tools.ant.filters.TabsToSpaces; | import org.apache.tools.ant.filters.TabsToSpaces; | ||||
import org.apache.tools.ant.filters.TailFilter; | 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. | * FilterChain may contain a chained set of filter readers. | ||||
* | * | ||||
* @author Magesh Umasankar | * @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(); | private Vector filterReaders = new Vector(); | ||||
@@ -145,6 +157,69 @@ public final class FilterChain extends DataType implements Cloneable { | |||||
filterReaders.addElement(escapeUnicode); | 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 | * Makes this instance in effect a reference to another FilterChain | ||||
* instance. | * instance. | ||||
@@ -171,4 +246,38 @@ public final class FilterChain extends DataType implements Cloneable { | |||||
super.setRefid(r); | 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 | extension=org.apache.tools.ant.taskdefs.optional.extension.ExtensionAdapter | ||||
libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet | libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet | ||||
selector=org.apache.tools.ant.types.selectors.SelectSelector | 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); | |||||
} | |||||
} | |||||
} |