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