2. Adapt FixCRLF the task to use the filter (single set of fixcrlf code) 3. Implement ChainableReader in FixCRLF so that the existing taskdef will be recognized as a nested element in a filterchain. PR: 33155 Submitted by: Kevin Greiner git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277787 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -132,6 +132,8 @@ Other changes: | |||
| * New condition <parsersupports> which can look for XML parser feature or | |||
| property support in the parser Ant is using. | |||
| * fixcrlf can be used in a filterchain. | |||
| Changes from Ant 1.6.2 to current Ant 1.6 CVS version | |||
| ===================================================== | |||
| @@ -9,170 +9,202 @@ | |||
| <h2><a name="fixcrlf">FixCRLF</a></h2> | |||
| <h3>Description</h3> | |||
| <p> | |||
| Adjusts a text file to local conventions. | |||
| </p> | |||
| <p> | |||
| Adjusts a text file to local conventions. | |||
| </p> | |||
| <p> | |||
| The set of files to be adjusted can be refined with the | |||
| <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, | |||
| <i>excludesfile</i> and <i>defaultexcludes</i> | |||
| attributes. Patterns provided through the <i>includes</i> or | |||
| <i>includesfile</i> attributes specify files to be | |||
| included. Patterns provided through the <i>exclude</i> or | |||
| <i>excludesfile</i> attribute specify files to be | |||
| excluded. Additionally, default exclusions can be specified with | |||
| the <i>defaultexcludes</i> attribute. See the section on <a | |||
| href="../dirtasks.html#directorybasedtasks">directory based | |||
| tasks</a>, for details of file inclusion/exclusion patterns | |||
| and their usage. | |||
| </p> | |||
| <p> | |||
| The set of files to be adjusted can be refined with the | |||
| <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, | |||
| <i>excludesfile</i> and <i>defaultexcludes</i> | |||
| attributes. Patterns provided through the <i>includes</i> or | |||
| <i>includesfile</i> attributes specify files to be | |||
| included. Patterns provided through the <i>exclude</i> or | |||
| <i>excludesfile</i> attribute specify files to be | |||
| excluded. Additionally, default exclusions can be specified with | |||
| the <i>defaultexcludes</i> attribute. See the section on <a | |||
| href="../dirtasks.html#directorybasedtasks">directory-based | |||
| tasks</a>, for details of file inclusion/exclusion patterns | |||
| and their usage. | |||
| </p> | |||
| <p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and | |||
| supports all attributes of <code><fileset></code> | |||
| (<code>dir</code> becomes <code>srcdir</code>) as well as the nested | |||
| <code><include></code>, <code><exclude></code> and | |||
| <code><patternset></code> elements.</p> | |||
| <p> | |||
| This task forms an implicit | |||
| <a href="../CoreTypes/fileset.html">FileSet</a> and | |||
| supports all attributes of <code><fileset></code> | |||
| (<code>dir</code> becomes <code>srcdir</code>) as well as the nested | |||
| <code><include></code>, <code><exclude></code> and | |||
| <code><patternset></code> elements. | |||
| </p> | |||
| <p> | |||
| The output file is only written if it is a new file, or if it | |||
| differs from the existing file. This prevents spurious | |||
| rebuilds based on unchanged files which have been regenerated | |||
| by this task. | |||
| </p> | |||
| <p> | |||
| The output file is only written if it is a new file, or if it | |||
| differs from the existing file. This prevents spurious | |||
| rebuilds based on unchanged files which have been regenerated | |||
| by this task. | |||
| </p> | |||
| <p> | |||
| Since <b>Ant 1.7</b>, this task can be used in a | |||
| <a href="../CoreTypes/filterchain.html">filterchain</a>. | |||
| </p> | |||
| <h3>Parameters</h3> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| <td valign="top"><b>Attribute</b></td> | |||
| <td valign="top"><b>Description</b></td> | |||
| <td align="center" valign="top"><b>Required</b></td> | |||
| <td valign="center" rowspan="2"><b>Attribute</b></td> | |||
| <td valign="center" rowspan="2"><b>Description</b></td> | |||
| <td align="center" valign="top" colspan="2"><b>Required</b></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="center"><b>As Task</b></td> | |||
| <td valign="center"><b>As Filter</b></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">srcDir</td> | |||
| <td valign="top">Where to find the files to be fixed up.</td> | |||
| <td valign="top" align="center">Either file or srcDir</td> | |||
| <td valign="top" align="center" rowspan="2">One of these</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">file</td> | |||
| <td valign="top">Name of a single file to fix. Since Ant1.7</td> | |||
| <td valign="top" align="center">Either file or srcDir</td> | |||
| <td valign="top">Name of a single file to fix. <b>Since Ant 1.7</b></td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">destDir</td> | |||
| <td valign="top">Where to place the corrected files. Defaults to | |||
| srcDir (replacing the original file)</td> | |||
| srcDir (replacing the original file).</td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">includes</td> | |||
| <td valign="top">comma- or space-separated list of patterns of files that must be | |||
| included. All files are included when omitted.</td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">includesfile</td> | |||
| <td valign="top">the name of a file. Each line of this file is | |||
| taken to be an include pattern</td> | |||
| taken to be an include pattern.</td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">excludes</td> | |||
| <td valign="top">comma- or space-separated list of patterns of files that must be | |||
| excluded. No files (except default excludes) are excluded when omitted.</td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">excludesfile</td> | |||
| <td valign="top">the name of a file. Each line of this file is | |||
| taken to be an exclude pattern</td> | |||
| taken to be an exclude pattern.</td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">defaultexcludes</td> | |||
| <td valign="top">indicates whether default excludes should be used or not | |||
| ("yes"/"no"). Default excludes are used when omitted.</td> | |||
| ("yes"/"no"). Default excludes are used when omitted. | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">encoding</td> | |||
| <td valign="top">The encoding of the files.</td> | |||
| <td align="center">No; defaults to default JVM encoding.</td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">preservelastmodified</td> | |||
| <td valign="top">Whether to preserve the last modified | |||
| date of source files. <b>Since Ant 1.6.3</b></td> | |||
| <td align="center">No; default is <i>false</i></td> | |||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">eol</td> | |||
| <td valign="top"> | |||
| Specifies how end-of-line (EOL) characters are to be | |||
| handled. The EOL characters are CR, LF and the pair CRLF. | |||
| Valid values for this property are: | |||
| <ul> | |||
| <li>asis: leave EOL characters alone</li> | |||
| <li>cr: convert all EOLs to a single CR</li> | |||
| <li>lf: convert all EOLs to a single LF</li> | |||
| <li>crlf: convert all EOLs to the pair CRLF</li> | |||
| <li>mac: convert all EOLs to a single CR</li> | |||
| <li>unix: convert all EOLs to a single LF</li> | |||
| <li>dos: convert all EOLs to the pair CRLF</li> | |||
| </ul> | |||
| Default is based on the platform on which you are running | |||
| this task. For Unix platforms, the default is "lf". | |||
| For DOS based systems (including Windows), the default is | |||
| "crlf". For Mac OS, the default is "cr". | |||
| <p> | |||
| This is the preferred method for specifying EOL. The | |||
| "<i><b>cr</b></i>" attribute (see below) is | |||
| now deprecated. | |||
| </p> | |||
| <p> | |||
| <i>N.B.</i>: One special case is recognized. The three | |||
| characters CR-CR-LF are regarded as a single EOL. | |||
| Unless this property is specified as "asis", | |||
| this sequence will be converted into the specified EOL | |||
| type. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">cr</td> | |||
| <td valign="top"> | |||
| <i><b>Deprecated.</b></i> Specifies how CR characters are | |||
| to be handled at end-of-line (EOL). Valid values for this | |||
| property are: | |||
| <ul> | |||
| <li>asis: leave EOL characters alone.</li> | |||
| <li> | |||
| add: add a CR before any single LF characters. The | |||
| intent is to convert all EOLs to the pair CRLF. | |||
| </li> | |||
| <li> | |||
| remove: remove all CRs from the file. The intent is | |||
| to convert all EOLs to a single LF. | |||
| </li> | |||
| </ul> | |||
| Default is based on the platform on which you are running | |||
| this task. For Unix platforms, the default is "remove". | |||
| For DOS based systems (including Windows), the default is | |||
| "add". | |||
| <p> | |||
| <i>N.B.</i>: One special case is recognized. The three | |||
| characters CR-CR-LF are regarded as a single EOL. | |||
| Unless this property is specified as "asis", | |||
| this sequence will be converted into the specified EOL | |||
| type. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">javafiles</td> | |||
| <td valign="top"> | |||
| Used only in association with the | |||
| "<i><b>tab</b></i>" attribute (see below), this | |||
| boolean attribute indicates whether the fileset is a set | |||
| of java source files | |||
| ("yes"/"no"). Defaults to | |||
| "no". See notes in section on "tab". | |||
| </td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">eol</td> | |||
| <td valign="top"> | |||
| Specifies how end-of-line (EOL) characters are to be | |||
| handled. The EOL characters are CR, LF and the pair CRLF. | |||
| Valid values for this property are: | |||
| <ul> | |||
| <li>asis: leave EOL characters alone</li> | |||
| <li>cr: convert all EOLs to a single CR</li> | |||
| <li>lf: convert all EOLs to a single LF</li> | |||
| <li>crlf: convert all EOLs to the pair CRLF</li> | |||
| <li>mac: convert all EOLs to a single CR</li> | |||
| <li>unix: convert all EOLs to a single LF</li> | |||
| <li>dos: convert all EOLs to the pair CRLF</li> | |||
| </ul> | |||
| Default is based on the platform on which you are running | |||
| this task. For Unix platforms, the default is "lf". | |||
| For DOS based systems (including Windows), the default is | |||
| "crlf". For Mac OS, the default is "cr". | |||
| <p> | |||
| This is the preferred method for specifying EOL. The | |||
| "<i><b>cr</b></i>" attribute (see below) is | |||
| now deprecated. | |||
| </p> | |||
| <p> | |||
| <i>N.B.</i>: One special case is recognized. The three | |||
| characters CR-CR-LF are regarded as a single EOL. | |||
| Unless this property is specified as "asis", | |||
| this sequence will be converted into the specified EOL | |||
| type. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">cr</td> | |||
| <td valign="top"> | |||
| <i><b>Deprecated.</b></i> Specifies how CR characters are | |||
| to be handled at end-of-line (EOL). Valid values for this | |||
| property are: | |||
| <ul> | |||
| <li>asis: leave EOL characters alone.</li> | |||
| <li> | |||
| add: add a CR before any single LF characters. The | |||
| intent is to convert all EOLs to the pair CRLF. | |||
| </li> | |||
| <li> | |||
| remove: remove all CRs from the file. The intent is | |||
| to convert all EOLs to a single LF. | |||
| </li> | |||
| </ul> | |||
| Default is based on the platform on which you are running | |||
| this task. For Unix platforms, the default is "remove". | |||
| For DOS based systems (including Windows), the default is | |||
| "add". | |||
| <p> | |||
| <i>N.B.</i>: One special case is recognized. The three | |||
| characters CR-CR-LF are regarded as a single EOL. | |||
| Unless this property is specified as "asis", | |||
| this sequence will be converted into the specified EOL | |||
| type. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">javafiles</td> | |||
| <td valign="top"> | |||
| Used only in association with the | |||
| "<i><b>tab</b></i>" attribute (see below), this | |||
| boolean attribute indicates whether the fileset is a set | |||
| of java source files | |||
| ("yes"/"no"). Defaults to | |||
| "no". See notes in section on "tab". | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <tr> | |||
| <td valign="top">tab</td> | |||
| <td valign="top">Specifies how tab characters are to be handled. Valid | |||
| values for this property are: | |||
| @@ -182,28 +214,28 @@ supports all attributes of <code><fileset></code> | |||
| <li>remove: convert tabs to spaces</li> | |||
| </ul> | |||
| Default for this parameter is "asis". | |||
| <p> | |||
| <i>N.B.</i>: When the attribute | |||
| "<i><b>javafiles</b></i>" (see above) is | |||
| "true", literal TAB characters occurring | |||
| within Java string or character constants are never | |||
| modified. This functionality also requires the | |||
| recognition of Java-style comments. | |||
| </p> | |||
| <p> | |||
| <i>N.B.</i>: There is an incompatibility between this | |||
| and the previous version in the handling of white | |||
| space at the end of lines. This version does | |||
| <i><b>not</b></i> remove trailing whitespace on lines. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| <i>N.B.</i>: When the attribute | |||
| "<i><b>javafiles</b></i>" (see above) is | |||
| "true", literal TAB characters occurring | |||
| within Java string or character constants are never | |||
| modified. This functionality also requires the | |||
| recognition of Java-style comments. | |||
| </p> | |||
| <p> | |||
| <i>N.B.</i>: There is an incompatibility between this | |||
| and the previous version in the handling of white | |||
| space at the end of lines. This version does | |||
| <i><b>not</b></i> remove trailing whitespace on lines. | |||
| </p> | |||
| </td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">tablength</td> | |||
| <td valign="top">TAB character interval. Valid values are between | |||
| 2 and 80 inclusive. The default for this parameter is 8.</td> | |||
| <td valign="top" align="center">No</td> | |||
| 2 and 80 inclusive. The default for this parameter is 8.</td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">eof</td> | |||
| @@ -218,76 +250,52 @@ supports all attributes of <code><fileset></code> | |||
| For Unix platforms, the default is remove. For DOS based systems | |||
| (including Windows), the default is asis. | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">encoding</td> | |||
| <td valign="top">The encoding of the files</td> | |||
| <td align="center">No - defaults to default JVM encoding</td> | |||
| <td valign="top" align="center" colspan="2">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">fixlast</td> | |||
| <td valign="top">Whether to add a missing EOL to the last line | |||
| of a processed file. (Since ant 1.6.1)</td> | |||
| <td align="center">No - default is <i>true</i></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">preservelastmodified</td> | |||
| <td valign="top">Whether to preserve the last modified | |||
| date of source files. <b>Since ant 1.6.3</b></td> | |||
| <td align="center">No; default is <i>false</i></td> | |||
| of a processed file. <b>Since Ant 1.6.1</b></td> | |||
| <td align="center" colspan="2">No; default is <i>true</i></td> | |||
| </tr> | |||
| </table> | |||
| <h3>Examples</h3> | |||
| <pre> <fixcrlf srcdir="${src}" | |||
| eol="lf" | |||
| eof="remove" | |||
| includes="**/*.sh" | |||
| /></pre> | |||
| <pre><fixcrlf srcdir="${src}" includes="**/*.sh" | |||
| eol="lf" eof="remove" /></pre> | |||
| <p>Replaces EOLs with LF characters and removes eof characters from | |||
| the shell scripts. Tabs and spaces are left as is.</p> | |||
| <pre> <fixcrlf srcdir="${src}" | |||
| eol="crlf" | |||
| includes="**/*.bat" | |||
| /></pre> | |||
| the shell scripts. Tabs and spaces are left as is.</p> | |||
| <pre><fixcrlf srcdir="${src}" | |||
| includes="**/*.bat" eol="crlf" /></pre> | |||
| <p>Replaces all EOLs with cr-lf pairs in the batch files. | |||
| Tabs and spaces are left as is. | |||
| EOF characters are left alone if run on | |||
| DOS systems, and are removed if run on Unix systems.</p> | |||
| <pre> <fixcrlf srcdir="${src}" | |||
| tab="add" | |||
| includes="**/Makefile" | |||
| /></pre> | |||
| Tabs and spaces are left as is. | |||
| EOF characters are left alone if run on | |||
| DOS systems, and are removed if run on Unix systems.</p> | |||
| <pre><fixcrlf srcdir="${src}" | |||
| includes="**/Makefile" tab="add" /></pre> | |||
| <p>Sets EOLs according to local OS conventions, and | |||
| converts sequences of spaces and tabs to the minimal set of spaces and | |||
| tabs which will maintain spacing within the line. Tabs are | |||
| set at 8 character intervals. EOF characters are left alone if | |||
| run on DOS systems, and are removed if run on Unix systems. | |||
| Many versions of make require tabs prior to commands.</p> | |||
| <pre> <fixcrlf srcdir="${src}" | |||
| tab="remove" | |||
| tablength="3" | |||
| eol="lf" | |||
| javafiles="yes" | |||
| includes="**/*.java" | |||
| /></pre> | |||
| <p> | |||
| Converts all EOLs in the included java source files to a | |||
| single LF. Replace all TAB characters except those in string | |||
| or character constants with spaces, assuming a tab width of 3. | |||
| If run on a unix system, any CTRL-Z EOF characters at the end | |||
| of the file are removed. On DOS/Windows, any such EOF | |||
| characters will be left untouched. | |||
| </p> | |||
| <pre> <fixcrlf srcdir="${src}" | |||
| tab="remove" | |||
| includes="**/README*" | |||
| /></pre> | |||
| converts sequences of spaces and tabs to the minimal set of spaces and | |||
| tabs which will maintain spacing within the line. Tabs are | |||
| set at 8 character intervals. EOF characters are left alone if | |||
| run on DOS systems, and are removed if run on Unix systems. | |||
| Many versions of make require tabs prior to commands.</p> | |||
| <pre><fixcrlf srcdir="${src}" includes="**/*.java" | |||
| tab="remove" tablength="3" | |||
| eol="lf" javafiles="yes" /></pre> | |||
| <p> | |||
| Converts all EOLs in the included java source files to a | |||
| single LF. Replace all TAB characters except those in string | |||
| or character constants with spaces, assuming a tab width of 3. | |||
| If run on a unix system, any CTRL-Z EOF characters at the end | |||
| of the file are removed. On DOS/Windows, any such EOF | |||
| characters will be left untouched. | |||
| </p> | |||
| <pre><fixcrlf srcdir="${src}" | |||
| includes="**/README*" tab="remove" /></pre> | |||
| <p>Sets EOLs according to local OS conventions, and | |||
| converts all tabs to spaces, assuming a tab width of 8. | |||
| EOF characters are left alone if run on | |||
| DOS systems, and are removed if run on Unix systems. | |||
| You never know what editor a user will use to browse README's.</p> | |||
| converts all tabs to spaces, assuming a tab width of 8. | |||
| EOF characters are left alone if run on | |||
| DOS systems, and are removed if run on Unix systems. | |||
| You never know what editor a user will use to browse READMEs.</p> | |||
| <hr> | |||
| <p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | |||
| Reserved.</p> | |||
| @@ -194,4 +194,100 @@ | |||
| <fail unless="fs" /> | |||
| </target> | |||
| <macrodef name="testjunk"> | |||
| <attribute name="n" /> | |||
| <sequential> | |||
| <fail> | |||
| <condition> | |||
| <not> | |||
| <filesmatch file1="result/Junk@{n}.java" | |||
| file2="expected/Junk@{n}.java" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </sequential> | |||
| </macrodef> | |||
| <target name="testFilter1" depends="init"> | |||
| <copy file="input/Junk1.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="add" | |||
| eol="crlf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="1" /> | |||
| </target> | |||
| <target name="testFilter2" depends="init"> | |||
| <copy file="input/Junk2.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="add" cr="add" eol="crlf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="2" /> | |||
| </target> | |||
| <target name="testFilter3" depends="init"> | |||
| <copy file="input/Junk3.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="remove" eol="lf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="3" /> | |||
| </target> | |||
| <target name="testFilter4" depends="init"> | |||
| <copy file="input/Junk4.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="remove" eol="lf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="4" /> | |||
| </target> | |||
| <target name="testFilter5" depends="init"> | |||
| <copy file="input/Junk5.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf tab="remove" eol="lf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="5" /> | |||
| </target> | |||
| <target name="testFilter6" depends="init"> | |||
| <copy file="input/Junk6.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf tab="add" cr="remove" eol="crlf" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="6" /> | |||
| </target> | |||
| <target name="testFilter7" depends="init"> | |||
| <copy file="input/Junk7.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf tab="add" cr="add" eof="asis" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="7" /> | |||
| </target> | |||
| <target name="testFilter8" depends="init"> | |||
| <copy file="input/Junk8.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="add" cr="add" eof="add" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="8" /> | |||
| </target> | |||
| <target name="testFilter9" depends="init"> | |||
| <copy file="input/Junk9.java" todir="result" overwrite="true"> | |||
| <filterchain> | |||
| <fixcrlf javafiles="true" tab="remove" cr="remove" eof="remove" /> | |||
| </filterchain> | |||
| </copy> | |||
| <testjunk n="9" /> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1,899 @@ | |||
| /* | |||
| * Copyright 2005 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant.filters; | |||
| import java.io.BufferedReader; | |||
| import java.io.CharArrayWriter; | |||
| import java.io.IOException; | |||
| import java.io.InvalidObjectException; | |||
| import java.io.ObjectStreamException; | |||
| import java.io.Reader; | |||
| import java.io.Writer; | |||
| import java.util.NoSuchElementException; | |||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| /** | |||
| * Converts text to local OS formatting conventions, as | |||
| * well as repair text damaged by misconfigured or misguided editors or | |||
| * file transfer programs. | |||
| * <p> | |||
| * This filter can take the following arguments: | |||
| * <ul> | |||
| * <li>eof | |||
| * <li>eol | |||
| * <li>fixlast | |||
| * <li>javafiles | |||
| * <li>tab | |||
| * <li>tablength | |||
| * </ul> | |||
| * None of which are required. | |||
| * <p> | |||
| * This version generalises the handling of EOL characters, and allows | |||
| * for CR-only line endings (which I suspect is the standard on Macs.) | |||
| * Tab handling has also been generalised to accommodate any tabwidth | |||
| * from 2 to 80, inclusive. Importantly, it can leave untouched any | |||
| * literal TAB characters embedded within Java string or character constants. | |||
| * <p> | |||
| * <em>Caution:</em> run with care on carefully formatted files. This may | |||
| * sound obvious, but if you don't specify asis, presume that your files are | |||
| * going to be modified. If "tabs" is "add" or "remove", whitespace | |||
| * characters may be added or removed as necessary. Similarly, for EOL's - | |||
| * eol="asis" actually means convert to your native O/S EOL convention while | |||
| * eol="crlf" or cr="add" can result in CR characters being removed in one | |||
| * special case accommodated, i.e., CRCRLF is regarded as a single EOL to | |||
| * handle cases where other programs have converted CRLF into CRCRLF. | |||
| * | |||
| * <P>Example: | |||
| * <pre><<fixcrlf tab="add" eol="crlf" eof="asis"/></pre> | |||
| * | |||
| * Or: | |||
| * | |||
| * <pre><filterreader classname="org.apache.tools.ant.filters.FixCrLfFilter"> | |||
| * <param eol="crlf" tab="asis"/> | |||
| * </filterreader></pre> | |||
| * | |||
| */ | |||
| public final class FixCrLfFilter | |||
| extends BaseParamFilterReader | |||
| implements ChainableReader { | |||
| private static final char CTRLZ = '\u001A'; | |||
| private int tabLength = 8; | |||
| private CrLf eol; | |||
| private AddAsisRemove ctrlz; | |||
| private AddAsisRemove tabs; | |||
| private boolean javafiles = false; | |||
| private boolean fixlast = true; | |||
| /** | |||
| * Constructor for "dummy" instances. | |||
| * | |||
| * @see BaseFilterReader#BaseFilterReader() | |||
| */ | |||
| public FixCrLfFilter() { | |||
| super(); | |||
| } | |||
| /** | |||
| * Create a new filtered reader. | |||
| * | |||
| * @param in A Reader object providing the underlying stream. | |||
| * Must not be <code>null</code>. | |||
| */ | |||
| public FixCrLfFilter(final Reader in) throws IOException { | |||
| super(in); | |||
| } | |||
| // Instance initializer: Executes just after the super() call in this class's constructor. | |||
| { | |||
| tabs = AddAsisRemove.ASIS; | |||
| if (Os.isFamily("mac")) { | |||
| ctrlz = AddAsisRemove.REMOVE; | |||
| setEol(CrLf.MAC); | |||
| } else if (Os.isFamily("dos")) { | |||
| ctrlz = AddAsisRemove.ASIS; | |||
| setEol(CrLf.DOS); | |||
| } else { | |||
| ctrlz = AddAsisRemove.REMOVE; | |||
| setEol(CrLf.UNIX); | |||
| } | |||
| } | |||
| /** | |||
| * Create a new FixCrLfFilter using the passed in | |||
| * Reader for instantiation. | |||
| * | |||
| * @param rdr A Reader object providing the underlying stream. | |||
| * Must not be <code>null</code>. | |||
| * | |||
| * @return a new filter based on this configuration, but filtering | |||
| * the specified reader. | |||
| */ | |||
| public final Reader chain(final Reader rdr) { | |||
| try { | |||
| FixCrLfFilter newFilter = new FixCrLfFilter(rdr); | |||
| newFilter.setJavafiles(getJavafiles()); | |||
| newFilter.setEol(getEol()); | |||
| newFilter.setTab(getTab()); | |||
| newFilter.setTablength(getTablength()); | |||
| newFilter.setEof(getEof()); | |||
| newFilter.setFixlast(getFixlast()); | |||
| newFilter.initInternalFilters(); | |||
| return newFilter; | |||
| } catch (IOException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| /** | |||
| * Get how DOS EOF (control-z) characters are being handled. | |||
| * | |||
| * @return values: | |||
| * <ul> | |||
| * <li>add: ensure that there is an eof at the end of the file | |||
| * <li>asis: leave eof characters alone | |||
| * <li>remove: remove any eof character found at the end | |||
| * </ul> | |||
| */ | |||
| public AddAsisRemove getEof() { | |||
| // Return copy so that the call must call setEof() to change the state of fixCRLF | |||
| return ctrlz.newInstance(); | |||
| } | |||
| /** | |||
| * Get how EndOfLine characters are being handled. | |||
| * | |||
| * @return values: | |||
| * <ul> | |||
| * <li>asis: convert line endings to your O/S convention | |||
| * <li>cr: convert line endings to CR | |||
| * <li>lf: convert line endings to LF | |||
| * <li>crlf: convert line endings to CRLF | |||
| * </ul> | |||
| */ | |||
| public CrLf getEol() { | |||
| // Return copy so that the call must call setEol() to change the state of fixCRLF | |||
| return eol.newInstance(); | |||
| } | |||
| /** | |||
| * Get whether a missing EOL be added to the final line of the stream. | |||
| * | |||
| * @return true if a filtered file will always end with an EOL | |||
| */ | |||
| public boolean getFixlast() { | |||
| return fixlast; | |||
| } | |||
| /** | |||
| * Get whether the stream is to be treated as though it contains Java source. | |||
| * <P> | |||
| * This attribute is only used in assocation with the | |||
| * "<i><b>tab</b></i>" attribute. Tabs found in Java literals | |||
| * are protected from changes by this filter. | |||
| * | |||
| * @return true if whitespace in Java character and string literals is | |||
| * ignored. | |||
| */ | |||
| public boolean getJavafiles() { | |||
| return javafiles; | |||
| } | |||
| /** | |||
| * Return how tab characters are being handled. | |||
| * | |||
| * @return values: | |||
| * <ul> | |||
| * <li>add: convert sequences of spaces which span a tab stop to tabs | |||
| * <li>asis: leave tab and space characters alone | |||
| * <li>remove: convert tabs to spaces | |||
| * </ul> | |||
| */ | |||
| public AddAsisRemove getTab() { | |||
| // Return copy so that the caller must call setTab() to change the state of fixCRLF. | |||
| return tabs.newInstance(); | |||
| } | |||
| /** | |||
| * Get the tab length to use. | |||
| * | |||
| * @return the length of tab in spaces | |||
| */ | |||
| public int getTablength(){ | |||
| return tabLength; | |||
| } | |||
| private static String calculateEolString(CrLf eol) { | |||
| // Calculate the EOL string per the current config | |||
| if (eol == CrLf.ASIS) { | |||
| return System.getProperty("line.separator"); | |||
| } | |||
| if (eol == CrLf.CR || eol == CrLf.MAC) { | |||
| return "\r"; | |||
| } | |||
| if (eol == CrLf.CRLF || eol == CrLf.DOS) { | |||
| return "\r\n"; | |||
| } | |||
| //assume (eol == CrLf.LF || eol == CrLf.UNIX) | |||
| return "\n"; | |||
| } | |||
| /** | |||
| * Wrap the input stream with the internal filters necessary to perform | |||
| * the configuration settings. | |||
| */ | |||
| private void initInternalFilters() { | |||
| // If I'm removing an EOF character, do so first so that the other | |||
| // filters don't see that character. | |||
| in = (ctrlz == AddAsisRemove.REMOVE) ? new RemoveEofFilter(in) : in; | |||
| // Change all EOL characters to match the calculated EOL string. If | |||
| // configured to do so, append a trailing EOL so that the file ends on | |||
| // a EOL. | |||
| in = new NormalizeEolFilter(in, calculateEolString(eol), getFixlast()); | |||
| if (tabs != AddAsisRemove.ASIS) { | |||
| // If filtering Java source, prevent changes to whitespace in | |||
| // character and string literals. | |||
| if (getJavafiles()) { | |||
| in = new MaskJavaTabLiteralsFilter(in); | |||
| } | |||
| // Add/Remove tabs | |||
| in = (tabs == AddAsisRemove.ADD) | |||
| ? (Reader) new AddTabFilter(in, getTablength()) | |||
| : (Reader) new RemoveTabFilter(in, getTablength()); | |||
| } | |||
| // Add missing EOF character | |||
| in = (ctrlz == AddAsisRemove.ADD) ? new AddEofFilter(in) : in; | |||
| } | |||
| /** | |||
| * Return the next character in the filtered stream. | |||
| * | |||
| * @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 final int read() throws IOException { | |||
| return in.read(); | |||
| } | |||
| /** | |||
| * Specify how DOS EOF (control-z) characters are to be handled. | |||
| * | |||
| * @param attr valid values: | |||
| * <ul> | |||
| * <li>add: ensure that there is an eof at the end of the file | |||
| * <li>asis: leave eof characters alone | |||
| * <li>remove: remove any eof character found at the end | |||
| * </ul> | |||
| */ | |||
| public void setEof(AddAsisRemove attr) { | |||
| ctrlz = attr.resolve(); | |||
| } | |||
| /** | |||
| * Specify how end of line (EOL) characters are to be handled. | |||
| * | |||
| * @param attr valid values: | |||
| * <ul> | |||
| * <li>asis: convert line endings to your O/S convention | |||
| * <li>cr: convert line endings to CR | |||
| * <li>lf: convert line endings to LF | |||
| * <li>crlf: convert line endings to CRLF | |||
| * </ul> | |||
| */ | |||
| public void setEol(CrLf attr) { | |||
| eol = attr.resolve(); | |||
| } | |||
| /** | |||
| * Specify whether a missing EOL will be added | |||
| * to the final line of input. | |||
| * | |||
| * @param fixlast if true a missing EOL will be appended. | |||
| */ | |||
| public void setFixlast(boolean fixlast) { | |||
| this.fixlast = fixlast; | |||
| } | |||
| /** | |||
| * Indicate whether this stream contains Java source. | |||
| * | |||
| * This attribute is only used in assocation with the | |||
| * "<i><b>tab</b></i>" attribute. | |||
| * | |||
| * @param javafiles set to true to prevent this filter from changing tabs | |||
| * found in Java literals. | |||
| */ | |||
| public void setJavafiles(boolean javafiles) { | |||
| this.javafiles = javafiles; | |||
| } | |||
| /** | |||
| * Specify how tab characters are to be handled. | |||
| * | |||
| * @param attr valid values: | |||
| * <ul> | |||
| * <li>add: convert sequences of spaces which span a tab stop to tabs | |||
| * <li>asis: leave tab and space characters alone | |||
| * <li>remove: convert tabs to spaces | |||
| * </ul> | |||
| */ | |||
| public void setTab(AddAsisRemove attr) { | |||
| tabs = attr.resolve(); | |||
| } | |||
| /** | |||
| * Specify tab length in characters. | |||
| * | |||
| * @param tabLength specify the length of tab in spaces. | |||
| * Valid values are between 2 and 80 | |||
| * inclusive. The default for this parameter is 8. | |||
| */ | |||
| public void setTablength(int tabLength) throws IOException { | |||
| if (tabLength < 2 || tabLength > 80) { | |||
| throw new IOException("tablength must be between 2 and 80"); | |||
| } | |||
| this.tabLength = tabLength; | |||
| } | |||
| /** | |||
| * This filter reader redirects all read I/O methods through its own read() method. | |||
| * | |||
| * <P>The input stream is already buffered by the copy task so this doesn't significantly | |||
| * impact performance while it makes writing the individual fix filters much easier.</P> | |||
| */ | |||
| private static class SimpleFilterReader extends Reader { | |||
| private Reader in; | |||
| int[] preempt = new int[16]; | |||
| int preemptIndex = 0; | |||
| public SimpleFilterReader(Reader in) { | |||
| this.in = in; | |||
| } | |||
| public void push(char c) { | |||
| push((int) c); | |||
| } | |||
| public void push(int c) { | |||
| try { | |||
| preempt[preemptIndex++] = c; | |||
| } catch (ArrayIndexOutOfBoundsException e) { | |||
| int[] p2 = new int[preempt.length * 2]; | |||
| System.arraycopy(preempt, 0, p2, 0, preempt.length); | |||
| preempt = p2; | |||
| push(c); | |||
| } | |||
| } | |||
| public void push(char[] cs, int start, int length) { | |||
| for (int i = start + length - 1; i >= start;) { | |||
| push(cs [i--]); | |||
| } | |||
| } | |||
| public void push(char[] cs) { | |||
| push(cs, 0, cs.length); | |||
| } | |||
| public void push(String s) { | |||
| push(s.toCharArray()); | |||
| } | |||
| /** | |||
| * Does this filter want to block edits on the last character returned by read()? | |||
| */ | |||
| public boolean editsBlocked() { | |||
| if (in instanceof SimpleFilterReader) { | |||
| return ((SimpleFilterReader) in).editsBlocked(); | |||
| } | |||
| return false; | |||
| } | |||
| public int read() throws java.io.IOException { | |||
| if (preemptIndex > 0) { | |||
| return preempt[--preemptIndex]; | |||
| } | |||
| return in.read(); | |||
| } | |||
| public void close() throws java.io.IOException { | |||
| in.close(); | |||
| } | |||
| public void reset() throws IOException { | |||
| in.reset(); | |||
| } | |||
| public boolean markSupported() { | |||
| return in.markSupported(); | |||
| } | |||
| public boolean ready() throws java.io.IOException { | |||
| return in.ready(); | |||
| } | |||
| public void mark(int i) throws java.io.IOException { | |||
| in.mark(i); | |||
| } | |||
| public long skip(long i) throws java.io.IOException { | |||
| return in.skip(i); | |||
| } | |||
| public int read(char[] buf) throws java.io.IOException { | |||
| return read(buf, 0, buf.length); | |||
| } | |||
| public int read(char[] buf, int start, int length) throws java.io.IOException { | |||
| int count = 0; | |||
| int c = 0; | |||
| while (length-- > 0 && (c = this.read()) != -1) { | |||
| buf[start++] = (char) c; | |||
| count++; | |||
| } | |||
| // if at EOF with no characters in the buffer, return EOF | |||
| if (count == 0 && c == -1) { | |||
| return -1; | |||
| } | |||
| return count; | |||
| } | |||
| } | |||
| private static class MaskJavaTabLiteralsFilter extends SimpleFilterReader { | |||
| boolean editsBlocked = false; | |||
| private static final int JAVA = 1; | |||
| private static final int IN_CHAR_CONST = 2; | |||
| private static final int IN_STR_CONST = 3; | |||
| private static final int IN_SINGLE_COMMENT = 4; | |||
| private static final int IN_MULTI_COMMENT = 5; | |||
| private static final int TRANS_TO_COMMENT = 6; | |||
| private static final int TRANS_FROM_MULTI = 8; | |||
| private int state; | |||
| public MaskJavaTabLiteralsFilter(Reader in) { | |||
| super(in); | |||
| state = JAVA; | |||
| } | |||
| public boolean editsBlocked () { | |||
| return editsBlocked || super.editsBlocked(); | |||
| } | |||
| public int read() throws IOException { | |||
| int thisChar = super.read(); | |||
| // Mask, block from being edited, all characters in constants. | |||
| editsBlocked = (state == IN_CHAR_CONST || state == IN_STR_CONST); | |||
| switch (state) { | |||
| case JAVA: | |||
| // The current character is always emitted. | |||
| switch(thisChar) { | |||
| case '\'': state = IN_CHAR_CONST; break; | |||
| case '"' : state = IN_STR_CONST; break; | |||
| case '/' : state = TRANS_TO_COMMENT; break; | |||
| } | |||
| break; | |||
| case IN_CHAR_CONST: | |||
| switch (thisChar) { | |||
| case '\'': state = JAVA; break; | |||
| } | |||
| break; | |||
| case IN_STR_CONST: | |||
| switch (thisChar) { | |||
| case '"' : state = JAVA; break; | |||
| } | |||
| break; | |||
| case IN_SINGLE_COMMENT: | |||
| // The current character is always emitted. | |||
| switch (thisChar) { | |||
| case '\n': | |||
| case '\r': // EOL | |||
| state = JAVA; | |||
| break; | |||
| } | |||
| break; | |||
| case IN_MULTI_COMMENT: | |||
| // The current character is always emitted. | |||
| switch (thisChar) { | |||
| case '*': state = TRANS_FROM_MULTI; break; | |||
| } | |||
| break; | |||
| case TRANS_TO_COMMENT: | |||
| // The current character is always emitted. | |||
| switch (thisChar) { | |||
| case '*' : state = IN_MULTI_COMMENT; break; | |||
| case '/' : state = IN_SINGLE_COMMENT; break; | |||
| case '\'': state = IN_CHAR_CONST; break; | |||
| case '"' : state = IN_STR_CONST; break; | |||
| default : state = JAVA; | |||
| } | |||
| case TRANS_FROM_MULTI: | |||
| // The current character is always emitted. | |||
| switch (thisChar) { | |||
| case '/': state = JAVA; break; | |||
| } | |||
| } | |||
| return thisChar; | |||
| } | |||
| } | |||
| private static class NormalizeEolFilter extends SimpleFilterReader { | |||
| boolean previousWasEOL; | |||
| boolean fixLast; | |||
| int normalizedEOL = 0; | |||
| char[] eol = null; | |||
| public NormalizeEolFilter(Reader in, String eolString, boolean fixLast) { | |||
| super(in); | |||
| eol = eolString.toCharArray(); | |||
| this.fixLast = fixLast; | |||
| } | |||
| public int read() throws IOException { | |||
| int thisChar = super.read(); | |||
| if (normalizedEOL == 0) { | |||
| int numEOL = 0; | |||
| switch (thisChar) { | |||
| case CTRLZ: | |||
| case -1: | |||
| if (fixLast && !previousWasEOL) { | |||
| numEOL = 1; | |||
| if (thisChar == CTRLZ) { | |||
| push(thisChar); | |||
| } | |||
| } | |||
| break; | |||
| case '\n': | |||
| // EOL was "\n" | |||
| numEOL = 1; | |||
| break; | |||
| case '\r': | |||
| numEOL = 1; | |||
| int c1 = super.read(); | |||
| int c2 = super.read(); | |||
| if (c1 == '\r' && c2 == '\n') { | |||
| // EOL was "\r\r\n" | |||
| } else if (c1 == '\r') { | |||
| // EOL was "\r\r" - handle as two consecutive "\r" and "\r" | |||
| numEOL = 2; | |||
| push(c2); | |||
| } else if (c1 == '\n') { | |||
| // EOL was "\r\n" | |||
| push(c2); | |||
| } else { | |||
| // EOL was "\r" | |||
| push(c2); | |||
| push(c1); | |||
| } | |||
| } | |||
| if (numEOL > 0) { | |||
| while (numEOL-- > 0) { | |||
| push(eol); | |||
| normalizedEOL += eol.length; | |||
| } | |||
| previousWasEOL = true; | |||
| thisChar = read(); | |||
| } else if (thisChar != -1) { | |||
| previousWasEOL = false; | |||
| } | |||
| } else { | |||
| normalizedEOL--; | |||
| } | |||
| return thisChar; | |||
| } | |||
| } | |||
| private static class FixLastFilter extends SimpleFilterReader { | |||
| int lastChar = -1; | |||
| char[] eol = null; | |||
| public FixLastFilter(Reader in, String eolString) { | |||
| super(in); | |||
| eol = eolString.toCharArray(); | |||
| } | |||
| public int read() throws IOException { | |||
| int thisChar = super.read(); | |||
| // if source is EOF but last character was NOT eol, return eol | |||
| if (thisChar == -1) { | |||
| switch (lastChar) { | |||
| case '\r': | |||
| case '\n': | |||
| // Return first character of EOL | |||
| thisChar = eol[0]; | |||
| // Push remaining characters onto input stream | |||
| push(eol, 1, eol.length - 1); | |||
| } | |||
| } | |||
| lastChar = thisChar; | |||
| return thisChar; | |||
| } | |||
| } | |||
| private static class AddEofFilter extends SimpleFilterReader { | |||
| int lastChar = -1; | |||
| public AddEofFilter(Reader in) { | |||
| super(in); | |||
| } | |||
| public int read() throws IOException { | |||
| int thisChar = super.read(); | |||
| // if source is EOF but last character was NOT ctrl-z, return ctrl-z | |||
| if (thisChar == -1) { | |||
| if (lastChar != CTRLZ) { | |||
| lastChar = CTRLZ; | |||
| thisChar = CTRLZ; | |||
| } | |||
| } else { | |||
| lastChar = thisChar; | |||
| } | |||
| return thisChar; | |||
| } | |||
| } | |||
| private static class RemoveEofFilter extends SimpleFilterReader { | |||
| int lookAhead = -1; | |||
| public RemoveEofFilter(Reader in) { | |||
| super(in); | |||
| try { | |||
| lookAhead = in.read(); | |||
| } catch (IOException e) { | |||
| lookAhead = -1; | |||
| } | |||
| } | |||
| public int read() throws IOException { | |||
| int lookAhead2 = super.read(); | |||
| // If source at EOF and lookAhead is ctrl-z, return EOF (NOT ctrl-z) | |||
| if (lookAhead2 == -1 && lookAhead == CTRLZ) { | |||
| return -1; | |||
| } | |||
| // Return current look-ahead | |||
| int i = lookAhead; | |||
| lookAhead = lookAhead2; | |||
| return i; | |||
| } | |||
| } | |||
| private static class AddTabFilter extends SimpleFilterReader { | |||
| int columnNumber = 0; | |||
| int tabLength = 0; | |||
| public AddTabFilter(Reader in, int tabLength) { | |||
| super(in); | |||
| this.tabLength = tabLength; | |||
| } | |||
| public int read() throws IOException { | |||
| int c = super.read(); | |||
| switch (c) { | |||
| case '\r': | |||
| case '\n': | |||
| columnNumber = 0; | |||
| break; | |||
| case ' ': | |||
| columnNumber++; | |||
| if (!editsBlocked()) { | |||
| int colNextTab = ((columnNumber + tabLength - 1) / tabLength) * tabLength; | |||
| int countSpaces = 1; | |||
| int numTabs = 0; | |||
| scanWhitespace: | |||
| while ((c = super.read()) != -1) { | |||
| switch (c) { | |||
| case ' ': | |||
| if (++columnNumber == colNextTab) { | |||
| numTabs++; | |||
| countSpaces = 0; | |||
| colNextTab += tabLength; | |||
| } else { | |||
| countSpaces++; | |||
| } | |||
| break; | |||
| case '\t': | |||
| columnNumber = colNextTab; | |||
| numTabs++; | |||
| countSpaces = 0; | |||
| colNextTab += tabLength; | |||
| break; | |||
| default: | |||
| push(c); | |||
| break scanWhitespace; | |||
| } | |||
| } | |||
| while (countSpaces-- > 0) { | |||
| push(' '); | |||
| columnNumber--; | |||
| } | |||
| while (numTabs-- > 0) { | |||
| push('\t'); | |||
| columnNumber -= tabLength; | |||
| } | |||
| c = super.read(); | |||
| switch (c) { | |||
| case ' ': columnNumber ++; break; | |||
| case '\t': columnNumber += tabLength; break; | |||
| } | |||
| } | |||
| break; | |||
| case '\t': | |||
| columnNumber = ((columnNumber + tabLength - 1) / tabLength) * tabLength; | |||
| break; | |||
| default: | |||
| columnNumber++; | |||
| } | |||
| return c; | |||
| } | |||
| } | |||
| private static class RemoveTabFilter extends SimpleFilterReader { | |||
| int columnNumber = 0; | |||
| int tabLength = 0; | |||
| public RemoveTabFilter(Reader in, int tabLength) { | |||
| super(in); | |||
| this.tabLength = tabLength; | |||
| } | |||
| public int read() throws IOException { | |||
| int c = super.read(); | |||
| switch (c) { | |||
| case '\r': | |||
| case '\n': | |||
| columnNumber = 0; | |||
| break; | |||
| case '\t': | |||
| int width = tabLength - columnNumber % tabLength; | |||
| if (!editsBlocked()) { | |||
| for (;width > 1; width--) { | |||
| push(' '); | |||
| } | |||
| c = ' '; | |||
| } | |||
| columnNumber += width; | |||
| break; | |||
| default: | |||
| columnNumber++; | |||
| } | |||
| return c; | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "asis", "add" and "remove". | |||
| */ | |||
| public static class AddAsisRemove extends EnumeratedAttribute { | |||
| private static final AddAsisRemove ASIS = newInstance("asis"); | |||
| private static final AddAsisRemove ADD = newInstance("add"); | |||
| private static final AddAsisRemove REMOVE = newInstance("remove"); | |||
| public String[] getValues() { | |||
| return new String[] {"add", "asis", "remove"}; | |||
| } | |||
| public boolean equals(Object other) { | |||
| return other instanceof AddAsisRemove | |||
| && getIndex() == ((AddAsisRemove) other).getIndex(); | |||
| } | |||
| AddAsisRemove resolve() throws IllegalStateException { | |||
| if (this.equals(ASIS)) { | |||
| return ASIS; | |||
| } | |||
| if (this.equals(ADD)) { | |||
| return ADD; | |||
| } | |||
| if (this.equals(REMOVE)) { | |||
| return REMOVE; | |||
| } | |||
| throw new IllegalStateException("No replacement for " + this); | |||
| } | |||
| // Works like clone() but doesn't show up in the Javadocs | |||
| private AddAsisRemove newInstance() { | |||
| return newInstance(getValue()); | |||
| } | |||
| public static AddAsisRemove newInstance(String value) { | |||
| AddAsisRemove a = new AddAsisRemove(); | |||
| a.setValue(value); | |||
| return a; | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "asis", "cr", "lf" and "crlf". | |||
| */ | |||
| public static class CrLf extends EnumeratedAttribute { | |||
| private static final CrLf ASIS = newInstance("asis"); | |||
| private static final CrLf CR = newInstance("cr"); | |||
| private static final CrLf CRLF = newInstance("crlf"); | |||
| private static final CrLf DOS = newInstance("dos"); | |||
| private static final CrLf LF = newInstance("lf"); | |||
| private static final CrLf MAC = newInstance("mac"); | |||
| private static final CrLf UNIX = newInstance("unix"); | |||
| /** | |||
| * @see EnumeratedAttribute#getValues | |||
| */ | |||
| public String[] getValues() { | |||
| return new String[] {"asis", "cr", "lf", "crlf", | |||
| "mac", "unix", "dos"}; | |||
| } | |||
| public boolean equals(Object other) { | |||
| return other instanceof CrLf | |||
| && getIndex() == ((CrLf) other).getIndex(); | |||
| } | |||
| CrLf resolve() { | |||
| if (this.equals(ASIS)) { | |||
| return ASIS; | |||
| } | |||
| if (this.equals(CR) || this.equals(UNIX)) { | |||
| return CR; | |||
| } | |||
| if (this.equals(CRLF) || this.equals(DOS)) { | |||
| return CRLF; | |||
| } | |||
| if (this.equals(LF) || this.equals(MAC)) { | |||
| return LF; | |||
| } | |||
| throw new IllegalStateException("No replacement for " + this); | |||
| } | |||
| // Works like clone() but doesn't show up in the Javadocs | |||
| private CrLf newInstance() { | |||
| return newInstance(getValue()); | |||
| } | |||
| public static CrLf newInstance(String value) { | |||
| CrLf c = new CrLf(); | |||
| c.setValue(value); | |||
| return c; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2000-2005 The Apache Software Foundation | |||
| * Copyright 2000-2005 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -17,24 +17,22 @@ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.BufferedWriter; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.Reader; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.BufferedReader; | |||
| import java.io.FileInputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.Reader; | |||
| import java.io.Writer; | |||
| import java.util.Vector; | |||
| import java.util.Enumeration; | |||
| import java.util.NoSuchElementException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||
| import org.apache.tools.ant.filters.FixCrLfFilter; | |||
| import org.apache.tools.ant.filters.ChainableReader; | |||
| import org.apache.tools.ant.types.FilterChain; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| @@ -82,53 +80,23 @@ import org.apache.tools.ant.util.FileUtils; | |||
| * @ant.task category="filesystem" | |||
| */ | |||
| public class FixCRLF extends MatchingTask { | |||
| private static final int UNDEF = -1; | |||
| private static final int NOTJAVA = 0; | |||
| private static final int LOOKING = 1; | |||
| private static final int IN_CHAR_CONST = 2; | |||
| private static final int IN_STR_CONST = 3; | |||
| private static final int IN_SINGLE_COMMENT = 4; | |||
| private static final int IN_MULTI_COMMENT = 5; | |||
| private static final int ASIS = 0; | |||
| private static final int CR = 1; | |||
| private static final int LF = 2; | |||
| private static final int CRLF = 3; | |||
| private static final int ADD = 1; | |||
| private static final int REMOVE = -1; | |||
| private static final int SPACES = -1; | |||
| private static final int TABS = 1; | |||
| private static final int INBUFLEN = 8192; | |||
| private static final int LINEBUFLEN = 200; | |||
| public class FixCRLF extends MatchingTask implements ChainableReader { | |||
| private static final char CTRLZ = '\u001A'; | |||
| public static final String ERROR_FILE_AND_SRCDIR | |||
| = "srcdir and file are mutually exclusive"; | |||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
| private int tablength = 8; | |||
| private String spaces = " "; | |||
| private StringBuffer linebuf = new StringBuffer(1024); | |||
| private StringBuffer linebuf2 = new StringBuffer(1024); | |||
| private int eol; | |||
| private String eolstr; | |||
| private int ctrlz; | |||
| private int tabs; | |||
| private boolean javafiles = false; | |||
| private boolean fixlast = true; | |||
| private boolean preserveLastModified = false; | |||
| private File srcDir; | |||
| private File destDir = null; | |||
| private File file; | |||
| private FixCrLfFilter filter = new FixCrLfFilter(); | |||
| /** | |||
| * Encoding to assume for the files | |||
| */ | |||
| private String encoding = null; | |||
| public static final String ERROR_FILE_AND_SRCDIR = "srcdir and file are mutually exclusive"; | |||
| /** | |||
| * Defaults the properties based on the system type. | |||
| @@ -137,24 +105,21 @@ public class FixCRLF extends MatchingTask { | |||
| * <li>DOS: eol="CRLF" tab="asis" eof="asis"</ul> | |||
| */ | |||
| public FixCRLF () { | |||
| tabs = ASIS; | |||
| if (Os.isFamily("mac")) { | |||
| ctrlz = REMOVE; | |||
| eol = CR; | |||
| eolstr = "\r"; | |||
| } else if (Os.isFamily("dos")) { | |||
| ctrlz = ASIS; | |||
| eol = CRLF; | |||
| eolstr = "\r\n"; | |||
| } else { | |||
| ctrlz = REMOVE; | |||
| eol = LF; | |||
| eolstr = "\n"; | |||
| } | |||
| } | |||
| /** | |||
| * Chain this task as a reader. | |||
| * @param rdr Reader to chain. | |||
| * @return a Reader. | |||
| * @since Ant 1.7? | |||
| */ | |||
| public final Reader chain(final Reader rdr) { | |||
| return filter.chain(rdr); | |||
| } | |||
| /** | |||
| * Set the source dir to find the source text files. | |||
| * @param srcDir the source directory. | |||
| */ | |||
| public void setSrcdir(File srcDir) { | |||
| this.srcDir = srcDir; | |||
| @@ -163,6 +128,7 @@ public class FixCRLF extends MatchingTask { | |||
| /** | |||
| * Set the destination where the fixed files should be placed. | |||
| * Default is to replace the original file. | |||
| * @param destDir the destination directory. | |||
| */ | |||
| public void setDestdir(File destDir) { | |||
| this.destDir = destDir; | |||
| @@ -170,15 +136,16 @@ public class FixCRLF extends MatchingTask { | |||
| /** | |||
| * Set to true if modifying Java source files. | |||
| * @param javafiles whether modifying Java files. | |||
| */ | |||
| public void setJavafiles(boolean javafiles) { | |||
| this.javafiles = javafiles; | |||
| filter.setJavafiles(javafiles); | |||
| } | |||
| /** | |||
| * set a single file to convert | |||
| * @since Ant1.7 | |||
| * @param file | |||
| * Set a single file to convert. | |||
| * @since Ant 1.6.3 | |||
| * @param file the file to convert. | |||
| */ | |||
| public void setFile(File file) { | |||
| this.file = file; | |||
| @@ -196,20 +163,7 @@ public class FixCRLF extends MatchingTask { | |||
| * </ul> | |||
| */ | |||
| public void setEol(CrLf attr) { | |||
| String option = attr.getValue(); | |||
| if (option.equals("asis")) { | |||
| eol = ASIS; | |||
| } else if (option.equals("cr") || option.equals("mac")) { | |||
| eol = CR; | |||
| eolstr = "\r"; | |||
| } else if (option.equals("lf") || option.equals("unix")) { | |||
| eol = LF; | |||
| eolstr = "\n"; | |||
| } else { | |||
| // Must be "crlf" | |||
| eol = CRLF; | |||
| eolstr = "\r\n"; | |||
| } | |||
| filter.setEol(FixCrLfFilter.CrLf.newInstance(attr.getValue())); | |||
| } | |||
| /** | |||
| @@ -252,15 +206,7 @@ public class FixCRLF extends MatchingTask { | |||
| * </ul> | |||
| */ | |||
| public void setTab(AddAsisRemove attr) { | |||
| String option = attr.getValue(); | |||
| if (option.equals("remove")) { | |||
| tabs = SPACES; | |||
| } else if (option.equals("asis")) { | |||
| tabs = ASIS; | |||
| } else { | |||
| // must be "add" | |||
| tabs = TABS; | |||
| } | |||
| filter.setTab(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue())); | |||
| } | |||
| /** | |||
| @@ -269,16 +215,11 @@ public class FixCRLF extends MatchingTask { | |||
| * @param tlength specify the length of tab in spaces, | |||
| */ | |||
| public void setTablength(int tlength) throws BuildException { | |||
| if (tlength < 2 || tlength > 80) { | |||
| throw new BuildException("tablength must be between 2 and 80", | |||
| getLocation()); | |||
| } | |||
| tablength = tlength; | |||
| StringBuffer sp = new StringBuffer(); | |||
| for (int i = 0; i < tablength; i++) { | |||
| sp.append(' '); | |||
| try { | |||
| filter.setTablength(tlength); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| spaces = sp.toString(); | |||
| } | |||
| /** | |||
| @@ -292,20 +233,13 @@ public class FixCRLF extends MatchingTask { | |||
| * </ul> | |||
| */ | |||
| public void setEof(AddAsisRemove attr) { | |||
| String option = attr.getValue(); | |||
| if (option.equals("remove")) { | |||
| ctrlz = REMOVE; | |||
| } else if (option.equals("asis")) { | |||
| ctrlz = ASIS; | |||
| } else { | |||
| // must be "add" | |||
| ctrlz = ADD; | |||
| } | |||
| filter.setEof(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue())); | |||
| } | |||
| /** | |||
| * Specifies the encoding Ant expects the files to be in - | |||
| * defaults to the platforms default encoding. | |||
| * Specifies the encoding Ant expects the files to be | |||
| * in--defaults to the platforms default encoding. | |||
| * @param encoding String encoding name. | |||
| */ | |||
| public void setEncoding(String encoding) { | |||
| this.encoding = encoding; | |||
| @@ -314,13 +248,15 @@ public class FixCRLF extends MatchingTask { | |||
| /** | |||
| * Specify whether a missing EOL will be added | |||
| * to the final line of a file. | |||
| * @param fixlast whether to fix the last line. | |||
| */ | |||
| public void setFixlast(boolean fixlast) { | |||
| this.fixlast = fixlast; | |||
| filter.setFixlast(fixlast); | |||
| } | |||
| /** | |||
| * Set to true if keeping the last modified time as the original files. | |||
| * Set whether to preserve the last modified time as the original files. | |||
| * @param preserve true if timestamps should be preserved. | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public void setPreserveLastModified(boolean preserve) { | |||
| @@ -333,14 +269,14 @@ public class FixCRLF extends MatchingTask { | |||
| public void execute() throws BuildException { | |||
| // first off, make sure that we've got a srcdir and destdir | |||
| if(file!=null) { | |||
| if(srcDir!=null) { | |||
| if (file != null) { | |||
| if (srcDir != null) { | |||
| throw new BuildException(ERROR_FILE_AND_SRCDIR); | |||
| } | |||
| //patch file into the fileset | |||
| fileset.setFile(file); | |||
| //set our parent dir | |||
| srcDir=file.getParentFile(); | |||
| srcDir = file.getParentFile(); | |||
| } | |||
| if (srcDir == null) { | |||
| throw new BuildException("srcdir attribute must be set!"); | |||
| @@ -359,14 +295,12 @@ public class FixCRLF extends MatchingTask { | |||
| throw new BuildException("destdir is not a directory!"); | |||
| } | |||
| } | |||
| // log options used | |||
| log("options:" | |||
| + " eol=" | |||
| + (eol == ASIS ? "asis" : eol == CR ? "cr" : eol == LF ? "lf" : "crlf") | |||
| + " tab=" + (tabs == TABS ? "add" : tabs == ASIS ? "asis" : "remove") | |||
| + " eof=" + (ctrlz == ADD ? "add" : ctrlz == ASIS ? "asis" : "remove") | |||
| + " tablength=" + tablength | |||
| + " eol=" + filter.getEol().getValue() | |||
| + " tab=" + filter.getTab().getValue() | |||
| + " eof=" + filter.getEof().getValue() | |||
| + " tablength=" + filter.getTablength() | |||
| + " encoding=" + (encoding == null ? "default" : encoding), | |||
| Project.MSG_VERBOSE); | |||
| @@ -378,177 +312,21 @@ public class FixCRLF extends MatchingTask { | |||
| } | |||
| } | |||
| /** | |||
| * Creates a Reader reading from a given file an taking the user | |||
| * defined encoding into account. | |||
| */ | |||
| private Reader getReader(File f) throws IOException { | |||
| return (encoding == null) ? new FileReader(f) | |||
| : new InputStreamReader(new FileInputStream(f), encoding); | |||
| } | |||
| private void processFile(String file) throws BuildException { | |||
| File srcFile = new File(srcDir, file); | |||
| long lastModified = srcFile.lastModified(); | |||
| File destD = destDir == null ? srcDir : destDir; | |||
| File tmpFile = null; | |||
| BufferedWriter outWriter; | |||
| OneLiner.BufferLine line; | |||
| // read the contents of the file | |||
| OneLiner lines = new OneLiner(srcFile); | |||
| FilterChain fc = new FilterChain(); | |||
| fc.add(filter); | |||
| Vector fcv = new Vector(1); | |||
| fcv.add(fc); | |||
| File tmpFile = FILE_UTILS.createTempFile("fixcrlf", "", null); | |||
| tmpFile.deleteOnExit(); | |||
| try { | |||
| // Set up the output Writer | |||
| try { | |||
| tmpFile = FILE_UTILS.createTempFile("fixcrlf", "", null); | |||
| tmpFile.deleteOnExit(); | |||
| Writer writer = (encoding == null) ? new FileWriter(tmpFile) | |||
| : new OutputStreamWriter(new FileOutputStream(tmpFile), | |||
| encoding); | |||
| outWriter = new BufferedWriter(writer); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| while (lines.hasMoreElements()) { | |||
| // In-line states | |||
| int endComment; | |||
| try { | |||
| line = (OneLiner.BufferLine) lines.nextElement(); | |||
| } catch (NoSuchElementException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| String lineString = line.getLineString(); | |||
| int linelen = line.length(); | |||
| // Note - all of the following processing NOT done for | |||
| // tabs ASIS | |||
| if (tabs == ASIS) { | |||
| // Just copy the body of the line across | |||
| try { | |||
| outWriter.write(lineString); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } // end of try-catch | |||
| } else { // (tabs != ASIS) | |||
| while (line.getNext() < linelen) { | |||
| switch (lines.getState()) { | |||
| case NOTJAVA: | |||
| notInConstant(line, line.length(), outWriter); | |||
| break; | |||
| case IN_MULTI_COMMENT: | |||
| endComment | |||
| = lineString.indexOf("*/", line.getNext()); | |||
| if (endComment >= 0) { | |||
| // End of multiLineComment on this line | |||
| endComment += 2; // Include the end token | |||
| lines.setState(LOOKING); | |||
| } else { | |||
| endComment = linelen; | |||
| } | |||
| notInConstant(line, endComment, outWriter); | |||
| break; | |||
| case IN_SINGLE_COMMENT: | |||
| notInConstant(line, line.length(), outWriter); | |||
| lines.setState(LOOKING); | |||
| break; | |||
| case IN_CHAR_CONST: | |||
| case IN_STR_CONST: | |||
| // Got here from LOOKING by finding an | |||
| // opening "\'" next points to that quote | |||
| // character. | |||
| // Find the end of the constant. Watch | |||
| // out for backslashes. Literal tabs are | |||
| // left unchanged, and the column is | |||
| // adjusted accordingly. | |||
| int begin = line.getNext(); | |||
| char terminator = (lines.getState() == IN_STR_CONST | |||
| ? '\"' | |||
| : '\''); | |||
| endOfCharConst(line, terminator); | |||
| while (line.getNext() < line.getLookahead()) { | |||
| if (line.getNextCharInc() == '\t') { | |||
| line.setColumn(line.getColumn() | |||
| + tablength | |||
| - (line.getColumn() % tablength)); | |||
| } else { | |||
| line.incColumn(); | |||
| } | |||
| } | |||
| // Now output the substring | |||
| try { | |||
| outWriter.write(line.substring(begin, | |||
| line.getNext())); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| lines.setState(LOOKING); | |||
| break; | |||
| case LOOKING: | |||
| nextStateChange(line); | |||
| notInConstant(line, line.getLookahead(), outWriter); | |||
| break; | |||
| } // end of switch (state) | |||
| } // end of while (line.getNext() < linelen) | |||
| } // end of else (tabs != ASIS) | |||
| if (!("".equals(line.getEol())) || fixlast) { | |||
| try { | |||
| outWriter.write(eolstr); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } // end of try-catch | |||
| } //end if non-blank original eol or fixlast | |||
| } // end of while (lines.hasNext()) | |||
| try { | |||
| // Handle CTRLZ | |||
| if (ctrlz == ASIS) { | |||
| outWriter.write(lines.getEofStr()); | |||
| } else if (ctrlz == ADD) { | |||
| outWriter.write(CTRLZ); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } finally { | |||
| try { | |||
| outWriter.close(); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| } | |||
| try { | |||
| lines.close(); | |||
| lines = null; | |||
| } catch (IOException e) { | |||
| throw new BuildException("Unable to close source file " | |||
| + srcFile); | |||
| } | |||
| FILE_UTILS.copyFile(srcFile, tmpFile, null, fcv, false, | |||
| false, encoding, getProject()); | |||
| File destFile = new File(destD, file); | |||
| @@ -556,15 +334,11 @@ public class FixCRLF extends MatchingTask { | |||
| if (destFile.exists()) { | |||
| // Compare the destination with the temp file | |||
| log("destFile exists", Project.MSG_DEBUG); | |||
| if (!FILE_UTILS.contentEquals(destFile, tmpFile)) { | |||
| log(destFile + " is being written", Project.MSG_DEBUG); | |||
| } else { | |||
| log(destFile + " is not written, as the contents " | |||
| + "are identical", Project.MSG_DEBUG); | |||
| destIsWrong = false; | |||
| } | |||
| destIsWrong = !FILE_UTILS.contentEquals(destFile, tmpFile); | |||
| log(destFile + (destIsWrong ? " is being written" | |||
| : " is not written, as the contents are identical"), | |||
| Project.MSG_DEBUG); | |||
| } | |||
| if (destIsWrong) { | |||
| FILE_UTILS.rename(tmpFile, destFile); | |||
| if (preserveLastModified) { | |||
| @@ -573,214 +347,20 @@ public class FixCRLF extends MatchingTask { | |||
| } | |||
| tmpFile = null; | |||
| } | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } finally { | |||
| try { | |||
| if (lines != null) { | |||
| lines.close(); | |||
| } | |||
| } catch (IOException io) { | |||
| log("Error closing " + srcFile, Project.MSG_ERR); | |||
| } // end of catch | |||
| if (tmpFile != null) { | |||
| tmpFile.delete(); | |||
| } | |||
| } // end of finally | |||
| } | |||
| /** | |||
| * Scan a BufferLine for the next state changing token: the beginning | |||
| * of a single or multi-line comment, a character or a string constant. | |||
| * | |||
| * As a side-effect, sets the buffer state to the next state, and sets | |||
| * field lookahead to the first character of the state-changing token, or | |||
| * to the next eol character. | |||
| * | |||
| * @param bufline BufferLine containing the string | |||
| * to be processed | |||
| * @exception org.apache.tools.ant.BuildException | |||
| * Thrown when end of line is reached | |||
| * before the terminator is found. | |||
| */ | |||
| private void nextStateChange(OneLiner.BufferLine bufline) | |||
| throws BuildException { | |||
| int eofl = bufline.length(); | |||
| int ptr = bufline.getNext(); | |||
| // Look for next single or double quote, double slash or slash star | |||
| while (ptr < eofl) { | |||
| switch (bufline.getChar(ptr++)) { | |||
| case '\'': | |||
| bufline.setState(IN_CHAR_CONST); | |||
| bufline.setLookahead(--ptr); | |||
| return; | |||
| case '\"': | |||
| bufline.setState(IN_STR_CONST); | |||
| bufline.setLookahead(--ptr); | |||
| return; | |||
| case '/': | |||
| if (ptr < eofl) { | |||
| if (bufline.getChar(ptr) == '*') { | |||
| bufline.setState(IN_MULTI_COMMENT); | |||
| bufline.setLookahead(--ptr); | |||
| return; | |||
| } else if (bufline.getChar(ptr) == '/') { | |||
| bufline.setState(IN_SINGLE_COMMENT); | |||
| bufline.setLookahead(--ptr); | |||
| return; | |||
| } | |||
| } | |||
| break; | |||
| } // end of switch (bufline.getChar(ptr++)) | |||
| } // end of while (ptr < eofl) | |||
| // Eol is the next token | |||
| bufline.setLookahead(ptr); | |||
| } | |||
| /** | |||
| * Scan a BufferLine forward from the 'next' pointer | |||
| * for the end of a character constant. Set 'lookahead' pointer to the | |||
| * character following the terminating quote. | |||
| * | |||
| * @param bufline BufferLine containing the string | |||
| * to be processed | |||
| * @param terminator The constant terminator | |||
| * | |||
| * @exception org.apache.tools.ant.BuildException | |||
| * Thrown when end of line is reached | |||
| * before the terminator is found. | |||
| */ | |||
| private void endOfCharConst(OneLiner.BufferLine bufline, char terminator) | |||
| throws BuildException { | |||
| int ptr = bufline.getNext(); | |||
| int eofl = bufline.length(); | |||
| char c; | |||
| ptr++; // skip past initial quote | |||
| while (ptr < eofl) { | |||
| if ((c = bufline.getChar(ptr++)) == '\\') { | |||
| ptr++; | |||
| } else { | |||
| if (c == terminator) { | |||
| bufline.setLookahead(ptr); | |||
| return; | |||
| } | |||
| } | |||
| } // end of while (ptr < eofl) | |||
| // Must have fallen through to the end of the line | |||
| throw new BuildException("endOfCharConst: unterminated char constant"); | |||
| } | |||
| /** | |||
| * Process a BufferLine string which is not part of a string constant. | |||
| * The start position of the string is given by the 'next' field. | |||
| * Sets the 'next' and 'column' fields in the BufferLine. | |||
| * | |||
| * @param bufline BufferLine containing the string | |||
| * to be processed | |||
| * @param end Index just past the end of the | |||
| * string | |||
| * @param outWriter Sink for the processed string | |||
| */ | |||
| private void notInConstant(OneLiner.BufferLine bufline, int end, | |||
| BufferedWriter outWriter) { | |||
| // N.B. both column and string index are zero-based | |||
| // Process a string not part of a constant; | |||
| // i.e. convert tabs<->spaces as required | |||
| // This is NOT called for ASIS tab handling | |||
| int nextTab; | |||
| int nextStop; | |||
| int tabspaces; | |||
| String line = bufline.substring(bufline.getNext(), end); | |||
| int place = 0; // Zero-based | |||
| int col = bufline.getColumn(); // Zero-based | |||
| // process sequences of white space | |||
| // first convert all tabs to spaces | |||
| linebuf = new StringBuffer(); | |||
| while ((nextTab = line.indexOf((int) '\t', place)) >= 0) { | |||
| linebuf.append(line.substring(place, nextTab)); // copy to the TAB | |||
| col += nextTab - place; | |||
| tabspaces = tablength - (col % tablength); | |||
| linebuf.append(spaces.substring(0, tabspaces)); | |||
| col += tabspaces; | |||
| place = nextTab + 1; | |||
| } // end of while | |||
| linebuf.append(line.substring(place, line.length())); | |||
| // if converting to spaces, all finished | |||
| String linestring = new String(linebuf.substring(0)); | |||
| if (tabs == REMOVE) { | |||
| try { | |||
| outWriter.write(linestring); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } // end of try-catch | |||
| } else { // tabs == ADD | |||
| int tabCol; | |||
| linebuf2 = new StringBuffer(); | |||
| place = 0; | |||
| col = bufline.getColumn(); | |||
| int placediff = col - 0; | |||
| // for the length of the string, cycle through the tab stop | |||
| // positions, checking for a space preceded by at least one | |||
| // other space at the tab stop. if so replace the longest possible | |||
| // preceding sequence of spaces with a tab. | |||
| nextStop = col + (tablength - col % tablength); | |||
| if (nextStop - col < 2) { | |||
| linebuf2.append(linestring.substring( | |||
| place, nextStop - placediff)); | |||
| place = nextStop - placediff; | |||
| nextStop += tablength; | |||
| } | |||
| for (; nextStop - placediff <= linestring.length(); | |||
| nextStop += tablength) { | |||
| for (tabCol = nextStop; | |||
| --tabCol - placediff >= place | |||
| && linestring.charAt(tabCol - placediff) == ' ';) { | |||
| ; // Loop for the side-effects | |||
| } | |||
| // tabCol is column index of the last non-space character | |||
| // before the next tab stop | |||
| if (nextStop - tabCol > 2) { | |||
| linebuf2.append(linestring.substring( | |||
| place, ++tabCol - placediff)); | |||
| linebuf2.append('\t'); | |||
| } else { | |||
| linebuf2.append(linestring.substring( | |||
| place, nextStop - placediff)); | |||
| } // end of else | |||
| place = nextStop - placediff; | |||
| } // end of for (nextStop ... ) | |||
| // pick up that last bit, if any | |||
| linebuf2.append(linestring.substring(place, linestring.length())); | |||
| try { | |||
| outWriter.write(linebuf2.substring(0)); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } // end of try-catch | |||
| } // end of else tabs == ADD | |||
| // Set column position as modified by this method | |||
| bufline.setColumn(bufline.getColumn() + linestring.length()); | |||
| bufline.setNext(end); | |||
| } | |||
| } | |||
| protected class OneLiner implements Enumeration { | |||
| private static final int UNDEF = -1; | |||
| private static final int NOTJAVA = 0; | |||
| private static final int LOOKING = 1; | |||
| private static final int INBUFLEN = 8192; | |||
| private static final int LINEBUFLEN = 200; | |||
| private static final char CTRLZ = '\u001A'; | |||
| private int state = javafiles ? LOOKING : NOTJAVA; | |||
| private int state = filter.getJavafiles() ? LOOKING : NOTJAVA; | |||
| private StringBuffer eolStr = new StringBuffer(LINEBUFLEN); | |||
| private StringBuffer eofStr = new StringBuffer(); | |||
| @@ -794,8 +374,11 @@ public class FixCRLF extends MatchingTask { | |||
| throws BuildException { | |||
| this.srcFile = srcFile; | |||
| try { | |||
| reader = new BufferedReader | |||
| (getReader(srcFile), INBUFLEN); | |||
| reader = new BufferedReader( | |||
| ((encoding == null) ? new FileReader(srcFile) | |||
| : new InputStreamReader( | |||
| new FileInputStream(srcFile), encoding)), INBUFLEN); | |||
| nextLine(); | |||
| } catch (IOException e) { | |||
| throw new BuildException(srcFile + ": " + e.getMessage(), | |||
| @@ -201,6 +201,42 @@ public class FixCrLfTest extends BuildFileTest { | |||
| executeTarget("testPreserveLastModified"); | |||
| } | |||
| public void testFilter1() { | |||
| executeTarget("testFilter1"); | |||
| } | |||
| public void testFilter2() { | |||
| executeTarget("testFilter2"); | |||
| } | |||
| public void testFilter3() { | |||
| executeTarget("testFilter3"); | |||
| } | |||
| public void testFilter4() { | |||
| executeTarget("testFilter4"); | |||
| } | |||
| public void testFilter5() { | |||
| executeTarget("testFilter5"); | |||
| } | |||
| public void testFilter6() { | |||
| executeTarget("testFilter6"); | |||
| } | |||
| public void testFilter7() { | |||
| executeTarget("testFilter7"); | |||
| } | |||
| public void testFilter8() { | |||
| executeTarget("testFilter8"); | |||
| } | |||
| public void testFilter9() { | |||
| executeTarget("testFilter9"); | |||
| } | |||
| public void assertEqualContent(File expect, File result) | |||
| throws AssertionFailedError, IOException { | |||
| if (!result.exists()) { | |||