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>
   &lt;filterreader 
classname=&quot;org.apache.tools.ant.filters.StripLineComments&quot;&gt;
  -  &lt;param type=&quot;comment&quot; value="#&quot;/&gt;
  +  &lt;param type=&quot;comment&quot; value=&quote;#&quot;/&gt;
     &lt;param type=&quot;comment&quot; value=&quot;--&quot;/&gt;
     &lt;param type=&quot;comment&quot; value=&quot;REM &quot;/&gt;
     &lt;param type=&quot;comment&quot; value=&quot;rem &quot;/&gt;
  @@ -785,6 +787,480 @@
     &lt;/filterchain&gt;
   &lt;/loadfile&gt;
   </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>
  +&lt;deletecharacters chars="\t\r"/&gt;
  +</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>
  +&lt;tokenfilter delimoutput=&quot;\n&quot;/&gt;
  +</PRE></BLOCKQUOTE>
  +
  +
  +Remove blank lines.
  +<BLOCKQUOTE><PRE>
  +&lt;tokenfilter&gt;
  +    &lt;ignoreblank/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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>
  +&lt;tokenfilter&gt;
  +      &lt;filetokenizer/&gt;
  +      &lt;replaceregex pattern="([\n\r]+[ \t]*|^[ \t]*)package"
  +                    flags="s"
  +                    replace="\1//package"/&gt;
  +&lt;/tokenfilter&gt;
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;stringtokenizer/&gt;
  +    &lt;replaceregex pattern="(.+)" replace="[\1]"/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;replacestring from="sun" to="moon"/&gt;
  +&lt;/tokenfilter&gt;
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;containsstring contains="foo"/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;replaceregex pattern="hello" replace="world" flags="gi"/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;containsregex pattern="(hello|world)" flags="i"/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</PRE></BLOCKQUOTE>
  +
  +This example replaces lines like "SUITE(TestSuite, bits);" with
  +"void register_bits();" and removes other lines.
  +
  +<BLOCKQUOTE><PRE>
  +&lt;tokenfilter&gt;
  +    &lt;containsregex
  +        pattern="^ *SUITE\(.*,\s*(.*)\s*\).*"
  +        replace="void register_\1();"/&gt;
  +&lt;/tokenfilter&gt;
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;deletecharacters chars="\t"/&gt;
  +    &lt;trim/&gt;
  +    &lt;ignoreblank/&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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>
  +&lt;tokenfilter&gt;
  +    &lt;scriptfilter language="javascript"&gt;
  +        self.setToken(self.getToken().toUpperCase());
  +    &lt;/scriptfilter&gt;
  +&lt;/tokenfilter&gt;
  +
  +</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 &lt;typedef/&gt;. 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>
  +  &lt;typedef type="capitalize" classname="my.customant.Capitalize"
  +           classpath="my.customant.path"/&gt;
  +  &lt;copy file="input" tofile="output"&gt;
  +    &lt;filterchain&gt;
  +      &lt;tokenfilter&gt;
  +        &lt;stringtokenizer/&gt;
  +        &lt;capitalize/&gt;
  +      &lt;/tokenfilter&gt;
  +    &lt;/filterchain&gt;
  +  &lt;/copy&gt;
  +</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);
          }
      }
  
  }
  
  
  

Reply via email to