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 | * New condition <parsersupports> which can look for XML parser feature or | ||||
| property support in the parser Ant is using. | 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 | Changes from Ant 1.6.2 to current Ant 1.6 CVS version | ||||
| ===================================================== | ===================================================== | ||||
| @@ -9,170 +9,202 @@ | |||||
| <h2><a name="fixcrlf">FixCRLF</a></h2> | <h2><a name="fixcrlf">FixCRLF</a></h2> | ||||
| <h3>Description</h3> | <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> | <h3>Parameters</h3> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| <tr> | <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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">srcDir</td> | <td valign="top">srcDir</td> | ||||
| <td valign="top">Where to find the files to be fixed up.</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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">file</td> | <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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">destDir</td> | <td valign="top">destDir</td> | ||||
| <td valign="top">Where to place the corrected files. Defaults to | <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 valign="top" align="center">No</td> | ||||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">includes</td> | <td valign="top">includes</td> | ||||
| <td valign="top">comma- or space-separated list of patterns of files that must be | <td valign="top">comma- or space-separated list of patterns of files that must be | ||||
| included. All files are included when omitted.</td> | included. All files are included when omitted.</td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">includesfile</td> | <td valign="top">includesfile</td> | ||||
| <td valign="top">the name of a file. Each line of this file is | <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 valign="top" align="center">No</td> | ||||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">excludes</td> | <td valign="top">excludes</td> | ||||
| <td valign="top">comma- or space-separated list of patterns of files that must be | <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> | excluded. No files (except default excludes) are excluded when omitted.</td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">excludesfile</td> | <td valign="top">excludesfile</td> | ||||
| <td valign="top">the name of a file. Each line of this file is | <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 valign="top" align="center">No</td> | ||||
| <td bgcolor="#CCCCCC"><nbsp /></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">defaultexcludes</td> | <td valign="top">defaultexcludes</td> | ||||
| <td valign="top">indicates whether default excludes should be used or not | <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 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> | ||||
| <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">tab</td> | ||||
| <td valign="top">Specifies how tab characters are to be handled. Valid | <td valign="top">Specifies how tab characters are to be handled. Valid | ||||
| values for this property are: | values for this property are: | ||||
| @@ -182,28 +214,28 @@ supports all attributes of <code><fileset></code> | |||||
| <li>remove: convert tabs to spaces</li> | <li>remove: convert tabs to spaces</li> | ||||
| </ul> | </ul> | ||||
| Default for this parameter is "asis". | 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> | <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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">tablength</td> | <td valign="top">tablength</td> | ||||
| <td valign="top">TAB character interval. Valid values are between | <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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">eof</td> | <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 | For Unix platforms, the default is remove. For DOS based systems | ||||
| (including Windows), the default is asis. | (including Windows), the default is asis. | ||||
| </td> | </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> | ||||
| <tr> | <tr> | ||||
| <td valign="top">fixlast</td> | <td valign="top">fixlast</td> | ||||
| <td valign="top">Whether to add a missing EOL to the last line | <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> | </tr> | ||||
| </table> | </table> | ||||
| <h3>Examples</h3> | <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 | <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. | <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 | <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 | <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> | <hr> | ||||
| <p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | <p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -194,4 +194,100 @@ | |||||
| <fail unless="fs" /> | <fail unless="fs" /> | ||||
| </target> | </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> | </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"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -17,24 +17,22 @@ | |||||
| package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
| import java.io.BufferedReader; | |||||
| import java.io.BufferedWriter; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.FileInputStream; | |||||
| import java.io.FileOutputStream; | |||||
| import java.io.Reader; | |||||
| import java.io.FileReader; | import java.io.FileReader; | ||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.BufferedReader; | |||||
| import java.io.FileInputStream; | |||||
| import java.io.InputStreamReader; | 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.Enumeration; | ||||
| import java.util.NoSuchElementException; | import java.util.NoSuchElementException; | ||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.DirectoryScanner; | 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.types.EnumeratedAttribute; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| @@ -82,53 +80,23 @@ import org.apache.tools.ant.util.FileUtils; | |||||
| * @ant.task category="filesystem" | * @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 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 boolean preserveLastModified = false; | ||||
| private File srcDir; | private File srcDir; | ||||
| private File destDir = null; | private File destDir = null; | ||||
| private File file; | private File file; | ||||
| private FixCrLfFilter filter = new FixCrLfFilter(); | |||||
| /** | /** | ||||
| * Encoding to assume for the files | * Encoding to assume for the files | ||||
| */ | */ | ||||
| private String encoding = null; | 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. | * 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> | * <li>DOS: eol="CRLF" tab="asis" eof="asis"</ul> | ||||
| */ | */ | ||||
| public FixCRLF () { | 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. | * Set the source dir to find the source text files. | ||||
| * @param srcDir the source directory. | |||||
| */ | */ | ||||
| public void setSrcdir(File srcDir) { | public void setSrcdir(File srcDir) { | ||||
| this.srcDir = srcDir; | this.srcDir = srcDir; | ||||
| @@ -163,6 +128,7 @@ public class FixCRLF extends MatchingTask { | |||||
| /** | /** | ||||
| * Set the destination where the fixed files should be placed. | * Set the destination where the fixed files should be placed. | ||||
| * Default is to replace the original file. | * Default is to replace the original file. | ||||
| * @param destDir the destination directory. | |||||
| */ | */ | ||||
| public void setDestdir(File destDir) { | public void setDestdir(File destDir) { | ||||
| this.destDir = destDir; | this.destDir = destDir; | ||||
| @@ -170,15 +136,16 @@ public class FixCRLF extends MatchingTask { | |||||
| /** | /** | ||||
| * Set to true if modifying Java source files. | * Set to true if modifying Java source files. | ||||
| * @param javafiles whether modifying Java files. | |||||
| */ | */ | ||||
| public void setJavafiles(boolean javafiles) { | 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) { | public void setFile(File file) { | ||||
| this.file = file; | this.file = file; | ||||
| @@ -196,20 +163,7 @@ public class FixCRLF extends MatchingTask { | |||||
| * </ul> | * </ul> | ||||
| */ | */ | ||||
| public void setEol(CrLf attr) { | 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> | * </ul> | ||||
| */ | */ | ||||
| public void setTab(AddAsisRemove attr) { | 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, | * @param tlength specify the length of tab in spaces, | ||||
| */ | */ | ||||
| public void setTablength(int tlength) throws BuildException { | 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> | * </ul> | ||||
| */ | */ | ||||
| public void setEof(AddAsisRemove attr) { | 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) { | public void setEncoding(String encoding) { | ||||
| this.encoding = encoding; | this.encoding = encoding; | ||||
| @@ -314,13 +248,15 @@ public class FixCRLF extends MatchingTask { | |||||
| /** | /** | ||||
| * Specify whether a missing EOL will be added | * Specify whether a missing EOL will be added | ||||
| * to the final line of a file. | * to the final line of a file. | ||||
| * @param fixlast whether to fix the last line. | |||||
| */ | */ | ||||
| public void setFixlast(boolean fixlast) { | 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 | * @since Ant 1.6.3 | ||||
| */ | */ | ||||
| public void setPreserveLastModified(boolean preserve) { | public void setPreserveLastModified(boolean preserve) { | ||||
| @@ -333,14 +269,14 @@ public class FixCRLF extends MatchingTask { | |||||
| public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
| // first off, make sure that we've got a srcdir and destdir | // 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); | throw new BuildException(ERROR_FILE_AND_SRCDIR); | ||||
| } | } | ||||
| //patch file into the fileset | //patch file into the fileset | ||||
| fileset.setFile(file); | fileset.setFile(file); | ||||
| //set our parent dir | //set our parent dir | ||||
| srcDir=file.getParentFile(); | |||||
| srcDir = file.getParentFile(); | |||||
| } | } | ||||
| if (srcDir == null) { | if (srcDir == null) { | ||||
| throw new BuildException("srcdir attribute must be set!"); | 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!"); | throw new BuildException("destdir is not a directory!"); | ||||
| } | } | ||||
| } | } | ||||
| // log options used | // log options used | ||||
| log("options:" | 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), | + " encoding=" + (encoding == null ? "default" : encoding), | ||||
| Project.MSG_VERBOSE); | 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 { | private void processFile(String file) throws BuildException { | ||||
| File srcFile = new File(srcDir, file); | File srcFile = new File(srcDir, file); | ||||
| long lastModified = srcFile.lastModified(); | long lastModified = srcFile.lastModified(); | ||||
| File destD = destDir == null ? srcDir : destDir; | 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 { | 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); | File destFile = new File(destD, file); | ||||
| @@ -556,15 +334,11 @@ public class FixCRLF extends MatchingTask { | |||||
| if (destFile.exists()) { | if (destFile.exists()) { | ||||
| // Compare the destination with the temp file | // Compare the destination with the temp file | ||||
| log("destFile exists", Project.MSG_DEBUG); | 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) { | if (destIsWrong) { | ||||
| FILE_UTILS.rename(tmpFile, destFile); | FILE_UTILS.rename(tmpFile, destFile); | ||||
| if (preserveLastModified) { | if (preserveLastModified) { | ||||
| @@ -573,214 +347,20 @@ public class FixCRLF extends MatchingTask { | |||||
| } | } | ||||
| tmpFile = null; | tmpFile = null; | ||||
| } | } | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| throw new BuildException(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 { | 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 eolStr = new StringBuffer(LINEBUFLEN); | ||||
| private StringBuffer eofStr = new StringBuffer(); | private StringBuffer eofStr = new StringBuffer(); | ||||
| @@ -794,8 +374,11 @@ public class FixCRLF extends MatchingTask { | |||||
| throws BuildException { | throws BuildException { | ||||
| this.srcFile = srcFile; | this.srcFile = srcFile; | ||||
| try { | try { | ||||
| reader = new BufferedReader | |||||
| (getReader(srcFile), INBUFLEN); | |||||
| reader = new BufferedReader( | |||||
| ((encoding == null) ? new FileReader(srcFile) | |||||
| : new InputStreamReader( | |||||
| new FileInputStream(srcFile), encoding)), INBUFLEN); | |||||
| nextLine(); | nextLine(); | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| throw new BuildException(srcFile + ": " + e.getMessage(), | throw new BuildException(srcFile + ": " + e.getMessage(), | ||||
| @@ -201,6 +201,42 @@ public class FixCrLfTest extends BuildFileTest { | |||||
| executeTarget("testPreserveLastModified"); | 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) | public void assertEqualContent(File expect, File result) | ||||
| throws AssertionFailedError, IOException { | throws AssertionFailedError, IOException { | ||||
| if (!result.exists()) { | if (!result.exists()) { | ||||