source: release-kits/lirk3/resources/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/filters/TokenFilter.java@ 14982

Last change on this file since 14982 was 14982, checked in by oranfry, 16 years ago

initial import of LiRK3

File size: 26.9 KB
Line 
1/*
2 * Copyright 2003-2004 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 */
17package org.apache.tools.ant.filters;
18
19import java.io.IOException;
20import java.io.Reader;
21import java.util.Vector;
22import java.util.Enumeration;
23import org.apache.tools.ant.BuildException;
24import org.apache.tools.ant.Project;
25import org.apache.tools.ant.ProjectComponent;
26import org.apache.tools.ant.types.RegularExpression;
27import org.apache.tools.ant.types.Substitution;
28import org.apache.tools.ant.util.FileUtils;
29import org.apache.tools.ant.util.Tokenizer;
30import org.apache.tools.ant.util.LineTokenizer;
31import org.apache.tools.ant.util.regexp.Regexp;
32
33/**
34 * This splits up input into tokens and passes
35 * the tokens to a sequence of filters.
36 *
37 * @since Ant 1.6
38 * @see BaseFilterReader
39 * @see ChainableReader
40 * @see org.apache.tools.ant.DynamicConfigurator
41 */
42public class TokenFilter extends BaseFilterReader
43 implements ChainableReader {
44 /**
45 * string filters implement this interface
46 */
47 public interface Filter {
48 /**
49 * filter and/of modify a string
50 *
51 * @param string the string to filter
52 * @return the modified string or null if the
53 * string did not pass the filter
54 */
55 String filter(String string);
56 }
57
58
59 /** string filters */
60 private Vector filters = new Vector();
61 /** the tokenizer to use on the input stream */
62 private Tokenizer tokenizer = null;
63 /** the output token termination */
64 private String delimOutput = null;
65 /** the current string token from the input stream */
66 private String line = null;
67 /** the position in the current string token */
68 private int linePos = 0;
69
70 /**
71 * Constructor for "dummy" instances.
72 *
73 * @see BaseFilterReader#BaseFilterReader()
74 */
75 public TokenFilter() {
76 super();
77 }
78
79 /**
80 * Creates a new filtered reader.
81 *
82 * @param in A Reader object providing the underlying stream.
83 * Must not be <code>null</code>.
84 */
85 public TokenFilter(final Reader in) {
86 super(in);
87 }
88
89
90 /**
91 * Returns the next character in the filtered stream, only including
92 * lines from the original stream which match all of the specified
93 * regular expressions.
94 *
95 * @return the next character in the resulting stream, or -1
96 * if the end of the resulting stream has been reached
97 *
98 * @exception IOException if the underlying stream throws an IOException
99 * during reading
100 */
101
102 public int read() throws IOException {
103 if (tokenizer == null) {
104 tokenizer = new LineTokenizer();
105 }
106 while (line == null || line.length() == 0) {
107 line = tokenizer.getToken(in);
108 if (line == null) {
109 return -1;
110 }
111 for (Enumeration e = filters.elements(); e.hasMoreElements();) {
112 Filter filter = (Filter) e.nextElement();
113 line = filter.filter(line);
114 if (line == null) {
115 break;
116 }
117 }
118 linePos = 0;
119 if (line != null) {
120 if (tokenizer.getPostToken().length() != 0) {
121 if (delimOutput != null) {
122 line = line + delimOutput;
123 } else {
124 line = line + tokenizer.getPostToken();
125 }
126 }
127 }
128 }
129 int ch = line.charAt(linePos);
130 linePos++;
131 if (linePos == line.length()) {
132 line = null;
133 }
134 return ch;
135 }
136
137 /**
138 * Creates a new TokenFilter using the passed in
139 * Reader for instantiation.
140 *
141 * @param reader A Reader object providing the underlying stream.
142 *
143 * @return a new filter based on this configuration
144 */
145
146 public final Reader chain(final Reader reader) {
147 TokenFilter newFilter = new TokenFilter(reader);
148 newFilter.filters = filters;
149 newFilter.tokenizer = tokenizer;
150 newFilter.delimOutput = delimOutput;
151 newFilter.setProject(getProject());
152 return newFilter;
153 }
154
155 /**
156 * set the output delimiter.
157 * @param delimOutput replaces the delim string returned by the
158 * tokenizer, if present.
159 */
160
161 public void setDelimOutput(String delimOutput) {
162 this.delimOutput = resolveBackSlash(delimOutput);
163 }
164
165 // -----------------------------------------
166 // Predefined tokenizers
167 // -----------------------------------------
168
169 /**
170 * add a line tokenizer - this is the default.
171 * @param tokenizer the line tokenizer
172 */
173
174 public void addLineTokenizer(LineTokenizer tokenizer) {
175 add(tokenizer);
176 }
177
178 /**
179 * add a string tokenizer
180 * @param tokenizer the string tokenizer
181 */
182
183 public void addStringTokenizer(StringTokenizer tokenizer) {
184 add(tokenizer);
185 }
186
187 /**
188 * add a file tokenizer
189 * @param tokenizer the file tokenizer
190 */
191 public void addFileTokenizer(FileTokenizer tokenizer) {
192 add(tokenizer);
193 }
194
195 /**
196 * add an arbitrary tokenizer
197 * @param tokenizer the tokenizer to all, only one allowed
198 */
199
200 public void add(Tokenizer tokenizer) {
201 if (this.tokenizer != null) {
202 throw new BuildException("Only one tokenizer allowed");
203 }
204 this.tokenizer = tokenizer;
205 }
206
207 // -----------------------------------------
208 // Predefined filters
209 // -----------------------------------------
210
211 /**
212 * replace string filter
213 * @param filter the replace string filter
214 */
215 public void addReplaceString(ReplaceString filter) {
216 filters.addElement(filter);
217 }
218
219 /**
220 * contains string filter
221 * @param filter the contains string filter
222 */
223 public void addContainsString(ContainsString filter) {
224 filters.addElement(filter);
225 }
226
227 /**
228 * replace regex filter
229 * @param filter the replace regex filter
230 */
231 public void addReplaceRegex(ReplaceRegex filter) {
232 filters.addElement(filter);
233 }
234
235 /**
236 * contains regex filter
237 * @param filter the contains regex filter
238 */
239 public void addContainsRegex(ContainsRegex filter) {
240 filters.addElement(filter);
241 }
242
243 /**
244 * trim filter
245 * @param filter the trim filter
246 */
247 public void addTrim(Trim filter) {
248 filters.addElement(filter);
249 }
250
251 /**
252 * ignore blank filter
253 * @param filter the ignore blank filter
254 */
255 public void addIgnoreBlank(IgnoreBlank filter) {
256 filters.addElement(filter);
257 }
258
259 /**
260 * delete chars
261 * @param filter the delete characters filter
262 */
263 public void addDeleteCharacters(DeleteCharacters filter) {
264 filters.addElement(filter);
265 }
266
267 /**
268 * Add an arbitrary filter
269 * @param filter the filter to add
270 */
271 public void add(Filter filter) {
272 filters.addElement(filter);
273 }
274
275
276 // --------------------------------------------
277 //
278 // Tokenizer Classes
279 //
280 // --------------------------------------------
281
282 /**
283 * class to read the complete input into a string
284 */
285 public static class FileTokenizer extends ProjectComponent
286 implements Tokenizer {
287 /**
288 * Get the complete input as a string
289 * @param in the reader object
290 * @return the complete input
291 * @throws IOException if error reading
292 */
293 public String getToken(Reader in) throws IOException {
294 return FileUtils.readFully(in);
295 }
296
297 /**
298 * Return the intra-token string
299 * @return an empty string always
300 */
301 public String getPostToken() {
302 return "";
303 }
304 }
305
306 /**
307 * class to tokenize the input as areas separated
308 * by white space, or by a specified list of
309 * delim characters. Behaves like java.util.StringTokenizer.
310 * if the stream starts with delim characters, the first
311 * token will be an empty string (unless the treat tokens
312 * as delims flag is set).
313 */
314 public static class StringTokenizer extends ProjectComponent
315 implements Tokenizer {
316 private String intraString = "";
317 private int pushed = -2;
318 private char[] delims = null;
319 private boolean delimsAreTokens = false;
320 private boolean suppressDelims = false;
321 private boolean includeDelims = false;
322
323 /**
324 * attribute delims - the delimiter characters
325 * @param delims a string containing the delimiter characters
326 */
327 public void setDelims(String delims) {
328 this.delims = resolveBackSlash(delims).toCharArray();
329 }
330
331 /**
332 * attribute delimsaretokens - treat delimiters as
333 * separate tokens.
334 * @param delimsAreTokens true if delimiters are to be separate
335 */
336
337 public void setDelimsAreTokens(boolean delimsAreTokens) {
338 this.delimsAreTokens = delimsAreTokens;
339 }
340 /**
341 * attribute suppressdelims - suppress delimiters.
342 * default - false
343 * @param suppressDelims if true do not report delimiters
344 */
345 public void setSuppressDelims(boolean suppressDelims) {
346 this.suppressDelims = suppressDelims;
347 }
348
349 /**
350 * attribute includedelims - treat delimiters as part
351 * of the token.
352 * default - false
353 * @param includeDelims if true add delimiters to the token
354 */
355 public void setIncludeDelims(boolean includeDelims) {
356 this.includeDelims = includeDelims;
357 }
358
359 /**
360 * find and return the next token
361 *
362 * @param in the input stream
363 * @return the token
364 * @exception IOException if an error occurs reading
365 */
366 public String getToken(Reader in) throws IOException {
367 int ch = -1;
368 if (pushed != -2) {
369 ch = pushed;
370 pushed = -2;
371 } else {
372 ch = in.read();
373 }
374 if (ch == -1) {
375 return null;
376 }
377 boolean inToken = true;
378 intraString = "";
379 StringBuffer word = new StringBuffer();
380 StringBuffer padding = new StringBuffer();
381 while (ch != -1) {
382 char c = (char) ch;
383 boolean isDelim = isDelim(c);
384 if (inToken) {
385 if (isDelim) {
386 if (delimsAreTokens) {
387 if (word.length() == 0) {
388 word.append(c);
389 } else {
390 pushed = ch;
391 }
392 break;
393 }
394 padding.append(c);
395 inToken = false;
396 } else {
397 word.append(c);
398 }
399 } else {
400 if (isDelim) {
401 padding.append(c);
402 } else {
403 pushed = ch;
404 break;
405 }
406 }
407 ch = in.read();
408 }
409 intraString = padding.toString();
410 if (includeDelims) {
411 word.append(intraString);
412 }
413 return word.toString();
414 }
415
416 /**
417 * @return the intratoken string
418 */
419 public String getPostToken() {
420 if (suppressDelims || includeDelims) {
421 return "";
422 }
423 return intraString;
424 }
425
426 private boolean isDelim(char ch) {
427 if (delims == null) {
428 return Character.isWhitespace(ch);
429 }
430 for (int i = 0; i < delims.length; ++i) {
431 if (delims[i] == ch) {
432 return true;
433 }
434 }
435 return false;
436 }
437 }
438
439 // --------------------------------------------
440 //
441 // Filter classes
442 //
443 // --------------------------------------------
444
445 /**
446 * Abstract class that converts derived filter classes into
447 * ChainableReaderFilter's
448 */
449 public abstract static class ChainableReaderFilter extends ProjectComponent
450 implements ChainableReader, Filter {
451 private boolean byLine = true;
452
453 /**
454 * set whether to use filetokenizer or line tokenizer
455 * @param byLine if true use a linetokenizer (default) otherwise
456 * use a filetokenizer
457 */
458 public void setByLine(boolean byLine) {
459 this.byLine = byLine;
460 }
461
462 /**
463 * Chain a tokenfilter reader to a reader,
464 *
465 * @param reader the input reader object
466 * @return the chained reader object
467 */
468 public Reader chain(Reader reader) {
469 TokenFilter tokenFilter = new TokenFilter(reader);
470 if (!byLine) {
471 tokenFilter.add(new FileTokenizer());
472 }
473 tokenFilter.add(this);
474 return tokenFilter;
475 }
476 }
477
478 /**
479 * Simple replace string filter.
480 */
481 public static class ReplaceString extends ChainableReaderFilter {
482 private String from;
483 private String to;
484
485 /**
486 * the from attribute
487 *
488 * @param from the string to replace
489 */
490 public void setFrom(String from) {
491 this.from = from;
492 }
493
494 /**
495 * the to attribute
496 *
497 * @param to the string to replace 'from' with
498 */
499 public void setTo(String to) {
500 this.to = to;
501 }
502
503 /**
504 * Filter a string 'line' replacing from with to
505 * (C&P from the Replace task)
506 * @param line the string to be filtered
507 * @return the filtered line
508 */
509 public String filter(String line) {
510 if (from == null) {
511 throw new BuildException("Missing from in stringreplace");
512 }
513 StringBuffer ret = new StringBuffer();
514 int start = 0;
515 int found = line.indexOf(from);
516 while (found >= 0) {
517 // write everything up to the from
518 if (found > start) {
519 ret.append(line.substring(start, found));
520 }
521
522 // write the replacement to
523 if (to != null) {
524 ret.append(to);
525 }
526
527 // search again
528 start = found + from.length();
529 found = line.indexOf(from, start);
530 }
531
532 // write the remaining characters
533 if (line.length() > start) {
534 ret.append(line.substring(start, line.length()));
535 }
536
537 return ret.toString();
538 }
539 }
540
541 /**
542 * Simple filter to filter lines contains strings
543 */
544 public static class ContainsString extends ProjectComponent
545 implements Filter {
546 private String contains;
547
548 /**
549 * the contains attribute
550 * @param contains the string that the token should contain
551 */
552 public void setContains(String contains) {
553 this.contains = contains;
554 }
555
556 /**
557 * Filter strings that contain the contains attribute
558 *
559 * @param string the string to be filtered
560 * @return null if the string does not contain "contains",
561 * string otherwise
562 */
563 public String filter(String string) {
564 if (contains == null) {
565 throw new BuildException("Missing contains in containsstring");
566 }
567 if (string.indexOf(contains) > -1) {
568 return string;
569 }
570 return null;
571 }
572 }
573
574 /**
575 * filter to replace regex.
576 */
577 public static class ReplaceRegex extends ChainableReaderFilter {
578 private String from;
579 private String to;
580 private RegularExpression regularExpression;
581 private Substitution substitution;
582 private boolean initialized = false;
583 private String flags = "";
584 private int options;
585 private Regexp regexp;
586
587 /**
588 * the from attribute
589 * @param from the regex string
590 */
591 public void setPattern(String from) {
592 this.from = from;
593 }
594 /**
595 * the to attribute
596 * @param to the replacement string
597 */
598 public void setReplace(String to) {
599 this.to = to;
600 }
601
602 /**
603 * @param flags the regex flags
604 */
605 public void setFlags(String flags) {
606 this.flags = flags;
607 }
608
609 private void initialize() {
610 if (initialized) {
611 return;
612 }
613 options = convertRegexOptions(flags);
614 if (from == null) {
615 throw new BuildException("Missing pattern in replaceregex");
616 }
617 regularExpression = new RegularExpression();
618 regularExpression.setPattern(from);
619 regexp = regularExpression.getRegexp(getProject());
620 if (to == null) {
621 to = "";
622 }
623 substitution = new Substitution();
624 substitution.setExpression(to);
625 }
626
627 /**
628 * @param line the string to modify
629 * @return the modified string
630 */
631 public String filter(String line) {
632 initialize();
633
634 if (!regexp.matches(line, options)) {
635 return line;
636 }
637 return regexp.substitute(
638 line, substitution.getExpression(getProject()), options);
639 }
640 }
641
642 /**
643 * filter to filter tokens matching regular expressions.
644 */
645 public static class ContainsRegex extends ChainableReaderFilter {
646 private String from;
647 private String to;
648 private Project project;
649 private RegularExpression regularExpression;
650 private Substitution substitution;
651 private boolean initialized = false;
652 private String flags = "";
653 private int options;
654 private Regexp regexp;
655
656
657 /**
658 * @param from the regex pattern
659 */
660 public void setPattern(String from) {
661 this.from = from;
662 }
663
664 /**
665 * @param to the replacement string
666 */
667 public void setReplace(String to) {
668 this.to = to;
669 }
670
671 /**
672 * @param flags the regex flags
673 */
674 public void setFlags(String flags) {
675 this.flags = flags;
676 }
677
678 private void initialize() {
679 if (initialized) {
680 return;
681 }
682 options = convertRegexOptions(flags);
683 if (from == null) {
684 throw new BuildException("Missing from in containsregex");
685 }
686 regularExpression = new RegularExpression();
687 regularExpression.setPattern(from);
688 regexp = regularExpression.getRegexp(project);
689 if (to == null) {
690 return;
691 }
692 substitution = new Substitution();
693 substitution.setExpression(to);
694 }
695
696 /**
697 * apply regex and substitution on a string
698 * @param string the string to apply filter on
699 * @return the filtered string
700 */
701 public String filter(String string) {
702 initialize();
703 if (!regexp.matches(string, options)) {
704 return null;
705 }
706 if (substitution == null) {
707 return string;
708 }
709 return regexp.substitute(
710 string, substitution.getExpression(getProject()), options);
711 }
712 }
713
714 /** Filter to trim white space */
715 public static class Trim extends ChainableReaderFilter {
716 /**
717 * @param line the string to be trimmed
718 * @return the trimmed string
719 */
720 public String filter(String line) {
721 return line.trim();
722 }
723 }
724
725
726
727 /** Filter remove empty tokens */
728 public static class IgnoreBlank extends ChainableReaderFilter {
729 /**
730 * @param line the line to modify
731 * @return the trimmed line
732 */
733 public String filter(String line) {
734 if (line.trim().length() == 0) {
735 return null;
736 }
737 return line;
738 }
739 }
740
741 /**
742 * Filter to delete characters
743 */
744 public static class DeleteCharacters extends ProjectComponent
745 implements Filter, ChainableReader {
746 // Attributes
747 /** the list of characters to remove from the input */
748 private String deleteChars = "";
749
750 /**
751 * Set the list of characters to delete
752 * @param deleteChars the list of characters
753 */
754 public void setChars(String deleteChars) {
755 this.deleteChars = resolveBackSlash(deleteChars);
756 }
757
758 /**
759 * remove characters from a string
760 * @param string the string to remove the characters from
761 * @return the converted string
762 */
763 public String filter(String string) {
764 StringBuffer output = new StringBuffer(string.length());
765 for (int i = 0; i < string.length(); ++i) {
766 char ch = string.charAt(i);
767 if (!(isDeleteCharacter(ch))) {
768 output.append(ch);
769 }
770 }
771 return output.toString();
772 }
773
774 /**
775 * factory method to provide a reader that removes
776 * the characters from a reader as part of a filter
777 * chain
778 * @param reader the reader object
779 * @return the chained reader object
780 */
781 public Reader chain(Reader reader) {
782 return new BaseFilterReader(reader) {
783 /**
784 * @return the next non delete character
785 */
786 public int read()
787 throws IOException {
788 while (true) {
789 int c = in.read();
790 if (c == -1) {
791 return c;
792 }
793 if (!(isDeleteCharacter((char) c))) {
794 return c;
795 }
796 }
797 }
798 };
799 }
800
801 /** check if the character c is to be deleted */
802 private boolean isDeleteCharacter(char c) {
803 for (int d = 0; d < deleteChars.length(); ++d) {
804 if (deleteChars.charAt(d) == c) {
805 return true;
806 }
807 }
808 return false;
809 }
810 }
811
812 // --------------------------------------------------------
813 // static utility methods - could be placed somewhere else
814 // --------------------------------------------------------
815
816 /**
817 * xml does not do "c" like interpretation of strings.
818 * i.e. \n\r\t etc.
819 * this method processes \n, \r, \t, \f, \\
820 * also subs \s -> " \n\r\t\f"
821 * a trailing '\' will be ignored
822 *
823 * @param input raw string with possible embedded '\'s
824 * @return converted string
825 */
826 public static String resolveBackSlash(String input) {
827 StringBuffer b = new StringBuffer();
828 boolean backSlashSeen = false;
829 for (int i = 0; i < input.length(); ++i) {
830 char c = input.charAt(i);
831 if (!backSlashSeen) {
832 if (c == '\\') {
833 backSlashSeen = true;
834 } else {
835 b.append(c);
836 }
837 } else {
838 switch (c) {
839 case '\\':
840 b.append((char) '\\');
841 break;
842 case 'n':
843 b.append((char) '\n');
844 break;
845 case 'r':
846 b.append((char) '\r');
847 break;
848 case 't':
849 b.append((char) '\t');
850 break;
851 case 'f':
852 b.append((char) '\f');
853 break;
854 case 's':
855 b.append(" \t\n\r\f");
856 break;
857 default:
858 b.append(c);
859 }
860 backSlashSeen = false;
861 }
862 }
863 return b.toString();
864 }
865
866 /**
867 * convert regex option flag characters to regex options
868 * <dl>
869 * <li>g - Regexp.REPLACE_ALL</li>
870 * <li>i - Regexp.MATCH_CASE_INSENSITIVE</li>
871 * <li>m - Regexp.MATCH_MULTILINE</li>
872 * <li>s - Regexp.MATCH_SINGLELINE</li>
873 * </dl>
874 * @param flags the string containing the flags
875 * @return the Regexp option bits
876 */
877 public static int convertRegexOptions(String flags) {
878 if (flags == null) {
879 return 0;
880 }
881 int options = 0;
882 if (flags.indexOf('g') != -1) {
883 options |= Regexp.REPLACE_ALL;
884 }
885 if (flags.indexOf('i') != -1) {
886 options |= Regexp.MATCH_CASE_INSENSITIVE;
887 }
888 if (flags.indexOf('m') != -1) {
889 options |= Regexp.MATCH_MULTILINE;
890 }
891 if (flags.indexOf('s') != -1) {
892 options |= Regexp.MATCH_SINGLELINE;
893 }
894 return options;
895 }
896}
Note: See TracBrowser for help on using the repository browser.