source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 34.0 KB
Line 
1/*
2 * Copyright 2000-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant.taskdefs;
19
20import java.io.BufferedReader;
21import java.io.BufferedWriter;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.FileReader;
26import java.io.FileWriter;
27import java.io.IOException;
28import java.io.InputStreamReader;
29import java.io.OutputStreamWriter;
30import java.io.Reader;
31import java.io.Writer;
32import java.util.Enumeration;
33import java.util.NoSuchElementException;
34import org.apache.tools.ant.BuildException;
35import org.apache.tools.ant.DirectoryScanner;
36import org.apache.tools.ant.Project;
37import org.apache.tools.ant.taskdefs.condition.Os;
38import org.apache.tools.ant.types.EnumeratedAttribute;
39import org.apache.tools.ant.util.FileUtils;
40
41/**
42 * Converts text source files to local OS formatting conventions, as
43 * well as repair text files damaged by misconfigured or misguided editors or
44 * file transfer programs.
45 * <p>
46 * This task can take the following arguments:
47 * <ul>
48 * <li>srcdir
49 * <li>destdir
50 * <li>include
51 * <li>exclude
52 * <li>cr
53 * <li>eol
54 * <li>tab
55 * <li>eof
56 * <li>encoding
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 (which I suspect is the standard on Macs.)
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
84public class FixCRLF extends MatchingTask {
85
86 private static final int UNDEF = -1;
87 private static final int NOTJAVA = 0;
88 private static final int LOOKING = 1;
89 private static final int IN_CHAR_CONST = 2;
90 private static final int IN_STR_CONST = 3;
91 private static final int IN_SINGLE_COMMENT = 4;
92 private static final int IN_MULTI_COMMENT = 5;
93
94 private static final int ASIS = 0;
95 private static final int CR = 1;
96 private static final int LF = 2;
97 private static final int CRLF = 3;
98 private static final int ADD = 1;
99 private static final int REMOVE = -1;
100 private static final int SPACES = -1;
101 private static final int TABS = 1;
102
103 private static final int INBUFLEN = 8192;
104 private static final int LINEBUFLEN = 200;
105
106 private static final char CTRLZ = '\u001A';
107
108 private int tablength = 8;
109 private String spaces = " ";
110 private StringBuffer linebuf = new StringBuffer(1024);
111 private StringBuffer linebuf2 = new StringBuffer(1024);
112 private int eol;
113 private String eolstr;
114 private int ctrlz;
115 private int tabs;
116 private boolean javafiles = false;
117 private boolean fixlast = true;
118
119 private File srcDir;
120 private File destDir = null;
121
122 private FileUtils fileUtils = FileUtils.newFileUtils();
123
124 /**
125 * Encoding to assume for the files
126 */
127 private String encoding = null;
128
129 /**
130 * Defaults the properties based on the system type.
131 * <ul><li>Unix: eol="LF" tab="asis" eof="remove"
132 * <li>Mac: eol="CR" tab="asis" eof="remove"
133 * <li>DOS: eol="CRLF" tab="asis" eof="asis"</ul>
134 */
135 public FixCRLF () {
136 tabs = ASIS;
137 if (Os.isFamily("mac")) {
138 ctrlz = REMOVE;
139 eol = CR;
140 eolstr = "\r";
141 } else if (Os.isFamily("dos")) {
142 ctrlz = ASIS;
143 eol = CRLF;
144 eolstr = "\r\n";
145 } else {
146 ctrlz = REMOVE;
147 eol = LF;
148 eolstr = "\n";
149 }
150 }
151
152 /**
153 * Set the source dir to find the source text files.
154 */
155 public void setSrcdir(File srcDir) {
156 this.srcDir = srcDir;
157 }
158
159 /**
160 * Set the destination where the fixed files should be placed.
161 * Default is to replace the original file.
162 */
163 public void setDestdir(File destDir) {
164 this.destDir = destDir;
165 }
166
167 /**
168 * Set to true if modifying Java source files.
169 */
170 public void setJavafiles(boolean javafiles) {
171 this.javafiles = javafiles;
172 }
173
174
175 /**
176 * Specify how EndOfLine characters are to be handled.
177 *
178 * @param attr valid values:
179 * <ul>
180 * <li>asis: leave line endings alone
181 * <li>cr: convert line endings to CR
182 * <li>lf: convert line endings to LF
183 * <li>crlf: convert line endings to CRLF
184 * </ul>
185 */
186 public void setEol(CrLf attr) {
187 String option = attr.getValue();
188 if (option.equals("asis")) {
189 eol = ASIS;
190 } else if (option.equals("cr") || option.equals("mac")) {
191 eol = CR;
192 eolstr = "\r";
193 } else if (option.equals("lf") || option.equals("unix")) {
194 eol = LF;
195 eolstr = "\n";
196 } else {
197 // Must be "crlf"
198 eol = CRLF;
199 eolstr = "\r\n";
200 }
201 }
202
203 /**
204 * Specify how carriage return (CR) characters are to be handled.
205 *
206 * @param attr valid values:
207 * <ul>
208 * <li>add: ensure that there is a CR before every LF
209 * <li>asis: leave CR characters alone
210 * <li>remove: remove all CR characters
211 * </ul>
212 *
213 * @deprecated use {@link #setEol setEol} instead.
214 */
215 public void setCr(AddAsisRemove attr) {
216 log("DEPRECATED: The cr attribute has been deprecated,",
217 Project.MSG_WARN);
218 log("Please use the eol attribute instead", Project.MSG_WARN);
219 String option = attr.getValue();
220 CrLf c = new CrLf();
221 if (option.equals("remove")) {
222 c.setValue("lf");
223 } else if (option.equals("asis")) {
224 c.setValue("asis");
225 } else {
226 // must be "add"
227 c.setValue("crlf");
228 }
229 setEol(c);
230 }
231
232 /**
233 * Specify how tab characters are to be handled.
234 *
235 * @param attr valid values:
236 * <ul>
237 * <li>add: convert sequences of spaces which span a tab stop to tabs
238 * <li>asis: leave tab and space characters alone
239 * <li>remove: convert tabs to spaces
240 * </ul>
241 */
242 public void setTab(AddAsisRemove attr) {
243 String option = attr.getValue();
244 if (option.equals("remove")) {
245 tabs = SPACES;
246 } else if (option.equals("asis")) {
247 tabs = ASIS;
248 } else {
249 // must be "add"
250 tabs = TABS;
251 }
252 }
253
254 /**
255 * Specify tab length in characters.
256 *
257 * @param tlength specify the length of tab in spaces,
258 */
259 public void setTablength(int tlength) throws BuildException {
260 if (tlength < 2 || tlength > 80) {
261 throw new BuildException("tablength must be between 2 and 80",
262 getLocation());
263 }
264 tablength = tlength;
265 StringBuffer sp = new StringBuffer();
266 for (int i = 0; i < tablength; i++) {
267 sp.append(' ');
268 }
269 spaces = sp.toString();
270 }
271
272 /**
273 * Specify how DOS EOF (control-z) characters are to be handled.
274 *
275 * @param attr valid values:
276 * <ul>
277 * <li>add: ensure that there is an eof at the end of the file
278 * <li>asis: leave eof characters alone
279 * <li>remove: remove any eof character found at the end
280 * </ul>
281 */
282 public void setEof(AddAsisRemove attr) {
283 String option = attr.getValue();
284 if (option.equals("remove")) {
285 ctrlz = REMOVE;
286 } else if (option.equals("asis")) {
287 ctrlz = ASIS;
288 } else {
289 // must be "add"
290 ctrlz = ADD;
291 }
292 }
293
294 /**
295 * Specifies the encoding Ant expects the files to be in -
296 * defaults to the platforms default encoding.
297 */
298 public void setEncoding(String encoding) {
299 this.encoding = encoding;
300 }
301
302 /**
303 * Specify whether a missing EOL will be added
304 * to the final line of a file.
305 */
306 public void setFixlast(boolean fixlast) {
307 this.fixlast = fixlast;
308 }
309
310 /**
311 * Executes the task.
312 */
313 public void execute() throws BuildException {
314 // first off, make sure that we've got a srcdir and destdir
315
316 if (srcDir == null) {
317 throw new BuildException("srcdir attribute must be set!");
318 }
319 if (!srcDir.exists()) {
320 throw new BuildException("srcdir does not exist!");
321 }
322 if (!srcDir.isDirectory()) {
323 throw new BuildException("srcdir is not a directory!");
324 }
325 if (destDir != null) {
326 if (!destDir.exists()) {
327 throw new BuildException("destdir does not exist!");
328 }
329 if (!destDir.isDirectory()) {
330 throw new BuildException("destdir is not a directory!");
331 }
332 }
333
334 // log options used
335 log("options:"
336 + " eol="
337 + (eol == ASIS ? "asis" : eol == CR ? "cr" : eol == LF ? "lf" : "crlf")
338 + " tab=" + (tabs == TABS ? "add" : tabs == ASIS ? "asis" : "remove")
339 + " eof=" + (ctrlz == ADD ? "add" : ctrlz == ASIS ? "asis" : "remove")
340 + " tablength=" + tablength
341 + " encoding=" + (encoding == null ? "default" : encoding),
342 Project.MSG_VERBOSE);
343
344 DirectoryScanner ds = super.getDirectoryScanner(srcDir);
345 String[] files = ds.getIncludedFiles();
346
347 for (int i = 0; i < files.length; i++) {
348 processFile(files[i]);
349 }
350 }
351
352 /**
353 * Creates a Reader reading from a given file an taking the user
354 * defined encoding into account.
355 */
356 private Reader getReader(File f) throws IOException {
357 return (encoding == null) ? new FileReader(f)
358 : new InputStreamReader(new FileInputStream(f), encoding);
359 }
360
361
362 private void processFile(String file) throws BuildException {
363 File srcFile = new File(srcDir, file);
364 File destD = destDir == null ? srcDir : destDir;
365 File tmpFile = null;
366 BufferedWriter outWriter;
367 OneLiner.BufferLine line;
368
369 // read the contents of the file
370 OneLiner lines = new OneLiner(srcFile);
371
372 try {
373 // Set up the output Writer
374 try {
375 tmpFile = fileUtils.createTempFile("fixcrlf", "", null);
376 tmpFile.deleteOnExit();
377 Writer writer = (encoding == null) ? new FileWriter(tmpFile)
378 : new OutputStreamWriter(new FileOutputStream(tmpFile),
379 encoding);
380 outWriter = new BufferedWriter(writer);
381 } catch (IOException e) {
382 throw new BuildException(e);
383 }
384
385 while (lines.hasMoreElements()) {
386 // In-line states
387 int endComment;
388
389 try {
390 line = (OneLiner.BufferLine) lines.nextElement();
391 } catch (NoSuchElementException e) {
392 throw new BuildException(e);
393 }
394
395 String lineString = line.getLineString();
396 int linelen = line.length();
397
398 // Note - all of the following processing NOT done for
399 // tabs ASIS
400
401 if (tabs == ASIS) {
402 // Just copy the body of the line across
403 try {
404 outWriter.write(lineString);
405 } catch (IOException e) {
406 throw new BuildException(e);
407 } // end of try-catch
408
409 } else { // (tabs != ASIS)
410
411 while (line.getNext() < linelen) {
412
413 switch (lines.getState()) {
414
415 case NOTJAVA:
416 notInConstant(line, line.length(), outWriter);
417 break;
418
419 case IN_MULTI_COMMENT:
420 endComment
421 = lineString.indexOf("*/", line.getNext());
422 if (endComment >= 0) {
423 // End of multiLineComment on this line
424 endComment += 2; // Include the end token
425 lines.setState(LOOKING);
426 } else {
427 endComment = linelen;
428 }
429
430 notInConstant(line, endComment, outWriter);
431 break;
432
433 case IN_SINGLE_COMMENT:
434 notInConstant(line, line.length(), outWriter);
435 lines.setState(LOOKING);
436 break;
437
438 case IN_CHAR_CONST:
439 case IN_STR_CONST:
440 // Got here from LOOKING by finding an
441 // opening "\'" next points to that quote
442 // character.
443 // Find the end of the constant. Watch
444 // out for backslashes. Literal tabs are
445 // left unchanged, and the column is
446 // adjusted accordingly.
447
448 int begin = line.getNext();
449 char terminator = (lines.getState() == IN_STR_CONST
450 ? '\"'
451 : '\'');
452 endOfCharConst(line, terminator);
453 while (line.getNext() < line.getLookahead()) {
454 if (line.getNextCharInc() == '\t') {
455 line.setColumn(line.getColumn()
456 + tablength
457 - (line.getColumn() % tablength));
458 } else {
459 line.incColumn();
460 }
461 }
462
463 // Now output the substring
464 try {
465 outWriter.write(line.substring(begin,
466 line.getNext()));
467 } catch (IOException e) {
468 throw new BuildException(e);
469 }
470
471 lines.setState(LOOKING);
472
473 break;
474
475
476 case LOOKING:
477 nextStateChange(line);
478 notInConstant(line, line.getLookahead(), outWriter);
479 break;
480
481 } // end of switch (state)
482
483 } // end of while (line.getNext() < linelen)
484
485 } // end of else (tabs != ASIS)
486
487 if (!("".equals(line.getEol())) || fixlast) {
488 try {
489 outWriter.write(eolstr);
490 } catch (IOException e) {
491 throw new BuildException(e);
492 } // end of try-catch
493 } //end if non-blank original eol or fixlast
494
495 } // end of while (lines.hasNext())
496
497 try {
498 // Handle CTRLZ
499 if (ctrlz == ASIS) {
500 outWriter.write(lines.getEofStr());
501 } else if (ctrlz == ADD) {
502 outWriter.write(CTRLZ);
503 }
504 } catch (IOException e) {
505 throw new BuildException(e);
506 } finally {
507 try {
508 outWriter.close();
509 } catch (IOException e) {
510 throw new BuildException(e);
511 }
512 }
513
514
515 try {
516 lines.close();
517 lines = null;
518 } catch (IOException e) {
519 throw new BuildException("Unable to close source file "
520 + srcFile);
521 }
522
523 File destFile = new File(destD, file);
524
525 boolean destIsWrong = true;
526 if (destFile.exists()) {
527 // Compare the destination with the temp file
528 log("destFile exists", Project.MSG_DEBUG);
529 if (!fileUtils.contentEquals(destFile, tmpFile)) {
530 log(destFile + " is being written", Project.MSG_DEBUG);
531 } else {
532 log(destFile + " is not written, as the contents "
533 + "are identical", Project.MSG_DEBUG);
534 destIsWrong = false;
535 }
536 }
537
538 if (destIsWrong) {
539 fileUtils.rename(tmpFile, destFile);
540 tmpFile = null;
541 }
542
543 } catch (IOException e) {
544 throw new BuildException(e);
545 } finally {
546 try {
547 if (lines != null) {
548 lines.close();
549 }
550 } catch (IOException io) {
551 log("Error closing " + srcFile, Project.MSG_ERR);
552 } // end of catch
553
554 if (tmpFile != null) {
555 tmpFile.delete();
556 }
557 } // end of finally
558 }
559
560 /**
561 * Scan a BufferLine for the next state changing token: the beginning
562 * of a single or multi-line comment, a character or a string constant.
563 *
564 * As a side-effect, sets the buffer state to the next state, and sets
565 * field lookahead to the first character of the state-changing token, or
566 * to the next eol character.
567 *
568 * @param bufline BufferLine containing the string
569 * to be processed
570 * @exception org.apache.tools.ant.BuildException
571 * Thrown when end of line is reached
572 * before the terminator is found.
573 */
574 private void nextStateChange(OneLiner.BufferLine bufline)
575 throws BuildException {
576 int eol = bufline.length();
577 int ptr = bufline.getNext();
578
579
580 // Look for next single or double quote, double slash or slash star
581 while (ptr < eol) {
582 switch (bufline.getChar(ptr++)) {
583 case '\'':
584 bufline.setState(IN_CHAR_CONST);
585 bufline.setLookahead(--ptr);
586 return;
587 case '\"':
588 bufline.setState(IN_STR_CONST);
589 bufline.setLookahead(--ptr);
590 return;
591 case '/':
592 if (ptr < eol) {
593 if (bufline.getChar(ptr) == '*') {
594 bufline.setState(IN_MULTI_COMMENT);
595 bufline.setLookahead(--ptr);
596 return;
597 } else if (bufline.getChar(ptr) == '/') {
598 bufline.setState(IN_SINGLE_COMMENT);
599 bufline.setLookahead(--ptr);
600 return;
601 }
602 }
603 break;
604 } // end of switch (bufline.getChar(ptr++))
605
606 } // end of while (ptr < eol)
607 // Eol is the next token
608 bufline.setLookahead(ptr);
609 }
610
611
612 /**
613 * Scan a BufferLine forward from the 'next' pointer
614 * for the end of a character constant. Set 'lookahead' pointer to the
615 * character following the terminating quote.
616 *
617 * @param bufline BufferLine containing the string
618 * to be processed
619 * @param terminator The constant terminator
620 *
621 * @exception org.apache.tools.ant.BuildException
622 * Thrown when end of line is reached
623 * before the terminator is found.
624 */
625 private void endOfCharConst(OneLiner.BufferLine bufline, char terminator)
626 throws BuildException {
627 int ptr = bufline.getNext();
628 int eol = bufline.length();
629 char c;
630 ptr++; // skip past initial quote
631 while (ptr < eol) {
632 if ((c = bufline.getChar(ptr++)) == '\\') {
633 ptr++;
634 } else {
635 if (c == terminator) {
636 bufline.setLookahead(ptr);
637 return;
638 }
639 }
640 } // end of while (ptr < eol)
641 // Must have fallen through to the end of the line
642 throw new BuildException("endOfCharConst: unterminated char constant");
643 }
644
645
646 /**
647 * Process a BufferLine string which is not part of a string constant.
648 * The start position of the string is given by the 'next' field.
649 * Sets the 'next' and 'column' fields in the BufferLine.
650 *
651 * @param bufline BufferLine containing the string
652 * to be processed
653 * @param end Index just past the end of the
654 * string
655 * @param outWriter Sink for the processed string
656 */
657 private void notInConstant(OneLiner.BufferLine bufline, int end,
658 BufferedWriter outWriter) {
659 // N.B. both column and string index are zero-based
660 // Process a string not part of a constant;
661 // i.e. convert tabs<->spaces as required
662 // This is NOT called for ASIS tab handling
663 int nextTab;
664 int nextStop;
665 int tabspaces;
666 String line = bufline.substring(bufline.getNext(), end);
667 int place = 0; // Zero-based
668 int col = bufline.getColumn(); // Zero-based
669
670 // process sequences of white space
671 // first convert all tabs to spaces
672 linebuf = new StringBuffer();
673 while ((nextTab = line.indexOf((int) '\t', place)) >= 0) {
674 linebuf.append(line.substring(place, nextTab)); // copy to the TAB
675 col += nextTab - place;
676 tabspaces = tablength - (col % tablength);
677 linebuf.append(spaces.substring(0, tabspaces));
678 col += tabspaces;
679 place = nextTab + 1;
680 } // end of while
681 linebuf.append(line.substring(place, line.length()));
682 // if converting to spaces, all finished
683 String linestring = new String(linebuf.substring(0));
684 if (tabs == REMOVE) {
685 try {
686 outWriter.write(linestring);
687 } catch (IOException e) {
688 throw new BuildException(e);
689 } // end of try-catch
690 } else { // tabs == ADD
691 int tabCol;
692 linebuf2 = new StringBuffer();
693 place = 0;
694 col = bufline.getColumn();
695 int placediff = col - 0;
696 // for the length of the string, cycle through the tab stop
697 // positions, checking for a space preceded by at least one
698 // other space at the tab stop. if so replace the longest possible
699 // preceding sequence of spaces with a tab.
700 nextStop = col + (tablength - col % tablength);
701 if (nextStop - col < 2) {
702 linebuf2.append(linestring.substring(
703 place, nextStop - placediff));
704 place = nextStop - placediff;
705 nextStop += tablength;
706 }
707
708 for (; nextStop - placediff <= linestring.length();
709 nextStop += tablength) {
710 for (tabCol = nextStop;
711 --tabCol - placediff >= place
712 && linestring.charAt(tabCol - placediff) == ' ';) {
713 ; // Loop for the side-effects
714 }
715 // tabCol is column index of the last non-space character
716 // before the next tab stop
717 if (nextStop - tabCol > 2) {
718 linebuf2.append(linestring.substring(
719 place, ++tabCol - placediff));
720 linebuf2.append('\t');
721 } else {
722 linebuf2.append(linestring.substring(
723 place, nextStop - placediff));
724 } // end of else
725
726 place = nextStop - placediff;
727 } // end of for (nextStop ... )
728
729 // pick up that last bit, if any
730 linebuf2.append(linestring.substring(place, linestring.length()));
731
732 try {
733 outWriter.write(linebuf2.substring(0));
734 } catch (IOException e) {
735 throw new BuildException(e);
736 } // end of try-catch
737
738 } // end of else tabs == ADD
739
740 // Set column position as modified by this method
741 bufline.setColumn(bufline.getColumn() + linestring.length());
742 bufline.setNext(end);
743
744 }
745
746
747 class OneLiner implements Enumeration {
748
749 private int state = javafiles ? LOOKING : NOTJAVA;
750
751 private StringBuffer eolStr = new StringBuffer(LINEBUFLEN);
752 private StringBuffer eofStr = new StringBuffer();
753
754 private BufferedReader reader;
755 private StringBuffer line = new StringBuffer();
756 private boolean reachedEof = false;
757 private File srcFile;
758
759 public OneLiner(File srcFile)
760 throws BuildException {
761 this.srcFile = srcFile;
762 try {
763 reader = new BufferedReader
764 (getReader(srcFile), INBUFLEN);
765 nextLine();
766 } catch (IOException e) {
767 throw new BuildException(srcFile + ": " + e.getMessage(),
768 e, getLocation());
769 }
770 }
771
772 protected void nextLine()
773 throws BuildException {
774 int ch = -1;
775 int eolcount = 0;
776
777 eolStr = new StringBuffer();
778 line = new StringBuffer();
779
780 try {
781 ch = reader.read();
782 while (ch != -1 && ch != '\r' && ch != '\n') {
783 line.append((char) ch);
784 ch = reader.read();
785 }
786
787 if (ch == -1 && line.length() == 0) {
788 // Eof has been reached
789 reachedEof = true;
790 return;
791 }
792
793 switch ((char) ch) {
794 case '\r':
795 // Check for \r, \r\n and \r\r\n
796 // Regard \r\r not followed by \n as two lines
797 ++eolcount;
798 eolStr.append('\r');
799 reader.mark(2);
800 switch ((ch = reader.read())) {
801 case '\r':
802 if ((char) (ch = reader.read()) == '\n') {
803 eolcount += 2;
804 eolStr.append("\r\n");
805 } else {
806 reader.reset();
807 }
808 break;
809 case '\n':
810 ++eolcount;
811 eolStr.append('\n');
812 break;
813 case -1:
814 // don't reposition when we've reached the end
815 // of the stream
816 break;
817 default:
818 reader.reset();
819 break;
820 } // end of switch ((char)(ch = reader.read()))
821 break;
822
823 case '\n':
824 ++eolcount;
825 eolStr.append('\n');
826 break;
827
828 } // end of switch ((char) ch)
829
830 // if at eolcount == 0 and trailing characters of string
831 // are CTRL-Zs, set eofStr
832 if (eolcount == 0) {
833 int i = line.length();
834 while (--i >= 0 && line.charAt(i) == CTRLZ) {
835 // keep searching for the first ^Z
836 }
837 if (i < line.length() - 1) {
838 // Trailing characters are ^Zs
839 // Construct new line and eofStr
840 eofStr.append(line.toString().substring(i + 1));
841 if (i < 0) {
842 line.setLength(0);
843 reachedEof = true;
844 } else {
845 line.setLength(i + 1);
846 }
847 }
848
849 } // end of if (eolcount == 0)
850
851 } catch (IOException e) {
852 throw new BuildException(srcFile + ": " + e.getMessage(),
853 e, getLocation());
854 }
855 }
856
857 public String getEofStr() {
858 return eofStr.substring(0);
859 }
860
861 public int getState() {
862 return state;
863 }
864
865 public void setState(int state) {
866 this.state = state;
867 }
868
869 public boolean hasMoreElements() {
870 return !reachedEof;
871 }
872
873 public Object nextElement()
874 throws NoSuchElementException {
875 if (!hasMoreElements()) {
876 throw new NoSuchElementException("OneLiner");
877 }
878 BufferLine tmpLine =
879 new BufferLine(line.toString(), eolStr.substring(0));
880 nextLine();
881 return tmpLine;
882 }
883
884 public void close() throws IOException {
885 if (reader != null) {
886 reader.close();
887 }
888 }
889
890 class BufferLine {
891 private int next = 0;
892 private int column = 0;
893 private int lookahead = UNDEF;
894 private String line;
895 private String eolStr;
896
897 public BufferLine(String line, String eolStr)
898 throws BuildException {
899 next = 0;
900 column = 0;
901 this.line = line;
902 this.eolStr = eolStr;
903 }
904
905 public int getNext() {
906 return next;
907 }
908
909 public void setNext(int next) {
910 this.next = next;
911 }
912
913 public int getLookahead() {
914 return lookahead;
915 }
916
917 public void setLookahead(int lookahead) {
918 this.lookahead = lookahead;
919 }
920
921 public char getChar(int i) {
922 return line.charAt(i);
923 }
924
925 public char getNextChar() {
926 return getChar(next);
927 }
928
929 public char getNextCharInc() {
930 return getChar(next++);
931 }
932
933 public int getColumn() {
934 return column;
935 }
936
937 public void setColumn(int col) {
938 column = col;
939 }
940
941 public int incColumn() {
942 return column++;
943 }
944
945 public int length() {
946 return line.length();
947 }
948
949 public int getEolLength() {
950 return eolStr.length();
951 }
952
953 public String getLineString() {
954 return line;
955 }
956
957 public String getEol() {
958 return eolStr;
959 }
960
961 public String substring(int begin) {
962 return line.substring(begin);
963 }
964
965 public String substring(int begin, int end) {
966 return line.substring(begin, end);
967 }
968
969 public void setState(int state) {
970 OneLiner.this.setState(state);
971 }
972
973 public int getState() {
974 return OneLiner.this.getState();
975 }
976 }
977 }
978
979 /**
980 * Enumerated attribute with the values "asis", "add" and "remove".
981 */
982 public static class AddAsisRemove extends EnumeratedAttribute {
983 public String[] getValues() {
984 return new String[] {"add", "asis", "remove"};
985 }
986 }
987
988 /**
989 * Enumerated attribute with the values "asis", "cr", "lf" and "crlf".
990 */
991 public static class CrLf extends EnumeratedAttribute {
992 /**
993 * @see EnumeratedAttribute#getValues
994 */
995 public String[] getValues() {
996 return new String[] {"asis", "cr", "lf", "crlf",
997 "mac", "unix", "dos"};
998 }
999 }
1000
1001}
Note: See TracBrowser for help on using the repository browser.