PR: 18312 Submitted by: peter.reilly@corvil.com (peter reilly) git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274449 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -99,6 +99,9 @@ Fixed bugs: | |||
| Other changes: | |||
| -------------- | |||
| * A new filter reader namely tokenfilter has been added. Bugzilla | |||
| Report 18312. | |||
| * A new attribute named skip is added to the TailFilter and | |||
| HeadFilter filter readers. | |||
| @@ -202,7 +202,10 @@ | |||
| <filename name="${ant.package}/listener/CommonsLoggingListener*"/> | |||
| </selector> | |||
| <selector id="needs.bsf"> | |||
| <filename name="${optional.package}/Script*"/> | |||
| <or> | |||
| <filename name="${optional.package}/Script*"/> | |||
| <filename name="${optional.type.package}/Script*"/> | |||
| </or> | |||
| </selector> | |||
| <selector id="needs.stylebook"> | |||
| <filename name="${optional.package}/StyleBook*"/> | |||
| @@ -101,6 +101,8 @@ nested elements.<BR> | |||
| <a href="#striplinecomments">StripLineComments</a><BR> | |||
| <a href="#tabstospaces">TabsToSpaces</a><BR> | |||
| <a href="#tailfilter">TailFilter</a><BR> | |||
| <a href="#deletecharacters">DeleteCharacters</a><BR> | |||
| <a href="#tokenfilter">TokenFilter</a><BR> | |||
| <H3><a name="filterreader">FilterReader</a></H3> | |||
| @@ -552,7 +554,7 @@ that represent comments as specified by the user. | |||
| This removes all lines that begin with #, --, REM, rem and // | |||
| <BLOCKQUOTE><PRE> | |||
| <filterreader classname="org.apache.tools.ant.filters.StripLineComments"> | |||
| <param type="comment" value="#"/> | |||
| <param type="comment" value="e;#"/> | |||
| <param type="comment" value="--"/> | |||
| <param type="comment" value="REM "/> | |||
| <param type="comment" value="rem "/> | |||
| @@ -786,6 +788,480 @@ lines 49-58 are extracted) | |||
| </loadfile> | |||
| </PRE></BLOCKQUOTE> | |||
| <H3><a name="deletecharacters">DeleteCharacters</a></H3> | |||
| <p>This filter deletes specified characters.</p> | |||
| <p><em>since Ant 1.6</em></p> | |||
| <p>This filter is only available in the convenience form.</p> | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Parameter Name</B></TD> | |||
| <TD vAlign=top><B>Parameter Value</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>chars</TD> | |||
| <TD vAlign=top> | |||
| The characters to delete. This attribute is | |||
| <a href="#backslash">backslash enabled</a>. | |||
| </TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <P> | |||
| <H4>Examples:</H4> | |||
| Delete tabs and returns from the data. | |||
| <BLOCKQUOTE><PRE> | |||
| <deletecharacters chars="\t\r"/> | |||
| </PRE></BLOCKQUOTE> | |||
| <H3><a name="tokenfilter">TokenFilter</a></H3> | |||
| This filter tokenizes the inputstream into strings and passes these | |||
| strings to filters of strings. Unlike the other filterreaders, this does | |||
| not support params, only convenience methods are implemented. | |||
| The tokenizer and the string filters are defined by nested elements. | |||
| <P><em>since Ant 1.6</em></p> | |||
| <P> | |||
| Only one tokenizer element may be used, the LineTokenizer is the | |||
| default if none are specified. A tokenizer | |||
| splits the input into token strings and trailing delimiter strings. | |||
| <P> | |||
| There may be zero or more string filters. A string filter processes | |||
| a token and either returns a string or a null. | |||
| It the string is not null it is passed to the next filter. This | |||
| proceeds until all the filters are called. | |||
| If a string is returned after all the filters, the string is | |||
| outputs with its associated token delimitier | |||
| (if one is present). | |||
| The trailing delimiter may be overridden by the <i>delimOutput</i> | |||
| attribute. | |||
| <P> | |||
| <a name="backslash"><em>blackslash interpretation</em></a> | |||
| A number of attributes (including <i>delimOutput</i>) interpret | |||
| backslash escapes. The following are understood: \n, \r, \f, \t | |||
| and \\. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>delimOutput</TD> | |||
| <TD vAlign=top> | |||
| This overrides the tokendelimiter | |||
| returned by the tokenizer if it is not empty. This | |||
| attribute is backslash enabled. | |||
| </TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <P> | |||
| The following tokenizers are provided by the default distribution. | |||
| <p> | |||
| <a href="#linetokenizer">LineTokenizer</a><br> | |||
| <a href="#filetokenizer">FileTokenizer</a><br> | |||
| <a href="#stringtokenizer">StringTokenizer</a><br> | |||
| </p> | |||
| The following string filters are provided by the default distribution. | |||
| <p> | |||
| <a href="#replacestring">ReplaceString</a><br> | |||
| <a href="#containsstring">ContainsString</a><br> | |||
| <a href="#replaceregex">ReplaceRegex</a><br> | |||
| <a href="#containsregex">ContainsRegex</a><br> | |||
| <a href="#trim">Trim</a><br> | |||
| <a href="#ignoreblank">IgnoreBlank</a><br> | |||
| <a href="#filterdeletecharacters">DeleteCharacters</a><br> | |||
| </p> | |||
| The following string filters are provided by the optional distribution. | |||
| <p> | |||
| <a href="#scriptfilter">ScriptFilter</a><br> | |||
| </p> | |||
| Some of the filters may be used directly within a filter chain. In this | |||
| case a tokenfilter is created implicitly. An extra attribute "byline" | |||
| is added to the filter to specify whether to use a linetokenizer | |||
| (byline="true") or a filetokenizer (byline="false"). The default | |||
| is "true". | |||
| <P> | |||
| <p><b><em><a name="linetokenizer">LineTokenizer</a></em></b></p> | |||
| This tokenizer splits the input into lines. | |||
| The tokenizer delimits lines | |||
| by "\r", "\n" or "\r\n". | |||
| This is the default tokenizer. | |||
| <H4>Examples:</H4> | |||
| Convert input current line endings to unix style line endings. | |||
| <em>This currently has no effect when used in the copy task.</em> | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter delimoutput="\n"/> | |||
| </PRE></BLOCKQUOTE> | |||
| Remove blank lines. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <ignoreblank/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="filetokenizer">FileTokenizer</a></em></b></p> | |||
| This tokenizer treats <b>all</b> the input as a token. So be | |||
| careful not to use this on very large input. | |||
| <H4>Examples:</H4> | |||
| Replace the first occurance of package with //package. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <filetokenizer/> | |||
| <replaceregex pattern="([\n\r]+[ \t]*|^[ \t]*)package" | |||
| flags="s" | |||
| replace="\1//package"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="stringtokenizer">StringTokenizer</a></em></b></p> | |||
| This tokenizer is based on java.util.StringTokenizer. | |||
| It splits up the input into strings separated by white space, or | |||
| by a specified list of delimiting characters. | |||
| If the stream starts with delimiter characters, the first | |||
| token will be the empty string (unless the <i>delimsaretokens</i> | |||
| attribute is used). | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>delims</TD> | |||
| <TD vAlign=top>The delimiter characters. White space | |||
| is used if this is not set. (White space is defined | |||
| in this case by java.lang.Character.isWhitespace()). | |||
| </TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| <tr> | |||
| <td valign="top">delimsaretokens</td> | |||
| <td valign="top">If this is true, | |||
| each delimiter character is returned as a token</td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">suppressdelims</td> | |||
| <td valign="top">If this is true, delimiters are not returned. </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Surround each non space token with a "[]". | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <stringtokenizer/> | |||
| <replaceregex pattern="(.+)" replace="[\1]"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="replacestring">ReplaceString</a></em></b></p> | |||
| This is a simple filter to replace strings. | |||
| This filter may be used directly within a filterchain. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>from</TD> | |||
| <TD vAlign=top>The string that must be replaced.</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| <tr> | |||
| <td valign="top">to</td> | |||
| <td valign="top">The new value for the replaced string. When omitted | |||
| an empty string is used. | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Replace "sun" with "moon". | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <replacestring from="sun" to="moon"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="containsstring">ContainsString</a></em></b></p> | |||
| This is a simple filter to filter tokens that contains | |||
| a specified string. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>contains</TD> | |||
| <TD vAlign=top>The string that the token must contain.</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Include only lines that contain "foo"; | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <containsstring contains="foo"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="replaceregex">ReplaceRegex</a></em></b></p> | |||
| This string filter replaces regular expressions. See | |||
| <a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a> | |||
| for an explanation on regular expressions. | |||
| This filter may be used directly within a filterchain. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>pattern</TD> | |||
| <TD vAlign=top>The regular expression pattern to match in | |||
| the token.</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>replace</TD> | |||
| <TD vAlign=top>The substitution pattern to replace the matched | |||
| regular expression. When omitted an empty string is used.</TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>flags</TD> | |||
| <TD vAlign=top>See | |||
| <a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a> | |||
| for an explanation of regex flags.</TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Replace all occurances of "hello" with "world", ignoring case. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <replaceregex pattern="hello" replace="world" flags="gi"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="containsregex">ContainsRegex</a></em></b></p> | |||
| This filters strings that match regular expressions. | |||
| The filter may optionally replace the matched regular expression. | |||
| See | |||
| <a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a> | |||
| for an explanation on regular expressions. | |||
| This filter may be used directly within a filterchain. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>pattern</TD> | |||
| <TD vAlign=top>The regular expression pattern to match in | |||
| the token.</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>replace</TD> | |||
| <TD vAlign=top>The substitution pattern to replace the matched | |||
| regular expression. When omitted the orignal token is returned. | |||
| </TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>flags</TD> | |||
| <TD vAlign=top>See | |||
| <a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a> | |||
| for an explanation of regex flags.</TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Filter lines that contain "hello" or "world", ignoring case. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <containsregex pattern="(hello|world)" flags="i"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| This example replaces lines like "SUITE(TestSuite, bits);" with | |||
| "void register_bits();" and removes other lines. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <containsregex | |||
| pattern="^ *SUITE\(.*,\s*(.*)\s*\).*" | |||
| replace="void register_\1();"/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="trim">Trim</a></em></b></p> | |||
| This filter trims whitespace from the start and end of | |||
| tokens. | |||
| This filter may be used directly within a filterchain. | |||
| <p><b><em><a name="ignoreblank">IgnoreBlank</a></em></b></p> | |||
| This filter removes empty tokens. | |||
| This filter may be used directly within a filterchain. | |||
| <p><b><em><a name="filterdeletecharacters">DeleteCharacters</a></em></b></p> | |||
| This filter deletes specified characters from tokens. | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>chars</TD> | |||
| <TD vAlign=top>The characters to delete. This attribute | |||
| is backslash enabled.</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Delete tabs from lines, trim the lines and removes empty lines. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <deletecharacters chars="\t"/> | |||
| <trim/> | |||
| <ignoreblank/> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <p><b><em><a name="scriptfilter">ScriptFilter</a></em></b></p> | |||
| This is an optional filter that executes a script in a | |||
| <a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a> | |||
| supported language.</p> | |||
| See the <a href="../OptionalTasks/script.html">Script</a> task for | |||
| an explanation of scripts and dependencies. | |||
| </p> | |||
| <p> | |||
| The script is provided with an object <i>self</i> that has | |||
| getToken() and setToken(String) methods. | |||
| </p> | |||
| This filter may be used directly within a filterchain.<p> | |||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||
| <TR> | |||
| <TD vAlign=top><B>Attribute</B></TD> | |||
| <TD vAlign=top><B>Description</B></TD> | |||
| <TD vAlign=top align="center"><B>Required</B></TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>language</TD> | |||
| <TD vAlign=top> The programming language the script is written in. | |||
| Must be a supported Apache BSF language</TD> | |||
| <TD vAlign=top align="center">Yes</TD> | |||
| </TR> | |||
| <TR> | |||
| <TD vAlign=top>src</TD> | |||
| <TD vAlign=top>The location of the script as a file, if not inline | |||
| </TD> | |||
| <TD vAlign=top align="center">No</TD> | |||
| </TR> | |||
| <TR> | |||
| </TABLE> | |||
| <H4>Examples:</H4> | |||
| Convert to uppercase. | |||
| <BLOCKQUOTE><PRE> | |||
| <tokenfilter> | |||
| <scriptfilter language="javascript"> | |||
| self.setToken(self.getToken().toUpperCase()); | |||
| </scriptfilter> | |||
| </tokenfilter> | |||
| </PRE></BLOCKQUOTE> | |||
| <H4>Custom tokenizers and string filters</H4> | |||
| Custom string filters and tokenizers may be plugged in by | |||
| extending the interfaces org.apache.tools.ant.filters.TokenFilter.Filter | |||
| and org.apache.tools.ant.filters.TokenFilter.Tokenizer respectly. | |||
| They are defined the build file using <typedef/>. For | |||
| example a string filter that capitalizes words may be declared as: | |||
| <blockquote><pre> | |||
| package my.customant; | |||
| import org.apache.tools.ant.filters.TokenFilter; | |||
| public class Capitalize | |||
| implements TokenFilter.Filter | |||
| { | |||
| public String filter(String token) { | |||
| if (token.length() == 0) | |||
| return token; | |||
| return token.substring(0, 1).toUpperCase() + | |||
| token.substring(1); | |||
| } | |||
| } | |||
| </pre></blockquote> | |||
| This may be used as follows: | |||
| <blockquote><pre> | |||
| <typedef type="capitalize" classname="my.customant.Capitalize" | |||
| classpath="my.customant.path"/> | |||
| <copy file="input" tofile="output"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <stringtokenizer/> | |||
| <capitalize/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </pre></blockquote> | |||
| <HR> | |||
| <P align=center>Copyright © 2002-2003 Apache Software Foundation. All rights | |||
| @@ -0,0 +1,34 @@ | |||
| <?xml version="1.0"?> | |||
| <project default="cleanup" basedir="."> | |||
| <target name="init"> | |||
| <mkdir dir="result" /> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete dir="result"/> | |||
| </target> | |||
| <target name="dynamicfilter"> | |||
| <path id="test-classes"> | |||
| <pathelement location="../../../../build/testcases" /> | |||
| <pathelement path="${java.class.path}" /> | |||
| </path> | |||
| <typedef | |||
| name="customfilter" | |||
| classname="org.apache.tools.ant.filters.DynamicFilterTest$CustomFilter"> | |||
| <classpath refid="test-classes"/> | |||
| </typedef> | |||
| <concat destfile="result/input"> | |||
| hello world | |||
| </concat> | |||
| <copy file="result/input" tofile="result/dynamicfilter"> | |||
| <filterchain> | |||
| <customfilter replace="o" with="O"/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1,314 @@ | |||
| <?xml version="1.0"?> | |||
| <project default="cleanup" basedir="."> | |||
| <target name="init"> | |||
| <mkdir dir="result" /> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete dir="result"/> | |||
| </target> | |||
| <target name="tokenfilter"> | |||
| <copy file="input/linecontains.test" tofile="result/file1"> | |||
| <filterchain> | |||
| <tokenfilter/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="trimignore"> | |||
| <concat destfile="result/input"> | |||
| Hello | |||
| World | |||
| </concat> | |||
| <copy file="result/input" tofile="result/output" overwrite="yes"> | |||
| <filterchain> | |||
| <tokenfilter delimoutput="-"> | |||
| <trim/> | |||
| <ignoreblank/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| <concat> | |||
| <filelist dir="." files="result/output"/> | |||
| </concat> | |||
| </target> | |||
| <target name="trimfile"> | |||
| <concat destfile="result/trimfile"> | |||
| This is the contents of the trimmed file. | |||
| This is the second line. | |||
| <filterchain> | |||
| <trim byline="no"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="trimfilebyline"> | |||
| <concat destfile="result/trimfilebyline"> | |||
| This is the contents of the trimmed file. | |||
| This is the second line. | |||
| <filterchain> | |||
| <trim/> | |||
| <tokenfilter delimoutput="\n"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="filterreplacestring"> | |||
| <concat destfile="result/filterreplacestring"> | |||
| This is foo bar | |||
| <filterchain> | |||
| <replacestring from="foo" to="the"/> | |||
| <replacestring from="bar" to="moon"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="stringtokenizer"> | |||
| <concat destfile="result/input"> | |||
| This is a number | |||
| of words | |||
| </concat> | |||
| <copy file="result/input" tofile="result/output" overwrite="yes"> | |||
| <filterchain> | |||
| <tokenfilter delimoutput="#"> | |||
| <stringtokenizer/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| <concat> | |||
| <filelist dir="." files="result/output"/> | |||
| </concat> | |||
| </target> | |||
| <target name="unixlineoutput"> | |||
| <concat destfile="result/unixlineoutput"> | |||
| This is a number | |||
| of words | |||
| <filterchain> | |||
| <tokenfilter delimoutput="\n"> | |||
| <stringtokenizer/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="doslineoutput"> | |||
| <concat destfile="result/doslineoutput"> | |||
| This is a number | |||
| of words | |||
| <filterchain> | |||
| <tokenfilter delimoutput="\r\n"> | |||
| <stringtokenizer/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="filetokenizer"> | |||
| <concat destfile="result/input"> | |||
| This is a number | |||
| of words | |||
| </concat> | |||
| <copy file="result/input" tofile="result/filetokenizer"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <filetokenizer/> | |||
| <trim/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="replacestring"> | |||
| <concat destfile="result/replacestring"> | |||
| this is the sun | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <replacestring from="sun" to="moon"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="containsstring"> | |||
| <concat destfile="result/input"> | |||
| this is a line contains foo | |||
| this line does not | |||
| </concat> | |||
| <copy file="result/input" tofile="result/containsstring"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <containsstring contains="foo"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <!-- need to check for existance of regex --> | |||
| <target name="replaceregex"> | |||
| <concat destfile="result/input"> | |||
| hello Hello HELLO hello | |||
| cat Cat cat | |||
| Sun Sun Sun | |||
| WhiteSpace tab | |||
| This is a line with digits - 1234 -- there | |||
| </concat> | |||
| <copy file="result/input" tofile="result/replaceregex"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <replaceregex pattern="hello" replace="world" flags="gi"/> | |||
| <replaceregex pattern="cat" replace="dog" flags="g"/> | |||
| <replaceregex pattern="sun" replace="moon" flags="i"/> | |||
| <replaceregex pattern="WhiteSpace[ \t]+tab" | |||
| replace="found WhiteSpace"/> | |||
| <replaceregex pattern="This is a line with dig.* ([0-9]+).*" | |||
| replace="Found digits [\1]"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="filterreplaceregex"> | |||
| <concat destfile="result/filterreplaceregex"> | |||
| hello Hello HELLO hello | |||
| <filterchain> | |||
| <replaceregex pattern="hello" replace="world" flags="gi"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <!-- need to check for existance of regex --> | |||
| <target name="containsregex"> | |||
| <concat destfile="result/input"> | |||
| hello world | |||
| this is the moon | |||
| World here | |||
| </concat> | |||
| <copy file="result/input" tofile="result/containsregex"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <containsregex pattern="(hello|world)" flags="i"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="filtercontainsregex"> | |||
| <concat destfile="result/filtercontainsregex"> | |||
| hello world | |||
| this is the moon | |||
| World here | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <containsregex pattern="(hello|world)" flags="i"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <!-- need to check for existance of regex --> | |||
| <target name="containsregex2"> | |||
| <concat destfile="result/input"> | |||
| SUITE(TestSuite, bits); | |||
| here | |||
| </concat> | |||
| <copy file="result/input" tofile="result/containsregex2"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <containsregex | |||
| pattern="^ *SUITE\(.*,\s*(.*)\s*\).*" | |||
| replace="void register_\1();"/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="deletecharacters"> | |||
| <concat destfile="result/deletechars"> | |||
| This is some ### s | |||
| some **** | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <deletecharacters chars="#"/> | |||
| </tokenfilter> | |||
| <deletecharacters chars="*"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="scriptfilter"> | |||
| <concat destfile="result/input"> | |||
| hello world | |||
| </concat> | |||
| <copy file="result/input" tofile="result/scriptfilter"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <scriptfilter language="javascript"> | |||
| self.setToken(self.getToken().toUpperCase()); | |||
| </scriptfilter> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="scriptfilter2"> | |||
| <concat destfile="result/input"> | |||
| hello moon | |||
| </concat> | |||
| <copy file="result/input" tofile="result/scriptfilter2"> | |||
| <filterchain> | |||
| <scriptfilter language="javascript"> | |||
| self.setToken(self.getToken().toUpperCase()); | |||
| </scriptfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="customtokenfilter"> | |||
| <path id="test-classes"> | |||
| <pathelement location="../../../../build/testcases" /> | |||
| <pathelement path="${java.class.path}" /> | |||
| </path> | |||
| <typedef | |||
| name="capitalize" | |||
| classname="org.apache.tools.ant.filters.TokenFilterTest$Capitalize"> | |||
| <classpath refid="test-classes"/> | |||
| </typedef> | |||
| <concat destfile="result/input"> | |||
| hello world | |||
| </concat> | |||
| <copy file="result/input" tofile="result/custom"> | |||
| <filterchain> | |||
| <tokenfilter> | |||
| <stringtokenizer/> | |||
| <capitalize/> | |||
| </tokenfilter> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="hasscript"> | |||
| <script language="beanshell"> | |||
| i = 1; | |||
| </script> | |||
| </target> | |||
| <target name="hasregex"> | |||
| <concat destfile="result/replaceregexp"> | |||
| hello world | |||
| </concat> | |||
| <replaceregexp file="result/replaceregexp" | |||
| match="hello( )world" | |||
| replace="bye\1world"/> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1,918 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "Ant" and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.filters; | |||
| import java.io.IOException; | |||
| import java.io.Reader; | |||
| import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import java.util.Enumeration; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DynamicConfigurator; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Parameter; | |||
| import org.apache.tools.ant.types.RegularExpression; | |||
| import org.apache.tools.ant.types.Substitution; | |||
| import org.apache.tools.ant.util.regexp.Regexp; | |||
| /** | |||
| * This splits up input into tokens and passes | |||
| * the tokens to a sequence of filters. | |||
| * | |||
| * @author Peter Reilly | |||
| * @since Ant 1.6 | |||
| * @see BaseFilterReader | |||
| * @see ChainableReader | |||
| * @see DynamicConfigurator | |||
| */ | |||
| public class TokenFilter | |||
| extends BaseFilterReader | |||
| implements ChainableReader, DynamicConfigurator | |||
| { | |||
| /** | |||
| * input stream tokenizers implement this interface | |||
| */ | |||
| public interface Tokenizer { | |||
| /** | |||
| * get the next token from the input stream | |||
| * @param in the input stream | |||
| * @return the next token, or null for the end | |||
| * of the stream | |||
| */ | |||
| public String getToken(Reader in) | |||
| throws IOException; | |||
| /** | |||
| * return the string between tokens, after the | |||
| * previous token. | |||
| * @return the intra-token string | |||
| */ | |||
| public String getPostToken(); | |||
| } | |||
| /** | |||
| * string filters implement this interface | |||
| */ | |||
| public interface Filter { | |||
| /** | |||
| * filter and/of modify a string | |||
| * | |||
| * @param filter the string to filter | |||
| * @return the modified string or null if the | |||
| * string did not pass the filter | |||
| */ | |||
| public String filter(String string); | |||
| } | |||
| /** string filters */ | |||
| private Vector filters = new Vector(); | |||
| /** the tokenizer to use on the input stream */ | |||
| private Tokenizer tokenizer = null; | |||
| /** the output token termination */ | |||
| private String delimOutput = null; | |||
| /** the current string token from the input stream */ | |||
| private String line = null; | |||
| /** the position in the current string token */ | |||
| private int linePos = 0; | |||
| /** | |||
| * Constructor for "dummy" instances. | |||
| * | |||
| * @see BaseFilterReader#BaseFilterReader() | |||
| */ | |||
| public TokenFilter() { | |||
| super(); | |||
| } | |||
| /** | |||
| * Creates a new filtered reader. | |||
| * | |||
| * @param in A Reader object providing the underlying stream. | |||
| * Must not be <code>null</code>. | |||
| */ | |||
| public TokenFilter(final Reader in) { | |||
| super(in); | |||
| } | |||
| /** | |||
| * Returns the next character in the filtered stream, only including | |||
| * lines from the original stream which match all of the specified | |||
| * regular expressions. | |||
| * | |||
| * @return the next character in the resulting stream, or -1 | |||
| * if the end of the resulting stream has been reached | |||
| * | |||
| * @exception IOException if the underlying stream throws an IOException | |||
| * during reading | |||
| */ | |||
| public int read() throws IOException { | |||
| if (tokenizer == null) | |||
| tokenizer = new LineTokenizer(); | |||
| while (line == null || line.length() == 0) { | |||
| line = tokenizer.getToken(in); | |||
| if (line == null) | |||
| return -1; | |||
| for (Enumeration e = filters.elements(); e.hasMoreElements();) | |||
| { | |||
| Filter filter = (Filter) e.nextElement(); | |||
| line = filter.filter(line); | |||
| if (line == null) | |||
| break; | |||
| } | |||
| linePos = 0; | |||
| if (line != null) { | |||
| if (tokenizer.getPostToken().length() != 0) { | |||
| if (delimOutput != null) | |||
| line = line + delimOutput; | |||
| else | |||
| line = line + tokenizer.getPostToken(); | |||
| } | |||
| } | |||
| } | |||
| int ch = line.charAt(linePos); | |||
| linePos ++; | |||
| if (linePos == line.length()) | |||
| line = null; | |||
| return ch; | |||
| } | |||
| /** | |||
| * Creates a new TokenFilter using the passed in | |||
| * Reader for instantiation. | |||
| * | |||
| * @param reader A Reader object providing the underlying stream. | |||
| * | |||
| * @return a new filter based on this configuration | |||
| */ | |||
| public final Reader chain(final Reader reader) { | |||
| TokenFilter newFilter = new TokenFilter(reader); | |||
| newFilter.filters = filters; | |||
| newFilter.tokenizer = tokenizer; | |||
| newFilter.delimOutput = delimOutput; | |||
| newFilter.setProject(getProject()); | |||
| return newFilter; | |||
| } | |||
| /** | |||
| * set the output delimitor. | |||
| * @param delimOutput replaces the delim string returned by the | |||
| * tokenizer, it it present. | |||
| */ | |||
| public void setDelimOutput(String delimOutput) { | |||
| this.delimOutput = resolveBackSlash(delimOutput); | |||
| } | |||
| // ----------------------------------------- | |||
| // Predefined tokenizers | |||
| // ----------------------------------------- | |||
| /** | |||
| * add a line tokenizer - this is the default. | |||
| */ | |||
| public void addLineTokenizer(LineTokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| } | |||
| /** | |||
| * add a string tokenizer | |||
| */ | |||
| public void addStringTokenizer(StringTokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| } | |||
| /** | |||
| * add a file tokenizer | |||
| */ | |||
| public void addFileTokenizer(FileTokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| } | |||
| // ----------------------------------------- | |||
| // Predefined filters | |||
| // ----------------------------------------- | |||
| /** replace string filter */ | |||
| public void addReplaceString(ReplaceString filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** contains string filter */ | |||
| public void addContainsString(ContainsString filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** replace regex filter */ | |||
| public void addReplaceRegex(ReplaceRegex filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** contains regex filter */ | |||
| public void addContainsRegex(ContainsRegex filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** trim filter */ | |||
| public void addTrim(Trim filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** ignore blank filter */ | |||
| public void addIgnoreBlank(IgnoreBlank filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** delete chars */ | |||
| public void addDeleteCharacters(DeleteCharacters filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| public void add(Filter filter) { | |||
| filters.addElement(filter); | |||
| } | |||
| /** | |||
| * create the named datatype and check if it | |||
| * is a filter or a tokenizer | |||
| * | |||
| * @throws BuildException if unknown datatype or incorrect datatype | |||
| */ | |||
| public Object createDynamicElement(String name) | |||
| { | |||
| if (getProject() == null) | |||
| throw new BuildException( | |||
| "createDynamicElement.TokenFilter" + | |||
| " - Unable to get the project"); | |||
| Object obj = getProject().createDataType(name); | |||
| if (obj == null) | |||
| throw new BuildException("Unknown type " + name); | |||
| if (obj instanceof Filter) | |||
| filters.addElement(obj); | |||
| else if (obj instanceof Tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| tokenizer = (Tokenizer) obj; | |||
| } | |||
| else | |||
| throw new BuildException( | |||
| "type " + name + " is not a TokenFilter.Filter or " + | |||
| "TokenFiler.Tokenizer"); | |||
| return obj; | |||
| } | |||
| /** | |||
| * Needed for dynamic element support. | |||
| * | |||
| * @throws BuildException always | |||
| */ | |||
| public void setDynamicAttribute(String name, String value) { | |||
| throw new BuildException("Unknown attribute " + name); | |||
| } | |||
| // -------------------------------------------- | |||
| // | |||
| // Tokenizer Classes | |||
| // | |||
| // -------------------------------------------- | |||
| /** | |||
| * class to read the complete input into a string | |||
| */ | |||
| public static class FileTokenizer | |||
| implements Tokenizer | |||
| { | |||
| /** | |||
| * Get the complete input as a string | |||
| * | |||
| * @return the complete input | |||
| */ | |||
| public String getToken(Reader in) | |||
| throws IOException | |||
| { | |||
| StringBuffer output = new StringBuffer(); | |||
| char[] buffer = new char[8192]; | |||
| while (true) { | |||
| int nread = in.read(buffer, 0, 8192); | |||
| if (nread == -1) | |||
| break; | |||
| output.append(buffer, 0, nread); | |||
| } | |||
| if (output.length() == 0) | |||
| return null; | |||
| return output.toString(); | |||
| } | |||
| /** | |||
| * Return an empty string | |||
| * | |||
| * @return an empty string | |||
| */ | |||
| public String getPostToken() { | |||
| return ""; | |||
| } | |||
| } | |||
| /** | |||
| * class to tokenize the input as lines seperated | |||
| * by \r (mac style), \r\n (dos/windows style) or \n (unix style) | |||
| */ | |||
| public static class LineTokenizer | |||
| implements Tokenizer | |||
| { | |||
| String lineEnd = ""; | |||
| int pushed = -2; | |||
| public String getToken(Reader in) | |||
| throws IOException | |||
| { | |||
| int ch = -1; | |||
| if (pushed != -2) { | |||
| ch = pushed; | |||
| pushed = -2; | |||
| } | |||
| else | |||
| ch = in.read(); | |||
| if (ch == -1) { | |||
| return null; | |||
| } | |||
| lineEnd = ""; | |||
| StringBuffer line = new StringBuffer(); | |||
| int state = 0; | |||
| while (ch != -1) { | |||
| if (state == 0) { | |||
| if (ch == '\r') { | |||
| state = 1; | |||
| } | |||
| else if (ch == '\n') { | |||
| lineEnd = "\n"; | |||
| break; | |||
| } | |||
| else { | |||
| line.append((char) ch); | |||
| } | |||
| } | |||
| else { | |||
| state = 0; | |||
| if (ch == '\n') { | |||
| lineEnd = "\r\n"; | |||
| } | |||
| else { | |||
| pushed = ch; | |||
| lineEnd = "\r"; | |||
| } | |||
| break; | |||
| } | |||
| ch = in.read(); | |||
| } | |||
| if (ch == -1 && state == 1) { | |||
| lineEnd = "\r"; | |||
| } | |||
| return line.toString(); | |||
| } | |||
| public String getPostToken() { | |||
| return lineEnd; | |||
| } | |||
| } | |||
| /** | |||
| * class to tokenize the input as areas seperated | |||
| * by white space, or by a specified list of | |||
| * delim characters. Behaves like java.util.StringTokenizer. | |||
| * if the stream starts with delim characters, the first | |||
| * token will be an empty string (unless the treat tokens | |||
| * as delims flag is set). | |||
| */ | |||
| public static class StringTokenizer | |||
| implements Tokenizer | |||
| { | |||
| private String intraString = ""; | |||
| private int pushed = -2; | |||
| private char[] delims = null; | |||
| private boolean delimsAreTokens = false; | |||
| private boolean suppressDelims = false; | |||
| public void setDelims(String delims) { | |||
| this.delims = resolveBackSlash(delims).toCharArray(); | |||
| } | |||
| public void setDelimsAreTokens(boolean delimsAreTokens) { | |||
| this.delimsAreTokens = delimsAreTokens; | |||
| } | |||
| public void setSuppressDelims(boolean suppressDelims) { | |||
| this.suppressDelims = suppressDelims; | |||
| } | |||
| public String getToken(Reader in) | |||
| throws IOException | |||
| { | |||
| int ch = -1; | |||
| if (pushed != -2) { | |||
| ch = pushed; | |||
| pushed = -2; | |||
| } | |||
| else | |||
| ch = in.read(); | |||
| if (ch == -1) { | |||
| return null; | |||
| } | |||
| boolean inToken = true; | |||
| intraString = ""; | |||
| StringBuffer word = new StringBuffer(); | |||
| StringBuffer padding = new StringBuffer(); | |||
| while (ch != -1) { | |||
| char c = (char) ch; | |||
| boolean isDelim = isDelim(c); | |||
| if (inToken) { | |||
| if (isDelim) { | |||
| if (delimsAreTokens) { | |||
| if (word.length() == 0) { | |||
| word.append(c); | |||
| } | |||
| else { | |||
| pushed = ch; | |||
| } | |||
| break; | |||
| } | |||
| padding.append(c); | |||
| inToken = false; | |||
| } | |||
| else | |||
| word.append(c); | |||
| } | |||
| else { | |||
| if (isDelim) { | |||
| padding.append(c); | |||
| } | |||
| else { | |||
| pushed = ch; | |||
| break; | |||
| } | |||
| } | |||
| ch = in.read(); | |||
| } | |||
| intraString = padding.toString(); | |||
| return word.toString(); | |||
| } | |||
| public String getPostToken() { | |||
| if (suppressDelims) | |||
| return ""; | |||
| return intraString; | |||
| } | |||
| private boolean isDelim(char ch) { | |||
| if (delims == null) | |||
| return Character.isWhitespace(ch); | |||
| for (int i = 0; i < delims.length; ++i) | |||
| if (delims[i] == ch) | |||
| return true; | |||
| return false; | |||
| } | |||
| } | |||
| // -------------------------------------------- | |||
| // | |||
| // Filter classes | |||
| // | |||
| // -------------------------------------------- | |||
| public static abstract class ChainableReaderFilter | |||
| implements ChainableReader, Filter | |||
| { | |||
| private boolean byLine = true; | |||
| public void setByLine(boolean byLine) { | |||
| this.byLine = byLine; | |||
| } | |||
| public Reader chain(Reader reader) { | |||
| TokenFilter tokenFilter = new TokenFilter(reader); | |||
| if (!byLine) | |||
| tokenFilter.addFileTokenizer(new FileTokenizer()); | |||
| tokenFilter.add(this); | |||
| return tokenFilter; | |||
| } | |||
| } | |||
| /** | |||
| * Simple replace string filter. | |||
| */ | |||
| public static class ReplaceString | |||
| extends ChainableReaderFilter | |||
| { | |||
| private String from; | |||
| private String to; | |||
| public void setFrom(String from) { | |||
| this.from = from; | |||
| } | |||
| public void setTo(String to) { | |||
| this.to = to; | |||
| } | |||
| /** | |||
| * CAP from the Replace task | |||
| */ | |||
| public String filter(String line) { | |||
| if (from == null) | |||
| throw new BuildException("Missing from in stringreplace"); | |||
| StringBuffer ret = new StringBuffer(); | |||
| int start = 0; | |||
| int found = line.indexOf(from); | |||
| while (found >= 0) { | |||
| // write everything up to the from | |||
| if (found > start) { | |||
| ret.append(line.substring(start, found)); | |||
| } | |||
| // write the replacement to | |||
| if (to != null) { | |||
| ret.append(to); | |||
| } | |||
| // search again | |||
| start = found + from.length(); | |||
| found = line.indexOf(line, start); | |||
| } | |||
| // write the remaining characters | |||
| if (line.length() > start) { | |||
| ret.append(line.substring(start, line.length())); | |||
| } | |||
| return ret.toString(); | |||
| } | |||
| } | |||
| /** | |||
| * Simple filter to filter lines contains strings | |||
| */ | |||
| public static class ContainsString | |||
| implements Filter | |||
| { | |||
| private String contains; | |||
| public void setContains(String contains) { | |||
| this.contains = contains; | |||
| } | |||
| public String filter(String line) { | |||
| if (contains == null) | |||
| throw new BuildException("Missing contains in containsstring"); | |||
| if (line.indexOf(contains) > -1) | |||
| return line; | |||
| return null; | |||
| } | |||
| } | |||
| /** | |||
| * filter to replace regex. | |||
| */ | |||
| public static class ReplaceRegex | |||
| extends ChainableReaderFilter | |||
| { | |||
| private String from; | |||
| private String to; | |||
| private Project project; | |||
| private RegularExpression regularExpression; | |||
| private Substitution substitution; | |||
| private boolean initialized = false; | |||
| private String flags = ""; | |||
| private int options; | |||
| private Regexp regexp; | |||
| public void setPattern(String from) { | |||
| this.from = from; | |||
| } | |||
| public void setReplace(String to) { | |||
| this.to = to; | |||
| } | |||
| public void setProject(Project p) { | |||
| this.project = p; | |||
| } | |||
| public void setFlags(String flags) { | |||
| this.flags = flags; | |||
| } | |||
| private void initialize() { | |||
| if (initialized) | |||
| return; | |||
| options = convertRegexOptions(flags); | |||
| if (from == null) | |||
| throw new BuildException("Missing pattern in replaceregex"); | |||
| regularExpression = new RegularExpression(); | |||
| regularExpression.setPattern(from); | |||
| regexp = regularExpression.getRegexp(project); | |||
| if (to == null) | |||
| to = ""; | |||
| substitution = new Substitution(); | |||
| substitution.setExpression(to); | |||
| } | |||
| public String filter(String line) { | |||
| initialize(); | |||
| if (!regexp.matches(line, options)) { | |||
| return line; | |||
| } | |||
| return regexp.substitute( | |||
| line, substitution.getExpression(project), options); | |||
| } | |||
| } | |||
| /** | |||
| * filter to filter tokens matching regular expressions. | |||
| */ | |||
| public static class ContainsRegex | |||
| extends ChainableReaderFilter | |||
| { | |||
| private String from; | |||
| private String to; | |||
| private Project project; | |||
| private RegularExpression regularExpression; | |||
| private Substitution substitution; | |||
| private boolean initialized = false; | |||
| private String flags = ""; | |||
| private int options; | |||
| private Regexp regexp; | |||
| public void setPattern(String from) { | |||
| this.from = from; | |||
| } | |||
| public void setReplace(String to) { | |||
| this.to = to; | |||
| } | |||
| public void setProject(Project p) { | |||
| this.project = p; | |||
| } | |||
| public void setFlags(String flags) { | |||
| this.flags = flags; | |||
| } | |||
| private void initialize() { | |||
| if (initialized) | |||
| return; | |||
| options = convertRegexOptions(flags); | |||
| if (from == null) | |||
| throw new BuildException("Missing from in containsregex"); | |||
| regularExpression = new RegularExpression(); | |||
| regularExpression.setPattern(from); | |||
| regexp = regularExpression.getRegexp(project); | |||
| if (to == null) | |||
| return; | |||
| substitution = new Substitution(); | |||
| substitution.setExpression(to); | |||
| } | |||
| public String filter(String line) { | |||
| initialize(); | |||
| if (!regexp.matches(line, options)) { | |||
| return null; | |||
| } | |||
| if (substitution == null) | |||
| return line; | |||
| return regexp.substitute( | |||
| line, substitution.getExpression(project), options); | |||
| } | |||
| } | |||
| /** Filter to trim white space */ | |||
| public static class Trim | |||
| extends ChainableReaderFilter | |||
| { | |||
| public String filter(String line) { | |||
| return line.trim(); | |||
| } | |||
| } | |||
| /** Filter remove empty tokens */ | |||
| public static class IgnoreBlank | |||
| extends ChainableReaderFilter | |||
| { | |||
| public String filter(String line) { | |||
| if (line.trim().length() == 0) | |||
| return null; | |||
| return line; | |||
| } | |||
| } | |||
| /** | |||
| * Filter to delete characters | |||
| */ | |||
| public static class DeleteCharacters | |||
| implements Filter, ChainableReader | |||
| { | |||
| // Attributes | |||
| /** the list of characters to remove from the input */ | |||
| private String deleteChars = ""; | |||
| /** Set the list of characters to delete */ | |||
| public void setChars(String deleteChars) { | |||
| this.deleteChars = resolveBackSlash(deleteChars); | |||
| } | |||
| /** remove characters from a string */ | |||
| public String filter(String string) { | |||
| StringBuffer output = new StringBuffer(string.length()); | |||
| for (int i = 0; i < string.length(); ++i) { | |||
| char ch = string.charAt(i); | |||
| if (! isDeleteCharacter(ch)) | |||
| output.append(ch); | |||
| } | |||
| return output.toString(); | |||
| } | |||
| /** | |||
| * factory method to provide a reader that removes | |||
| * the characters from a reader as part of a filter | |||
| * chain | |||
| */ | |||
| public Reader chain(Reader reader) { | |||
| return new BaseFilterReader(reader) { | |||
| public int read() | |||
| throws IOException | |||
| { | |||
| while (true) { | |||
| int c = in.read(); | |||
| if (c == -1) | |||
| return c; | |||
| if (! isDeleteCharacter((char) c)) | |||
| return c; | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| /** check if the character c is to be deleted */ | |||
| private boolean isDeleteCharacter(char c) { | |||
| for (int d = 0; d < deleteChars.length(); ++d) { | |||
| if (deleteChars.charAt(d) == c) { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| // -------------------------------------------------------- | |||
| // static utility methods - could be placed somewhere else | |||
| // -------------------------------------------------------- | |||
| /** | |||
| * xml does not do "c" like interpetation of strings. | |||
| * i.e. \n\r\t etc. | |||
| * this methid processes \n, \r, \t, \f, \\ | |||
| * also subs \s -> " \n\r\t\f" | |||
| * a trailing '\' will be ignored | |||
| * | |||
| * @param input raw string with possible embedded '\'s | |||
| * @return converted string | |||
| */ | |||
| public static String resolveBackSlash(String input) { | |||
| StringBuffer b = new StringBuffer(); | |||
| boolean backSlashSeen = false; | |||
| for (int i = 0; i < input.length(); ++i) { | |||
| char c = input.charAt(i); | |||
| if (! backSlashSeen) { | |||
| if (c == '\\') | |||
| backSlashSeen = true; | |||
| else | |||
| b.append(c); | |||
| } | |||
| else { | |||
| switch (c) { | |||
| case '\\': | |||
| b.append((char) '\\'); | |||
| break; | |||
| case 'n': | |||
| b.append((char) '\n'); | |||
| break; | |||
| case 'r': | |||
| b.append((char) '\r'); | |||
| break; | |||
| case 't': | |||
| b.append((char) '\t'); | |||
| break; | |||
| case 'f': | |||
| b.append((char) '\f'); | |||
| break; | |||
| case 's': | |||
| b.append(" \t\n\r\f"); | |||
| break; | |||
| default: | |||
| b.append(c); | |||
| } | |||
| backSlashSeen = false; | |||
| } | |||
| } | |||
| return b.toString(); | |||
| } | |||
| /** | |||
| * convert regex option flag characters to regex options | |||
| * <dl> | |||
| * <li>g - Regexp.REPLACE_ALL</li> | |||
| * <li>i - Regexp.MATCH_CASE_INSENSITIVE</li> | |||
| * <li>m - Regexp.MATCH_MULTILINE</li> | |||
| * <li>s - Regexp.MATCH_SINGLELINE</li> | |||
| * </dl> | |||
| */ | |||
| public static int convertRegexOptions(String flags) { | |||
| if (flags == null) | |||
| return 0; | |||
| int options = 0; | |||
| if (flags.indexOf('g') != -1) | |||
| options |= Regexp.REPLACE_ALL; | |||
| if (flags.indexOf('i') != -1) | |||
| options |= Regexp.MATCH_CASE_INSENSITIVE; | |||
| if (flags.indexOf('m') != -1) | |||
| options |= Regexp.MATCH_MULTILINE; | |||
| if (flags.indexOf('s') != -1) | |||
| options |= Regexp.MATCH_SINGLELINE; | |||
| return options; | |||
| } | |||
| } | |||
| @@ -54,7 +54,13 @@ | |||
| package org.apache.tools.ant.types; | |||
| import java.util.Vector; | |||
| import java.io.StringWriter; | |||
| import java.io.Reader; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DynamicConfigurator; | |||
| import org.apache.tools.ant.filters.ChainableReader; | |||
| import org.apache.tools.ant.filters.ClassConstants; | |||
| import org.apache.tools.ant.filters.EscapeUnicode; | |||
| import org.apache.tools.ant.filters.ExpandProperties; | |||
| @@ -68,13 +74,19 @@ import org.apache.tools.ant.filters.StripLineBreaks; | |||
| import org.apache.tools.ant.filters.StripLineComments; | |||
| import org.apache.tools.ant.filters.TabsToSpaces; | |||
| import org.apache.tools.ant.filters.TailFilter; | |||
| import org.apache.tools.ant.filters.TokenFilter; | |||
| import org.apache.tools.ant.filters.BaseFilterReader; | |||
| import org.apache.tools.ant.taskdefs.Concat; | |||
| /** | |||
| * FilterChain may contain a chained set of filter readers. | |||
| * | |||
| * @author Magesh Umasankar | |||
| */ | |||
| public final class FilterChain extends DataType implements Cloneable { | |||
| public final class FilterChain extends DataType | |||
| implements Cloneable, DynamicConfigurator | |||
| { | |||
| private Vector filterReaders = new Vector(); | |||
| @@ -145,6 +157,69 @@ public final class FilterChain extends DataType implements Cloneable { | |||
| filterReaders.addElement(escapeUnicode); | |||
| } | |||
| /** | |||
| * @since Ant 1.6 | |||
| */ | |||
| public final void addTokenFilter(final TokenFilter tokenFilter) { | |||
| filterReaders.addElement(tokenFilter); | |||
| } | |||
| /** | |||
| * delete characters filter | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addDeleteCharacters(TokenFilter.DeleteCharacters filter) { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * containsregex | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addContainsRegex(TokenFilter.ContainsRegex filter) | |||
| { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * replaceregex | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addReplaceRegex(TokenFilter.ReplaceRegex filter) | |||
| { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * trim | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addTrim(TokenFilter.Trim filter) | |||
| { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * replacestring | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addReplaceString( | |||
| TokenFilter.ReplaceString filter) | |||
| { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * ignoreBlank | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void addIgnoreBlank( | |||
| TokenFilter.IgnoreBlank filter) | |||
| { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| /** | |||
| * Makes this instance in effect a reference to another FilterChain | |||
| * instance. | |||
| @@ -171,4 +246,38 @@ public final class FilterChain extends DataType implements Cloneable { | |||
| super.setRefid(r); | |||
| } | |||
| /** | |||
| * create the named datatype and check if it | |||
| * is a filter. | |||
| * | |||
| * @throws BuildException if unknown datatype or incorrect datatype | |||
| * @since Ant 1.6 | |||
| */ | |||
| public Object createDynamicElement(String name) | |||
| { | |||
| if (getProject() == null) | |||
| throw new BuildException("Unable to get the project"); | |||
| Object obj = getProject().createDataType(name); | |||
| if (obj == null) | |||
| throw new BuildException("Unknown type " + name); | |||
| if (! (obj instanceof ChainableReader)) | |||
| throw new BuildException( | |||
| "type " + name + " is not a filterreader"); | |||
| filterReaders.addElement(obj); | |||
| return obj; | |||
| } | |||
| /** | |||
| * Needed for dynamic element support. | |||
| * | |||
| * @throws BuildException always | |||
| */ | |||
| public void setDynamicAttribute(String name, String value) { | |||
| throw new BuildException("Unknown attribute " + name); | |||
| } | |||
| } | |||
| @@ -16,3 +16,5 @@ extensionSet=org.apache.tools.ant.taskdefs.optional.extension.ExtensionSet | |||
| extension=org.apache.tools.ant.taskdefs.optional.extension.ExtensionAdapter | |||
| libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet | |||
| selector=org.apache.tools.ant.types.selectors.SelectSelector | |||
| scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter | |||
| @@ -0,0 +1,269 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "Ant" and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.types.optional; | |||
| import org.apache.tools.ant.filters.TokenFilter; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import org.apache.bsf.BSFException; | |||
| import org.apache.bsf.BSFManager; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Most of this is CAP (Cut And Paste) from the Script task | |||
| * ScriptFilter class, implements TokenFilter.Filter | |||
| * for scripts to use. | |||
| * This provides the same beans as the Script Task | |||
| * to a script. | |||
| * The script is meant to use get self.token and | |||
| * set self.token in the reply. | |||
| */ | |||
| public class ScriptFilter | |||
| extends TokenFilter.ChainableReaderFilter | |||
| { | |||
| /** The current project - set by ant reflection */ | |||
| private Project project; | |||
| /** The language - attribute of element */ | |||
| private String language; | |||
| /** The script - inline text or external file */ | |||
| private String script = ""; | |||
| /** The beans - see ScriptTask */ | |||
| private Hashtable beans = new Hashtable(); | |||
| /** Has this object been initialized ? */ | |||
| private boolean initialized = false; | |||
| /** the BSF manager */ | |||
| private BSFManager manager; | |||
| /** the token used by the script */ | |||
| private String token; | |||
| /** Called by ant reflection to set the project */ | |||
| public void setProject(Project project) { | |||
| this.project = project; | |||
| } | |||
| /** this is provided to allow easier CAP from the ScriptTask */ | |||
| private Project getProject() { | |||
| return project; | |||
| } | |||
| /** | |||
| * Defines the language (required). | |||
| * | |||
| * @param msg Sets the value for the script variable. | |||
| */ | |||
| public void setLanguage(String language) { | |||
| this.language = language; | |||
| } | |||
| /** | |||
| * Add a list of named objects to the list to be exported to the script | |||
| * CAP from taskdefs.optional.Script | |||
| */ | |||
| private void addBeans(Hashtable dictionary) { | |||
| for (Enumeration e = dictionary.keys(); e.hasMoreElements();) { | |||
| String key = (String) e.nextElement(); | |||
| boolean isValid = key.length() > 0 && | |||
| Character.isJavaIdentifierStart(key.charAt(0)); | |||
| for (int i = 1; isValid && i < key.length(); i++) { | |||
| isValid = Character.isJavaIdentifierPart(key.charAt(i)); | |||
| } | |||
| try { | |||
| if (isValid) { | |||
| beans.put(key, dictionary.get(key)); | |||
| } | |||
| } | |||
| catch (Throwable t) { | |||
| throw new BuildException(t); | |||
| //System.err.println("What the helll"); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Initialize, mostly CAP from taskdefs.option.Script#execute() | |||
| * | |||
| * @exception BuildException if someting goes wrong | |||
| */ | |||
| private void init() throws BuildException { | |||
| if (initialized) | |||
| return; | |||
| initialized = true; | |||
| if (language == null) | |||
| throw new BuildException( | |||
| "scriptfilter: language is not defined"); | |||
| try { | |||
| addBeans(getProject().getProperties()); | |||
| addBeans(getProject().getUserProperties()); | |||
| addBeans(getProject().getTargets()); | |||
| addBeans(getProject().getReferences()); | |||
| beans.put("project", getProject()); | |||
| beans.put("self", this); | |||
| manager = new BSFManager (); | |||
| for (Enumeration e = beans.keys() ; e.hasMoreElements() ;) { | |||
| String key = (String) e.nextElement(); | |||
| Object value = beans.get(key); | |||
| manager.declareBean(key, value, value.getClass()); | |||
| } | |||
| } | |||
| catch (BSFException e) { | |||
| Throwable t = e; | |||
| Throwable te = e.getTargetException(); | |||
| if (te != null) { | |||
| if (te instanceof BuildException) { | |||
| throw (BuildException) te; | |||
| } else { | |||
| t = te; | |||
| } | |||
| } | |||
| throw new BuildException(t); | |||
| } | |||
| } | |||
| /** | |||
| * The current token | |||
| * | |||
| * @param token the string filtered by the script | |||
| */ | |||
| public void setToken(String token) { | |||
| this.token = token; | |||
| } | |||
| /** | |||
| * The current token | |||
| * | |||
| * @return the string filtered by the script | |||
| */ | |||
| public String getToken() { | |||
| return token; | |||
| } | |||
| /** | |||
| * Called filter the token. | |||
| * This sets the token in this object, calls | |||
| * the script and returns the token. | |||
| * | |||
| * @param token the token to be filtered | |||
| * @return the filtered token | |||
| */ | |||
| public String filter(String token) { | |||
| init(); | |||
| setToken(token); | |||
| try { | |||
| manager.exec(language, "<ANT>", 0, 0, script); | |||
| return getToken(); | |||
| } | |||
| catch (BSFException be) { | |||
| Throwable t = be; | |||
| Throwable te = be.getTargetException(); | |||
| if (te != null) { | |||
| if (te instanceof BuildException) { | |||
| throw (BuildException) te; | |||
| } else { | |||
| t = te; | |||
| } | |||
| } | |||
| throw new BuildException(t); | |||
| } | |||
| } | |||
| /** | |||
| * Load the script from an external file ; optional. | |||
| * | |||
| * @param msg Sets the value for the script variable. | |||
| */ | |||
| public void setSrc(String fileName) { | |||
| File file = new File(fileName); | |||
| if (!file.exists()) { | |||
| throw new BuildException("file " + fileName + " not found."); | |||
| } | |||
| int count = (int) file.length(); | |||
| byte data[] = new byte[count]; | |||
| try { | |||
| FileInputStream inStream = new FileInputStream(file); | |||
| inStream.read(data); | |||
| inStream.close(); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| script += new String(data); | |||
| } | |||
| /** | |||
| * The script text. | |||
| * | |||
| * @param msg Sets the value for the script variable. | |||
| */ | |||
| public void addText(String text) { | |||
| this.script += text; | |||
| } | |||
| } | |||
| @@ -0,0 +1,167 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "Ant" and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.filters; | |||
| import java.io.File; | |||
| import java.io.Reader; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * @author Peter Reilly | |||
| */ | |||
| public class DynamicFilterTest extends BuildFileTest { | |||
| public DynamicFilterTest(String name) { | |||
| super(name); | |||
| } | |||
| public void setUp() { | |||
| configureProject("src/etc/testcases/filters/dynamicfilter.xml"); | |||
| executeTarget("init"); | |||
| } | |||
| public void tearDown() { | |||
| executeTarget("cleanup"); | |||
| } | |||
| public void testCustomFilter() throws IOException { | |||
| expectFileContains("dynamicfilter", "result/dynamicfilter", | |||
| "hellO wOrld"); | |||
| } | |||
| // ------------------------------------------------------ | |||
| // Helper methods | |||
| // ----------------------------------------------------- | |||
| private void assertStringContains(String string, String contains) { | |||
| assertTrue("[" + string + "] does not contain [" + contains +"]", | |||
| string.indexOf(contains) > -1); | |||
| } | |||
| private void assertStringNotContains(String string, String contains) { | |||
| assertTrue("[" + string + "] does contain [" + contains +"]", | |||
| string.indexOf(contains) == -1); | |||
| } | |||
| private String getFileString(String filename) | |||
| throws IOException | |||
| { | |||
| Reader r = null; | |||
| try { | |||
| r = new FileReader(getProject().resolveFile(filename)); | |||
| return FileUtils.newFileUtils().readFully(r); | |||
| } | |||
| finally { | |||
| try {r.close();} catch (Throwable ignore) {} | |||
| } | |||
| } | |||
| private String getFileString(String target, String filename) | |||
| throws IOException | |||
| { | |||
| executeTarget(target); | |||
| return getFileString(filename); | |||
| } | |||
| private void expectFileContains(String name, String contains) | |||
| throws IOException | |||
| { | |||
| String content = getFileString(name); | |||
| assertTrue( | |||
| "expecting file " + name + " to contain " + contains + | |||
| " but got " + content, content.indexOf(contains) > -1); | |||
| } | |||
| private void expectFileContains( | |||
| String target, String name, String contains) | |||
| throws IOException | |||
| { | |||
| executeTarget(target); | |||
| expectFileContains(name, contains); | |||
| } | |||
| public static class CustomFilter implements ChainableReader { | |||
| char replace = 'x'; | |||
| char with = 'y'; | |||
| public void setReplace(char replace) { | |||
| this.replace = replace; | |||
| } | |||
| public void setWith(char with) { | |||
| this.with = with; | |||
| } | |||
| public Reader chain(final Reader rdr) { | |||
| return new BaseFilterReader(rdr) { | |||
| public int read() | |||
| throws IOException | |||
| { | |||
| int c = in.read(); | |||
| if (c == replace) | |||
| return with; | |||
| else | |||
| return c; | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,319 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "Ant" and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.filters; | |||
| import java.io.File; | |||
| import java.io.Reader; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * @author Peter Reilly | |||
| */ | |||
| public class TokenFilterTest extends BuildFileTest { | |||
| public TokenFilterTest(String name) { | |||
| super(name); | |||
| } | |||
| public void setUp() { | |||
| configureProject("src/etc/testcases/filters/tokenfilter.xml"); | |||
| executeTarget("init"); | |||
| } | |||
| public void tearDown() { | |||
| //executeTarget("cleanup"); | |||
| } | |||
| /** make sure tokenfilter exists */ | |||
| public void testTokenfilter() throws IOException { | |||
| executeTarget("tokenfilter"); | |||
| } | |||
| public void testTrimignore() throws IOException { | |||
| expectLogContaining("trimignore", "Hello-World"); | |||
| } | |||
| public void testStringTokenizer() throws IOException { | |||
| expectLogContaining( | |||
| "stringtokenizer", "#This#is#a#number#of#words#"); | |||
| } | |||
| public void testUnixLineOutput() throws IOException { | |||
| expectFileContains( | |||
| "unixlineoutput", "result/unixlineoutput", | |||
| "\nThis\nis\na\nnumber\nof\nwords\n"); | |||
| } | |||
| public void testDosLineOutput() throws IOException { | |||
| expectFileContains( | |||
| "doslineoutput", "result/doslineoutput", | |||
| "\r\nThis\r\nis\r\na\r\nnumber\r\nof\r\nwords\r\n"); | |||
| } | |||
| public void testFileTokenizer() throws IOException { | |||
| String contents = getFileString( | |||
| "filetokenizer", "result/filetokenizer"); | |||
| assertStringContains(contents, " of words"); | |||
| assertStringNotContains(contents, " This is"); | |||
| } | |||
| public void testReplaceString() throws IOException { | |||
| expectFileContains( | |||
| "replacestring", "result/replacestring", | |||
| "this is the moon"); | |||
| } | |||
| public void testContainsString() throws IOException { | |||
| String contents = getFileString( | |||
| "containsstring", "result/containsstring"); | |||
| assertStringContains(contents, "this is a line contains foo"); | |||
| assertStringNotContains(contents, "this line does not"); | |||
| } | |||
| public void testReplaceRegex() throws IOException { | |||
| if (! hasRegex("testReplaceRegex")) | |||
| return; | |||
| String contents = getFileString( | |||
| "replaceregex", "result/replaceregex"); | |||
| assertStringContains(contents, "world world world world"); | |||
| assertStringContains(contents, "dog Cat dog"); | |||
| assertStringContains(contents, "moon Sun Sun"); | |||
| assertStringContains(contents, "found WhiteSpace"); | |||
| assertStringContains(contents, "Found digits [1234]"); | |||
| assertStringNotContains(contents, "This is a line with digits"); | |||
| } | |||
| public void testFilterReplaceRegex() throws IOException { | |||
| if (! hasRegex("testFilterReplaceRegex")) | |||
| return; | |||
| String contents = getFileString( | |||
| "filterreplaceregex", "result/filterreplaceregex"); | |||
| assertStringContains(contents, "world world world world"); | |||
| } | |||
| public void testTrimFile() throws IOException { | |||
| String contents = getFileString( | |||
| "trimfile", "result/trimfile"); | |||
| assertTrue("no ws at start", contents.startsWith("This is th")); | |||
| assertTrue("no ws at end", contents.endsWith("second line.")); | |||
| assertStringContains(contents, " This is the second"); | |||
| } | |||
| public void testTrimFileByLine() throws IOException { | |||
| String contents = getFileString( | |||
| "trimfilebyline", "result/trimfilebyline"); | |||
| assertFalse("no ws at start", contents.startsWith("This is th")); | |||
| assertFalse("no ws at end", contents.endsWith("second line.")); | |||
| assertStringNotContains(contents, " This is the second"); | |||
| assertStringContains(contents, "file.\nThis is the second"); | |||
| } | |||
| public void testFilterReplaceString() throws IOException { | |||
| String contents = getFileString( | |||
| "filterreplacestring", "result/filterreplacestring"); | |||
| assertStringContains(contents, "This is the moon"); | |||
| } | |||
| public void testContainsRegex() throws IOException { | |||
| if (! hasRegex("testContainsRegex")) | |||
| return; | |||
| String contents = getFileString( | |||
| "containsregex", "result/containsregex"); | |||
| assertStringContains(contents, "hello world"); | |||
| assertStringNotContains(contents, "this is the moon"); | |||
| assertStringContains(contents, "World here"); | |||
| } | |||
| public void testFilterContainsRegex() throws IOException { | |||
| if (! hasRegex("testFilterContainsRegex")) | |||
| return; | |||
| String contents = getFileString( | |||
| "filtercontainsregex", "result/filtercontainsregex"); | |||
| assertStringContains(contents, "hello world"); | |||
| assertStringNotContains(contents, "this is the moon"); | |||
| assertStringContains(contents, "World here"); | |||
| } | |||
| public void testContainsRegex2() throws IOException { | |||
| if (! hasRegex("testContainsRegex2")) | |||
| return; | |||
| String contents = getFileString( | |||
| "containsregex2", "result/containsregex2"); | |||
| assertStringContains(contents, "void register_bits();"); | |||
| } | |||
| public void testDeleteCharacters() throws IOException { | |||
| String contents = getFileString( | |||
| "deletecharacters", "result/deletechars"); | |||
| assertStringNotContains(contents, "#"); | |||
| assertStringNotContains(contents, "*"); | |||
| assertStringContains(contents, "This is some "); | |||
| } | |||
| public void testScriptFilter() throws IOException { | |||
| if (! hasScript("testScriptFilter")) | |||
| return; | |||
| expectFileContains("scriptfilter", "result/scriptfilter", | |||
| "HELLO WORLD"); | |||
| } | |||
| public void testScriptFilter2() throws IOException { | |||
| if (! hasScript("testScriptFilter")) | |||
| return; | |||
| expectFileContains("scriptfilter2", "result/scriptfilter2", | |||
| "HELLO MOON"); | |||
| } | |||
| public void testCustomTokenFilter() throws IOException { | |||
| expectFileContains("customtokenfilter", "result/custom", | |||
| "Hello World"); | |||
| } | |||
| // ------------------------------------------------------ | |||
| // Helper methods | |||
| // ----------------------------------------------------- | |||
| private boolean hasScript(String test) { | |||
| try { | |||
| executeTarget("hasscript"); | |||
| } | |||
| catch (Throwable ex) { | |||
| System.out.println( | |||
| test + ": skipped - script not present "); | |||
| ex.printStackTrace(System.out); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| private boolean hasRegex(String test) { | |||
| try { | |||
| executeTarget("hasregex"); | |||
| expectFileContains("result/replaceregexp", "bye world"); | |||
| } | |||
| catch (Throwable ex) { | |||
| System.out.println(test + ": skipped - regex not present " | |||
| + ex); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| private void assertStringContains(String string, String contains) { | |||
| assertTrue("[" + string + "] does not contain [" + contains +"]", | |||
| string.indexOf(contains) > -1); | |||
| } | |||
| private void assertStringNotContains(String string, String contains) { | |||
| assertTrue("[" + string + "] does contain [" + contains +"]", | |||
| string.indexOf(contains) == -1); | |||
| } | |||
| private String getFileString(String filename) | |||
| throws IOException | |||
| { | |||
| Reader r = null; | |||
| try { | |||
| r = new FileReader(getProject().resolveFile(filename)); | |||
| return FileUtils.newFileUtils().readFully(r); | |||
| } | |||
| finally { | |||
| try {r.close();} catch (Throwable ignore) {} | |||
| } | |||
| } | |||
| private String getFileString(String target, String filename) | |||
| throws IOException | |||
| { | |||
| executeTarget(target); | |||
| return getFileString(filename); | |||
| } | |||
| private void expectFileContains(String name, String contains) | |||
| throws IOException | |||
| { | |||
| String content = getFileString(name); | |||
| assertTrue( | |||
| "expecting file " + name + " to contain " + contains + | |||
| " but got " + content, content.indexOf(contains) > -1); | |||
| } | |||
| private void expectFileContains( | |||
| String target, String name, String contains) | |||
| throws IOException | |||
| { | |||
| executeTarget(target); | |||
| expectFileContains(name, contains); | |||
| } | |||
| public static class Capitalize | |||
| implements TokenFilter.Filter | |||
| { | |||
| public String filter(String token) { | |||
| if (token.length() == 0) | |||
| return token; | |||
| return token.substring(0, 1).toUpperCase() + | |||
| token.substring(1); | |||
| } | |||
| } | |||
| } | |||