KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > FixCRLF


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File JavaDoc;
22 import java.io.Reader JavaDoc;
23 import java.io.FileReader JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.BufferedReader JavaDoc;
26 import java.io.FileInputStream JavaDoc;
27 import java.io.InputStreamReader JavaDoc;
28 import java.util.Vector JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.NoSuchElementException JavaDoc;
31 import org.apache.tools.ant.Project;
32 import org.apache.tools.ant.BuildException;
33 import org.apache.tools.ant.DirectoryScanner;
34 import org.apache.tools.ant.filters.FixCrLfFilter;
35 import org.apache.tools.ant.filters.ChainableReader;
36 import org.apache.tools.ant.types.FilterChain;
37 import org.apache.tools.ant.types.EnumeratedAttribute;
38 import org.apache.tools.ant.util.FileUtils;
39
40 /**
41  * Converts text source files to local OS formatting conventions, as
42  * well as repair text files damaged by misconfigured or misguided editors or
43  * file transfer programs.
44  * <p>
45  * This task can take the following arguments:
46  * <ul>
47  * <li>srcdir
48  * <li>destdir
49  * <li>include
50  * <li>exclude
51  * <li>cr
52  * <li>eol
53  * <li>tab
54  * <li>eof
55  * <li>encoding
56  * <li>targetencoding
57  * </ul>
58  * Of these arguments, only <b>sourcedir</b> is required.
59  * <p>
60  * When this task executes, it will scan the srcdir based on the include
61  * and exclude properties.
62  * <p>
63  * This version generalises the handling of EOL characters, and allows
64  * for CR-only line endings (the standard on Mac systems prior to OS X).
65  * Tab handling has also been generalised to accommodate any tabwidth
66  * from 2 to 80, inclusive. Importantly, it will leave untouched any
67  * literal TAB characters embedded within string or character constants.
68  * <p>
69  * <em>Warning:</em> do not run on binary files.
70  * <em>Caution:</em> run with care on carefully formatted files.
71  * This may sound obvious, but if you don't specify asis, presume that
72  * your files are going to be modified. If "tabs" is "add" or "remove",
73  * whitespace characters may be added or removed as necessary. Similarly,
74  * for CR's - in fact "eol"="crlf" or cr="add" can result in cr
75  * characters being removed in one special case accommodated, i.e.,
76  * CRCRLF is regarded as a single EOL to handle cases where other
77  * programs have converted CRLF into CRCRLF.
78  *
79  * @since Ant 1.1
80  *
81  * @ant.task category="filesystem"
82  */

83
84 public class FixCRLF extends MatchingTask implements ChainableReader {
85
86     /** error string for using srcdir and file */
87     public static final String JavaDoc ERROR_FILE_AND_SRCDIR
88         = "srcdir and file are mutually exclusive";
89
90     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
91
92     private boolean preserveLastModified = false;
93     private File JavaDoc srcDir;
94     private File JavaDoc destDir = null;
95     private File JavaDoc file;
96     private FixCrLfFilter filter = new FixCrLfFilter();
97     private Vector JavaDoc fcv = null;
98
99     /**
100      * Encoding to assume for the files
101      */

102     private String JavaDoc encoding = null;
103
104     /**
105      * Encoding to use for output files
106      */

107     private String JavaDoc outputEncoding = null;
108
109     /**
110      * Chain this task as a reader.
111      * @param rdr Reader to chain.
112      * @return a Reader.
113      * @since Ant 1.7?
114      */

115     public final Reader JavaDoc chain(final Reader JavaDoc rdr) {
116         return filter.chain(rdr);
117     }
118
119     /**
120      * Set the source dir to find the source text files.
121      * @param srcDir the source directory.
122      */

123     public void setSrcdir(File JavaDoc srcDir) {
124         this.srcDir = srcDir;
125     }
126
127     /**
128      * Set the destination where the fixed files should be placed.
129      * Default is to replace the original file.
130      * @param destDir the destination directory.
131      */

132     public void setDestdir(File JavaDoc destDir) {
133         this.destDir = destDir;
134     }
135
136     /**
137      * Set to true if modifying Java source files.
138      * @param javafiles whether modifying Java files.
139      */

140     public void setJavafiles(boolean javafiles) {
141         filter.setJavafiles(javafiles);
142     }
143
144     /**
145      * Set a single file to convert.
146      * @since Ant 1.6.3
147      * @param file the file to convert.
148      */

149     public void setFile(File JavaDoc file) {
150         this.file = file;
151     }
152
153     /**
154      * Specify how EndOfLine characters are to be handled.
155      *
156      * @param attr valid values:
157      * <ul>
158      * <li>asis: leave line endings alone
159      * <li>cr: convert line endings to CR
160      * <li>lf: convert line endings to LF
161      * <li>crlf: convert line endings to CRLF
162      * </ul>
163      */

164     public void setEol(CrLf attr) {
165         filter.setEol(FixCrLfFilter.CrLf.newInstance(attr.getValue()));
166     }
167
168     /**
169      * Specify how carriage return (CR) characters are to be handled.
170      *
171      * @param attr valid values:
172      * <ul>
173      * <li>add: ensure that there is a CR before every LF
174      * <li>asis: leave CR characters alone
175      * <li>remove: remove all CR characters
176      * </ul>
177      *
178      * @deprecated since 1.4.x.
179      * Use {@link #setEol setEol} instead.
180      */

181     public void setCr(AddAsisRemove attr) {
182         log("DEPRECATED: The cr attribute has been deprecated,",
183             Project.MSG_WARN);
184         log("Please use the eol attribute instead", Project.MSG_WARN);
185         String JavaDoc option = attr.getValue();
186         CrLf c = new CrLf();
187         if (option.equals("remove")) {
188             c.setValue("lf");
189         } else if (option.equals("asis")) {
190             c.setValue("asis");
191         } else {
192             // must be "add"
193
c.setValue("crlf");
194         }
195         setEol(c);
196     }
197
198     /**
199      * Specify how tab characters are to be handled.
200      *
201      * @param attr valid values:
202      * <ul>
203      * <li>add: convert sequences of spaces which span a tab stop to tabs
204      * <li>asis: leave tab and space characters alone
205      * <li>remove: convert tabs to spaces
206      * </ul>
207      */

208     public void setTab(AddAsisRemove attr) {
209         filter.setTab(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue()));
210     }
211
212     /**
213      * Specify tab length in characters.
214      *
215      * @param tlength specify the length of tab in spaces.
216      * @throws BuildException on error.
217      */

218     public void setTablength(int tlength) throws BuildException {
219         try {
220             filter.setTablength(tlength);
221         } catch (IOException JavaDoc e) {
222             throw new BuildException(e);
223         }
224     }
225
226     /**
227      * Specify how DOS EOF (control-z) characters are to be handled.
228      *
229      * @param attr valid values:
230      * <ul>
231      * <li>add: ensure that there is an eof at the end of the file
232      * <li>asis: leave eof characters alone
233      * <li>remove: remove any eof character found at the end
234      * </ul>
235      */

236     public void setEof(AddAsisRemove attr) {
237         filter.setEof(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue()));
238     }
239
240     /**
241      * Specifies the encoding Ant expects the files to be
242      * in--defaults to the platforms default encoding.
243      * @param encoding String encoding name.
244      */

245     public void setEncoding(String JavaDoc encoding) {
246         this.encoding = encoding;
247     }
248
249     /**
250      * Specifies the encoding that the files are
251      * to be written in--same as input encoding by default.
252      * @param outputEncoding String outputEncoding name.
253      */

254     public void setOutputEncoding(String JavaDoc outputEncoding) {
255         this.outputEncoding = outputEncoding;
256     }
257
258     /**
259      * Specify whether a missing EOL will be added
260      * to the final line of a file.
261      * @param fixlast whether to fix the last line.
262      */

263     public void setFixlast(boolean fixlast) {
264         filter.setFixlast(fixlast);
265     }
266
267     /**
268      * Set whether to preserve the last modified time as the original files.
269      * @param preserve true if timestamps should be preserved.
270      * @since Ant 1.6.3
271      */

272     public void setPreserveLastModified(boolean preserve) {
273         preserveLastModified = preserve;
274     }
275
276     /**
277      * Executes the task.
278      * @throws BuildException on error.
279      */

280     public void execute() throws BuildException {
281         // first off, make sure that we've got a srcdir and destdir
282
validate();
283
284         // log options used
285
String JavaDoc enc = encoding == null ? "default" : encoding;
286         log("options:"
287             + " eol=" + filter.getEol().getValue()
288             + " tab=" + filter.getTab().getValue()
289             + " eof=" + filter.getEof().getValue()
290             + " tablength=" + filter.getTablength()
291             + " encoding=" + enc
292             + " outputencoding="
293             + (outputEncoding == null ? enc : outputEncoding),
294             Project.MSG_VERBOSE);
295
296         DirectoryScanner ds = super.getDirectoryScanner(srcDir);
297         String JavaDoc[] files = ds.getIncludedFiles();
298
299         for (int i = 0; i < files.length; i++) {
300             processFile(files[i]);
301         }
302     }
303
304     private void validate() throws BuildException {
305         if (file != null) {
306             if (srcDir != null) {
307                 throw new BuildException(ERROR_FILE_AND_SRCDIR);
308             }
309             //patch file into the fileset
310
fileset.setFile(file);
311             //set our parent dir
312
srcDir = file.getParentFile();
313         }
314         if (srcDir == null) {
315             throw new BuildException("srcdir attribute must be set!");
316         }
317         if (!srcDir.exists()) {
318             throw new BuildException("srcdir does not exist!");
319         }
320         if (!srcDir.isDirectory()) {
321             throw new BuildException("srcdir is not a directory!");
322         }
323         if (destDir != null) {
324             if (!destDir.exists()) {
325                 throw new BuildException("destdir does not exist!");
326             }
327             if (!destDir.isDirectory()) {
328                 throw new BuildException("destdir is not a directory!");
329             }
330         }
331     }
332
333     private void processFile(String JavaDoc file) throws BuildException {
334         File JavaDoc srcFile = new File JavaDoc(srcDir, file);
335         long lastModified = srcFile.lastModified();
336         File JavaDoc destD = destDir == null ? srcDir : destDir;
337
338         if (fcv == null) {
339             FilterChain fc = new FilterChain();
340             fc.add(filter);
341             fcv = new Vector JavaDoc(1);
342             fcv.add(fc);
343         }
344         File JavaDoc tmpFile = FILE_UTILS.createTempFile("fixcrlf", "", null);
345         tmpFile.deleteOnExit();
346         try {
347             FILE_UTILS.copyFile(srcFile, tmpFile, null, fcv, false, false,
348                 encoding, outputEncoding == null ? encoding : outputEncoding,
349                 getProject());
350
351             File JavaDoc destFile = new File JavaDoc(destD, file);
352
353             boolean destIsWrong = true;
354             if (destFile.exists()) {
355                 // Compare the destination with the temp file
356
log("destFile exists", Project.MSG_DEBUG);
357                 destIsWrong = !FILE_UTILS.contentEquals(destFile, tmpFile);
358                 log(destFile + (destIsWrong ? " is being written"
359                     : " is not written, as the contents are identical"),
360                     Project.MSG_DEBUG);
361             }
362             if (destIsWrong) {
363                 FILE_UTILS.rename(tmpFile, destFile);
364                 if (preserveLastModified) {
365                     log("preserved lastModified", Project.MSG_DEBUG);
366                     FILE_UTILS.setFileLastModified(destFile, lastModified);
367                 }
368                 tmpFile = null;
369             }
370         } catch (IOException JavaDoc e) {
371             throw new BuildException(e);
372         }
373     }
374
375     /**
376      * Deprecated, the functionality has been moved to filters.FixCrLfFilter.
377      * @deprecated since 1.7.0.
378      */

379     protected class OneLiner implements Enumeration JavaDoc {
380         private static final int UNDEF = -1;
381         private static final int NOTJAVA = 0;
382         private static final int LOOKING = 1;
383         private static final int INBUFLEN = 8192;
384         private static final int LINEBUFLEN = 200;
385         private static final char CTRLZ = '\u001A';
386
387         private int state = filter.getJavafiles() ? LOOKING : NOTJAVA;
388
389         private StringBuffer JavaDoc eolStr = new StringBuffer JavaDoc(LINEBUFLEN);
390         private StringBuffer JavaDoc eofStr = new StringBuffer JavaDoc();
391
392         private BufferedReader JavaDoc reader;
393         private StringBuffer JavaDoc line = new StringBuffer JavaDoc();
394         private boolean reachedEof = false;
395         private File JavaDoc srcFile;
396
397         /**
398          * Constructor.
399          * @param srcFile the file to read.
400          * @throws BuildException if there is an error.
401          */

402         public OneLiner(File JavaDoc srcFile)
403             throws BuildException {
404             this.srcFile = srcFile;
405             try {
406                 reader = new BufferedReader JavaDoc(
407                     ((encoding == null) ? new FileReader JavaDoc(srcFile)
408                     : new InputStreamReader JavaDoc(
409                     new FileInputStream JavaDoc(srcFile), encoding)), INBUFLEN);
410
411                 nextLine();
412             } catch (IOException JavaDoc e) {
413                 throw new BuildException(srcFile + ": " + e.getMessage(),
414                                          e, getLocation());
415             }
416         }
417
418         /**
419          * Move to the next line.
420          * @throws BuildException if there is an error.
421          */

422         protected void nextLine()
423             throws BuildException {
424             int ch = -1;
425             int eolcount = 0;
426
427             eolStr = new StringBuffer JavaDoc();
428             line = new StringBuffer JavaDoc();
429
430             try {
431                 ch = reader.read();
432                 while (ch != -1 && ch != '\r' && ch != '\n') {
433                     line.append((char) ch);
434                     ch = reader.read();
435                 }
436
437                 if (ch == -1 && line.length() == 0) {
438                     // Eof has been reached
439
reachedEof = true;
440                     return;
441                 }
442
443                 switch ((char) ch) {
444                 case '\r':
445                     // Check for \r, \r\n and \r\r\n
446
// Regard \r\r not followed by \n as two lines
447
++eolcount;
448                     eolStr.append('\r');
449                     reader.mark(2);
450                     ch = reader.read();
451                     switch (ch) {
452                     case '\r':
453                         ch = reader.read();
454                         if ((char) (ch) == '\n') {
455                             eolcount += 2;
456                             eolStr.append("\r\n");
457                         } else {
458                             reader.reset();
459                         }
460                         break;
461                     case '\n':
462                         ++eolcount;
463                         eolStr.append('\n');
464                         break;
465                     case -1:
466                         // don't reposition when we've reached the end
467
// of the stream
468
break;
469                     default:
470                         reader.reset();
471                         break;
472                     } // end of switch ((char)(ch = reader.read()))
473
break;
474
475                 case '\n':
476                     ++eolcount;
477                     eolStr.append('\n');
478                     break;
479                 default:
480                     // Fall tru
481
} // end of switch ((char) ch)
482

483                 // if at eolcount == 0 and trailing characters of string
484
// are CTRL-Zs, set eofStr
485
if (eolcount == 0) {
486                     int i = line.length();
487                     while (--i >= 0 && line.charAt(i) == CTRLZ) {
488                         // keep searching for the first ^Z
489
}
490                     if (i < line.length() - 1) {
491                         // Trailing characters are ^Zs
492
// Construct new line and eofStr
493
eofStr.append(line.toString().substring(i + 1));
494                         if (i < 0) {
495                             line.setLength(0);
496                             reachedEof = true;
497                         } else {
498                             line.setLength(i + 1);
499                         }
500                     }
501
502                 } // end of if (eolcount == 0)
503

504             } catch (IOException JavaDoc e) {
505                 throw new BuildException(srcFile + ": " + e.getMessage(),
506                                          e, getLocation());
507             }
508         }
509
510         /**
511          * get the eof string.
512          * @return the eof string.
513          */

514         public String JavaDoc getEofStr() {
515             return eofStr.substring(0);
516         }
517
518         /**
519          * get the state.
520          * @return the state.
521          */

522         public int getState() {
523             return state;
524         }
525
526         /**
527          * Set the state.
528          * @param state the value to use.
529          */

530         public void setState(int state) {
531             this.state = state;
532         }
533
534         /**
535          * @return true if there is more elements.
536          */

537         public boolean hasMoreElements() {
538             return !reachedEof;
539         }
540
541         /**
542          * get the next element.
543          * @return the next element.
544          * @throws NoSuchElementException if there is no more.
545          */

546         public Object JavaDoc nextElement()
547             throws NoSuchElementException JavaDoc {
548             if (!hasMoreElements()) {
549                 throw new NoSuchElementException JavaDoc("OneLiner");
550             }
551             BufferLine tmpLine =
552                     new BufferLine(line.toString(), eolStr.substring(0));
553             nextLine();
554             return tmpLine;
555         }
556
557         /**
558          * Close the reader.
559          * @throws IOException if there is an error.
560          */

561         public void close() throws IOException JavaDoc {
562             if (reader != null) {
563                 reader.close();
564             }
565         }
566
567         class BufferLine {
568             private int next = 0;
569             private int column = 0;
570             private int lookahead = UNDEF;
571             private String JavaDoc line;
572             private String JavaDoc eolStr;
573
574             public BufferLine(String JavaDoc line, String JavaDoc eolStr)
575                 throws BuildException {
576                 next = 0;
577                 column = 0;
578                 this.line = line;
579                 this.eolStr = eolStr;
580             }
581
582             public int getNext() {
583                 return next;
584             }
585
586             public void setNext(int next) {
587                 this.next = next;
588             }
589
590             public int getLookahead() {
591                 return lookahead;
592             }
593
594             public void setLookahead(int lookahead) {
595                 this.lookahead = lookahead;
596             }
597
598             public char getChar(int i) {
599                 return line.charAt(i);
600             }
601
602             public char getNextChar() {
603                 return getChar(next);
604             }
605
606             public char getNextCharInc() {
607                 return getChar(next++);
608             }
609
610             public int getColumn() {
611                 return column;
612             }
613
614             public void setColumn(int col) {
615                 column = col;
616             }
617
618             public int incColumn() {
619                 return column++;
620             }
621
622             public int length() {
623                 return line.length();
624             }
625
626             public int getEolLength() {
627                 return eolStr.length();
628             }
629
630             public String JavaDoc getLineString() {
631                 return line;
632             }
633
634             public String JavaDoc getEol() {
635                 return eolStr;
636             }
637
638             public String JavaDoc substring(int begin) {
639                 return line.substring(begin);
640             }
641
642             public String JavaDoc substring(int begin, int end) {
643                 return line.substring(begin, end);
644             }
645
646             public void setState(int state) {
647                 OneLiner.this.setState(state);
648             }
649
650             public int getState() {
651                 return OneLiner.this.getState();
652             }
653         }
654     }
655
656     /**
657      * Enumerated attribute with the values "asis", "add" and "remove".
658      */

659     public static class AddAsisRemove extends EnumeratedAttribute {
660         /** {@inheritDoc}. */
661         public String JavaDoc[] getValues() {
662             return new String JavaDoc[] {"add", "asis", "remove"};
663         }
664     }
665
666     /**
667      * Enumerated attribute with the values "asis", "cr", "lf" and "crlf".
668      */

669     public static class CrLf extends EnumeratedAttribute {
670         /**
671          * @see EnumeratedAttribute#getValues
672          */

673         /** {@inheritDoc}. */
674         public String JavaDoc[] getValues() {
675             return new String JavaDoc[] {"asis", "cr", "lf", "crlf",
676                                  "mac", "unix", "dos"};
677         }
678     }
679
680 }
681
682
Popular Tags