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); | |||||
| } | |||||
| } | |||||
| } | |||||