PR: 18849 Submitted by: jan@materne.de (Jan Mat�rne) git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274446 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -32,6 +32,9 @@ Changes that could break older environments: | |||||
| Fixed bugs: | Fixed bugs: | ||||
| ----------- | ----------- | ||||
| * A new attribute named skip is added to the TailFilter and | |||||
| HeadFilter filter readers. | |||||
| * Expand tasks did not behave as expected with PatternSets. | * Expand tasks did not behave as expected with PatternSets. | ||||
| * <property environment=... /> now works on OS/400. | * <property environment=... /> now works on OS/400. | ||||
| @@ -240,7 +240,14 @@ This filter reads the first few lines from the data supplied to it. | |||||
| <TR> | <TR> | ||||
| <TD vAlign=top>lines</TD> | <TD vAlign=top>lines</TD> | ||||
| <TD vAlign=top align="center">Number of lines to be read. | <TD vAlign=top align="center">Number of lines to be read. | ||||
| Defaults to "10"</TD> | |||||
| Defaults to "10" <BR> A negative value means that all lines are | |||||
| passed (useful with <I>skip</I>)</TD> | |||||
| <TD vAlign=top align="center">No</TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD vAlign=top>skip</TD> | |||||
| <TD vAlign=top align="center">Number of lines to be skipped (from the beginning). | |||||
| Defaults to "0"</TD> | |||||
| <TD vAlign=top align="center">No</TD> | <TD vAlign=top align="center">No</TD> | ||||
| </TR> | </TR> | ||||
| </TABLE> | </TABLE> | ||||
| @@ -267,6 +274,19 @@ Convenience method: | |||||
| </loadfile> | </loadfile> | ||||
| </PRE></BLOCKQUOTE> | </PRE></BLOCKQUOTE> | ||||
| This stores the first 15 lines, skipping the first 2 lines, of the supplied data | |||||
| in the porperty ${src.file.head}. (Means: lines 3-17) | |||||
| <BLOCKQUOTE><PRE> | |||||
| <loadfile srcfile="${src.file}" property="${src.file.head}"> | |||||
| <filterchain> | |||||
| <headfilter lines="15" skip="2"/> | |||||
| </filterchain> | |||||
| </loadfile> | |||||
| </PRE></BLOCKQUOTE> | |||||
| See the testcases for more examples (<I>src\etc\testcases\filters\head-tail.xml</I> in the | |||||
| source distribution). | |||||
| <H3><a name="linecontains">LineContains</a></H3> | <H3><a name="linecontains">LineContains</a></H3> | ||||
| This filter includes only those lines that contain all the user-specified | This filter includes only those lines that contain all the user-specified | ||||
| @@ -602,11 +622,110 @@ This filter reads the last few lines from the data supplied to it. | |||||
| <TR> | <TR> | ||||
| <TD vAlign=top>lines</TD> | <TD vAlign=top>lines</TD> | ||||
| <TD vAlign=top align="center">Number of lines to be read. | <TD vAlign=top align="center">Number of lines to be read. | ||||
| Defaults to "10"</TD> | |||||
| Defaults to "10" <BR> A negative value means that all lines are | |||||
| passed (useful with <I>skip</I>)</TD> | |||||
| <TD vAlign=top align="center">No</TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD vAlign=top>skip</TD> | |||||
| <TD vAlign=top align="center">Number of lines to be skipped (from the end). | |||||
| Defaults to "0" </TD> | |||||
| <TD vAlign=top align="center">No</TD> | <TD vAlign=top align="center">No</TD> | ||||
| </TR> | </TR> | ||||
| </TABLE> | </TABLE> | ||||
| <P> | <P> | ||||
| <H4>Background:</H4> | |||||
| With HeadFilter and TailFilter you can extract each part of a text file you want. | |||||
| This graphic shows the dependencies: | |||||
| <TABLE cellSpacing=0 cellPadding=2 border=1> | |||||
| <TR> | |||||
| <TH> Content </TH> | |||||
| <TH></TH> | |||||
| <TH></TH> | |||||
| <TH></TH> | |||||
| <TH> Filter </TH> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 1 </TD> | |||||
| <TD rowspan="2" bgcolor="#C0C0C0"> </TD> | |||||
| <TD rowspan="9" bgcolor="#FF00FF"> </TD> | |||||
| <TD rowspan="4"> </TD> | |||||
| <TD rowspan="11"> | |||||
| <TABLE> | |||||
| <TR> | |||||
| <TD bgcolor="#C0C0C0"> </TD> | |||||
| <TD><PRE><filterchain> | |||||
| <headfilter lines="2"/> | |||||
| </filterchain></PRE></TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD bgcolor="#FF00FF"> </TD> | |||||
| <TD><PRE><filterchain> | |||||
| <tailfilter lines="-1" skip="2"/> | |||||
| </filterchain></PRE></TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD bgcolor="#008000"> </TD> | |||||
| <TD><PRE><filterchain> | |||||
| <headfilter lines="-1" skip="2"/> | |||||
| </filterchain></PRE></TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD bgcolor="#0000FF"> </TD> | |||||
| <TD><PRE><filterchain> | |||||
| <headfilter lines="-1" skip="2"/> | |||||
| <tailfilter lines="-1" skip="2"/> | |||||
| </filterchain></PRE></TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD bgcolor="#00FF00"> </TD> | |||||
| <TD><PRE><filterchain> | |||||
| <tailfilter lines="2"/> | |||||
| </filterchain></PRE></TD> | |||||
| </TR> | |||||
| </TABLE> | |||||
| </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 2 </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 3 </TD> | |||||
| <TD rowspan="9" bgcolor="#008000"> </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 4 </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 5 </TD> | |||||
| <TD rowspan="3" bgcolor="#0000FF"> </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Lines ... </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 95 </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 96 </TD> | |||||
| <TD rowspan="4"> </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 97 </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 98 </TD> | |||||
| <TD rowspan="2" bgcolor="#00FF00"> </TD> | |||||
| </TR> | |||||
| <TR> | |||||
| <TD> Line 99 </TD> | |||||
| </TR> | |||||
| </TABLE> | |||||
| <H4>Examples:</H4> | <H4>Examples:</H4> | ||||
| This stores the last 15 lines of the supplied data in the property ${src.file.tail} | This stores the last 15 lines of the supplied data in the property ${src.file.tail} | ||||
| @@ -655,6 +774,18 @@ Convenience method: | |||||
| </loadfile> | </loadfile> | ||||
| </PRE></BLOCKQUOTE> | </PRE></BLOCKQUOTE> | ||||
| This stores the last 10 lines, skipping the last 2 lines, of the supplied data | |||||
| in the porperty ${src.file.head}. (Means: if supplied data contains 60 lines, | |||||
| lines 49-58 are extracted) | |||||
| <BLOCKQUOTE><PRE> | |||||
| <loadfile srcfile="${src.file}" property="${src.file.head}"> | |||||
| <filterchain> | |||||
| <tailfilter lines="10" skip="2"/> | |||||
| </filterchain> | |||||
| </loadfile> | |||||
| </PRE></BLOCKQUOTE> | |||||
| <HR> | <HR> | ||||
| <P align=center>Copyright © 2002-2003 Apache Software Foundation. All rights | <P align=center>Copyright © 2002-2003 Apache Software Foundation. All rights | ||||
| @@ -0,0 +1,10 @@ | |||||
| Line 1 | |||||
| Line 2 | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| Line 6 | |||||
| Line 7 | |||||
| Line 8 | |||||
| Line 9 | |||||
| Line 10 | |||||
| @@ -0,0 +1,58 @@ | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| Line 6 | |||||
| Line 7 | |||||
| Line 8 | |||||
| Line 9 | |||||
| Line 10 | |||||
| Line 11 | |||||
| Line 12 | |||||
| Line 13 | |||||
| Line 14 | |||||
| Line 15 | |||||
| Line 16 | |||||
| Line 17 | |||||
| Line 18 | |||||
| Line 19 | |||||
| Line 20 | |||||
| Line 21 | |||||
| Line 22 | |||||
| Line 23 | |||||
| Line 24 | |||||
| Line 25 | |||||
| Line 26 | |||||
| Line 27 | |||||
| Line 28 | |||||
| Line 29 | |||||
| Line 30 | |||||
| Line 31 | |||||
| Line 32 | |||||
| Line 33 | |||||
| Line 34 | |||||
| Line 35 | |||||
| Line 36 | |||||
| Line 37 | |||||
| Line 38 | |||||
| Line 39 | |||||
| Line 40 | |||||
| Line 41 | |||||
| Line 42 | |||||
| Line 43 | |||||
| Line 44 | |||||
| Line 45 | |||||
| Line 46 | |||||
| Line 47 | |||||
| Line 48 | |||||
| Line 49 | |||||
| Line 50 | |||||
| Line 51 | |||||
| Line 52 | |||||
| Line 53 | |||||
| Line 54 | |||||
| Line 55 | |||||
| Line 56 | |||||
| Line 57 | |||||
| Line 58 | |||||
| Line 59 | |||||
| Line 60 | |||||
| @@ -0,0 +1,2 @@ | |||||
| Line 1 | |||||
| Line 2 | |||||
| @@ -0,0 +1,2 @@ | |||||
| Line 3 | |||||
| Line 4 | |||||
| @@ -0,0 +1,10 @@ | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| Line 6 | |||||
| Line 7 | |||||
| Line 8 | |||||
| Line 9 | |||||
| Line 10 | |||||
| Line 11 | |||||
| Line 12 | |||||
| @@ -0,0 +1 @@ | |||||
| Line 4 | |||||
| @@ -0,0 +1,10 @@ | |||||
| Line 51 | |||||
| Line 52 | |||||
| Line 53 | |||||
| Line 54 | |||||
| Line 55 | |||||
| Line 56 | |||||
| Line 57 | |||||
| Line 58 | |||||
| Line 59 | |||||
| Line 60 | |||||
| @@ -0,0 +1,58 @@ | |||||
| Line 1 | |||||
| Line 2 | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| Line 6 | |||||
| Line 7 | |||||
| Line 8 | |||||
| Line 9 | |||||
| Line 10 | |||||
| Line 11 | |||||
| Line 12 | |||||
| Line 13 | |||||
| Line 14 | |||||
| Line 15 | |||||
| Line 16 | |||||
| Line 17 | |||||
| Line 18 | |||||
| Line 19 | |||||
| Line 20 | |||||
| Line 21 | |||||
| Line 22 | |||||
| Line 23 | |||||
| Line 24 | |||||
| Line 25 | |||||
| Line 26 | |||||
| Line 27 | |||||
| Line 28 | |||||
| Line 29 | |||||
| Line 30 | |||||
| Line 31 | |||||
| Line 32 | |||||
| Line 33 | |||||
| Line 34 | |||||
| Line 35 | |||||
| Line 36 | |||||
| Line 37 | |||||
| Line 38 | |||||
| Line 39 | |||||
| Line 40 | |||||
| Line 41 | |||||
| Line 42 | |||||
| Line 43 | |||||
| Line 44 | |||||
| Line 45 | |||||
| Line 46 | |||||
| Line 47 | |||||
| Line 48 | |||||
| Line 49 | |||||
| Line 50 | |||||
| Line 51 | |||||
| Line 52 | |||||
| Line 53 | |||||
| Line 54 | |||||
| Line 55 | |||||
| Line 56 | |||||
| Line 57 | |||||
| Line 58 | |||||
| @@ -0,0 +1,2 @@ | |||||
| Line 59 | |||||
| Line 60 | |||||
| @@ -0,0 +1,2 @@ | |||||
| Line 57 | |||||
| Line 58 | |||||
| @@ -0,0 +1,10 @@ | |||||
| Line 49 | |||||
| Line 50 | |||||
| Line 51 | |||||
| Line 52 | |||||
| Line 53 | |||||
| Line 54 | |||||
| Line 55 | |||||
| Line 56 | |||||
| Line 57 | |||||
| Line 58 | |||||
| @@ -0,0 +1,107 @@ | |||||
| <?xml version="1.0"?> | |||||
| <project default="cleanup" basedir="."> | |||||
| <target name="init"> | |||||
| <mkdir dir="result" /> | |||||
| </target> | |||||
| <target name="cleanup"> | |||||
| <delete dir="result"/> | |||||
| </target> | |||||
| <!-- Testcases for HeadFilter --> | |||||
| <target name="testHead" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.head.test"> | |||||
| <filterchain> | |||||
| <headfilter/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testHeadLines" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.headLines.test"> | |||||
| <filterchain> | |||||
| <headfilter lines="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testHeadSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.headSkip.test"> | |||||
| <filterchain> | |||||
| <headfilter skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testHeadLinesSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.headLinesSkip.test"> | |||||
| <filterchain> | |||||
| <headfilter lines="2" skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testHeadAllSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.headAllSkip.test"> | |||||
| <filterchain> | |||||
| <headfilter lines="-1" skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <!-- Testcases for TailFilter --> | |||||
| <target name="testTail" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.tail.test"> | |||||
| <filterchain> | |||||
| <tailfilter/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testTailLines" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.tailLines.test"> | |||||
| <filterchain> | |||||
| <tailfilter lines="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testTailSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.tailSkip.test"> | |||||
| <filterchain> | |||||
| <tailfilter skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testTailLinesSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.tailLinesSkip.test"> | |||||
| <filterchain> | |||||
| <tailfilter lines="2" skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <target name="testTailAllSkip" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.tailAllSkip.test"> | |||||
| <filterchain> | |||||
| <tailfilter lines="-1" skip="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| <!-- Testcases for combined scenarios --> | |||||
| <target name="testHeadTail" depends="init"> | |||||
| <copy file="input/head-tail.test" tofile="result/head-tail.headtail.test"> | |||||
| <filterchain> | |||||
| <headfilter lines="4"/> | |||||
| <tailfilter lines="2"/> | |||||
| </filterchain> | |||||
| </copy> | |||||
| </target> | |||||
| </project> | |||||
| @@ -0,0 +1,5 @@ | |||||
| Line 1 | |||||
| Line 2 | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| @@ -0,0 +1,60 @@ | |||||
| Line 1 | |||||
| Line 2 | |||||
| Line 3 | |||||
| Line 4 | |||||
| Line 5 | |||||
| Line 6 | |||||
| Line 7 | |||||
| Line 8 | |||||
| Line 9 | |||||
| Line 10 | |||||
| Line 11 | |||||
| Line 12 | |||||
| Line 13 | |||||
| Line 14 | |||||
| Line 15 | |||||
| Line 16 | |||||
| Line 17 | |||||
| Line 18 | |||||
| Line 19 | |||||
| Line 20 | |||||
| Line 21 | |||||
| Line 22 | |||||
| Line 23 | |||||
| Line 24 | |||||
| Line 25 | |||||
| Line 26 | |||||
| Line 27 | |||||
| Line 28 | |||||
| Line 29 | |||||
| Line 30 | |||||
| Line 31 | |||||
| Line 32 | |||||
| Line 33 | |||||
| Line 34 | |||||
| Line 35 | |||||
| Line 36 | |||||
| Line 37 | |||||
| Line 38 | |||||
| Line 39 | |||||
| Line 40 | |||||
| Line 41 | |||||
| Line 42 | |||||
| Line 43 | |||||
| Line 44 | |||||
| Line 45 | |||||
| Line 46 | |||||
| Line 47 | |||||
| Line 48 | |||||
| Line 49 | |||||
| Line 50 | |||||
| Line 51 | |||||
| Line 52 | |||||
| Line 53 | |||||
| Line 54 | |||||
| Line 55 | |||||
| Line 56 | |||||
| Line 57 | |||||
| Line 58 | |||||
| Line 59 | |||||
| Line 60 | |||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * The Apache Software License, Version 1.1 | ||||
| * | * | ||||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||||
| * Copyright (c) 2002-2003 The Apache Software Foundation. All rights | |||||
| * reserved. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| @@ -76,15 +76,21 @@ public final class HeadFilter | |||||
| /** Parameter name for the number of lines to be returned. */ | /** Parameter name for the number of lines to be returned. */ | ||||
| private static final String LINES_KEY = "lines"; | private static final String LINES_KEY = "lines"; | ||||
| /** Parameter name for the number of lines to be skipped. */ | |||||
| private static final String SKIP_KEY = "skip"; | |||||
| /** Number of lines currently read in. */ | /** Number of lines currently read in. */ | ||||
| private long linesRead = 0; | private long linesRead = 0; | ||||
| /** Number of lines to be returned in the filtered stream. */ | /** Number of lines to be returned in the filtered stream. */ | ||||
| private long lines = 10; | private long lines = 10; | ||||
| /** Number of lines to be skipped. */ | |||||
| private long skip = 0; | |||||
| /** | /** | ||||
| * Constructor for "dummy" instances. | * Constructor for "dummy" instances. | ||||
| * | |||||
| * | |||||
| * @see BaseFilterReader#BaseFilterReader() | * @see BaseFilterReader#BaseFilterReader() | ||||
| */ | */ | ||||
| public HeadFilter() { | public HeadFilter() { | ||||
| @@ -104,14 +110,14 @@ public final class HeadFilter | |||||
| /** | /** | ||||
| * Returns the next character in the filtered stream. If the desired | * Returns the next character in the filtered stream. If the desired | ||||
| * number of lines have already been read, the resulting stream is | * number of lines have already been read, the resulting stream is | ||||
| * effectively at an end. Otherwise, the next character from the | |||||
| * effectively at an end. Otherwise, the next character from the | |||||
| * underlying stream is read and returned. | * underlying stream is read and returned. | ||||
| * | |||||
| * | |||||
| * @return the next character in the resulting stream, or -1 | * @return the next character in the resulting stream, or -1 | ||||
| * if the end of the resulting stream has been reached | * if the end of the resulting stream has been reached | ||||
| * | |||||
| * | |||||
| * @exception IOException if the underlying stream throws an IOException | * @exception IOException if the underlying stream throws an IOException | ||||
| * during reading | |||||
| * during reading | |||||
| */ | */ | ||||
| public final int read() throws IOException { | public final int read() throws IOException { | ||||
| if (!getInitialized()) { | if (!getInitialized()) { | ||||
| @@ -121,7 +127,13 @@ public final class HeadFilter | |||||
| int ch = -1; | int ch = -1; | ||||
| if (linesRead < lines) { | |||||
| // skip the lines (if set) | |||||
| while (skip > 0) { | |||||
| for (int tmp = in.read(); tmp != '\n'; tmp = in.read()); | |||||
| skip--; | |||||
| } | |||||
| if ( (linesRead < lines) || (lines < 0) ){ | |||||
| ch = in.read(); | ch = in.read(); | ||||
| @@ -135,7 +147,7 @@ public final class HeadFilter | |||||
| /** | /** | ||||
| * Sets the number of lines to be returned in the filtered stream. | * Sets the number of lines to be returned in the filtered stream. | ||||
| * | |||||
| * | |||||
| * @param lines the number of lines to be returned in the filtered stream | * @param lines the number of lines to be returned in the filtered stream | ||||
| */ | */ | ||||
| public final void setLines(final long lines) { | public final void setLines(final long lines) { | ||||
| @@ -144,26 +156,45 @@ public final class HeadFilter | |||||
| /** | /** | ||||
| * Returns the number of lines to be returned in the filtered stream. | * Returns the number of lines to be returned in the filtered stream. | ||||
| * | |||||
| * | |||||
| * @return the number of lines to be returned in the filtered stream | * @return the number of lines to be returned in the filtered stream | ||||
| */ | */ | ||||
| private final long getLines() { | private final long getLines() { | ||||
| return lines; | return lines; | ||||
| } | } | ||||
| /** | |||||
| * Sets the number of lines to be skipped in the filtered stream. | |||||
| * | |||||
| * @param lines the number of lines to be skipped in the filtered stream | |||||
| */ | |||||
| public final void setSkip(final long skip) { | |||||
| this.skip = skip; | |||||
| } | |||||
| /** | |||||
| * Returns the number of lines to be skipped in the filtered stream. | |||||
| * | |||||
| * @return the number of lines to be skipped in the filtered stream | |||||
| */ | |||||
| private final long getSkip() { | |||||
| return skip; | |||||
| } | |||||
| /** | /** | ||||
| * Creates a new HeadFilter using the passed in | * Creates a new HeadFilter using the passed in | ||||
| * Reader for instantiation. | * Reader for instantiation. | ||||
| * | |||||
| * | |||||
| * @param rdr A Reader object providing the underlying stream. | * @param rdr A Reader object providing the underlying stream. | ||||
| * Must not be <code>null</code>. | * Must not be <code>null</code>. | ||||
| * | |||||
| * | |||||
| * @return a new filter based on this configuration, but filtering | * @return a new filter based on this configuration, but filtering | ||||
| * the specified reader | * the specified reader | ||||
| */ | */ | ||||
| public final Reader chain(final Reader rdr) { | public final Reader chain(final Reader rdr) { | ||||
| HeadFilter newFilter = new HeadFilter(rdr); | HeadFilter newFilter = new HeadFilter(rdr); | ||||
| newFilter.setLines(getLines()); | newFilter.setLines(getLines()); | ||||
| newFilter.setSkip(getSkip()); | |||||
| newFilter.setInitialized(true); | newFilter.setInitialized(true); | ||||
| return newFilter; | return newFilter; | ||||
| } | } | ||||
| @@ -180,6 +211,10 @@ public final class HeadFilter | |||||
| lines = new Long(params[i].getValue()).longValue(); | lines = new Long(params[i].getValue()).longValue(); | ||||
| break; | break; | ||||
| } | } | ||||
| if (SKIP_KEY.equals(params[i].getName())) { | |||||
| skip = new Long(params[i].getValue()).longValue(); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * The Apache Software License, Version 1.1 | ||||
| * | * | ||||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||||
| * Copyright (c) 2002-2003 The Apache Software Foundation. All rights | |||||
| * reserved. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| @@ -78,12 +78,18 @@ public final class TailFilter | |||||
| /** Parameter name for the number of lines to be returned. */ | /** Parameter name for the number of lines to be returned. */ | ||||
| private static final String LINES_KEY = "lines"; | private static final String LINES_KEY = "lines"; | ||||
| /** Parameter name for the number of lines to be skipped. */ | |||||
| private static final String SKIP_KEY = "skip"; | |||||
| /** Number of lines currently read in. */ | /** Number of lines currently read in. */ | ||||
| private long linesRead = 0; | private long linesRead = 0; | ||||
| /** Number of lines to be returned in the filtered stream. */ | /** Number of lines to be returned in the filtered stream. */ | ||||
| private long lines = 10; | private long lines = 10; | ||||
| /** Number of lines to be skipped. */ | |||||
| private long skip = 0; | |||||
| /** Buffer to hold in characters read ahead. */ | /** Buffer to hold in characters read ahead. */ | ||||
| private char[] buffer = new char[4096]; | private char[] buffer = new char[4096]; | ||||
| @@ -98,7 +104,7 @@ public final class TailFilter | |||||
| /** | /** | ||||
| * Constructor for "dummy" instances. | * Constructor for "dummy" instances. | ||||
| * | |||||
| * | |||||
| * @see BaseFilterReader#BaseFilterReader() | * @see BaseFilterReader#BaseFilterReader() | ||||
| */ | */ | ||||
| public TailFilter() { | public TailFilter() { | ||||
| @@ -121,12 +127,12 @@ public final class TailFilter | |||||
| * Otherwise, the stream is read to the end and buffered (with the buffer | * Otherwise, the stream is read to the end and buffered (with the buffer | ||||
| * growing as necessary), then the appropriate position in the buffer is | * growing as necessary), then the appropriate position in the buffer is | ||||
| * set to read from. | * set to read from. | ||||
| * | |||||
| * | |||||
| * @return the next character in the resulting stream, or -1 | * @return the next character in the resulting stream, or -1 | ||||
| * if the end of the resulting stream has been reached | * if the end of the resulting stream has been reached | ||||
| * | |||||
| * | |||||
| * @exception IOException if the underlying stream throws an IOException | * @exception IOException if the underlying stream throws an IOException | ||||
| * during reading | |||||
| * during reading | |||||
| */ | */ | ||||
| public final int read() throws IOException { | public final int read() throws IOException { | ||||
| if (!getInitialized()) { | if (!getInitialized()) { | ||||
| @@ -152,16 +158,18 @@ public final class TailFilter | |||||
| } | } | ||||
| } | } | ||||
| if (ch == '\n' || ch == -1) { | |||||
| ++linesRead; | |||||
| if (lines > 0) { | |||||
| if (ch == '\n' || ch == -1) { | |||||
| ++linesRead; | |||||
| if (linesRead == lines) { | |||||
| int i = 0; | |||||
| for (i = returnedCharPos + 1; | |||||
| buffer[i] != 0 && buffer[i] != '\n'; i++) { | |||||
| if ((linesRead == lines + skip)) { | |||||
| int i = 0; | |||||
| for (i = returnedCharPos + 1; | |||||
| buffer[i] != 0 && buffer[i] != '\n'; i++) { | |||||
| } | |||||
| returnedCharPos = i; | |||||
| --linesRead; | |||||
| } | } | ||||
| returnedCharPos = i; | |||||
| --linesRead; | |||||
| } | } | ||||
| } | } | ||||
| if (ch == -1) { | if (ch == -1) { | ||||
| @@ -174,6 +182,26 @@ public final class TailFilter | |||||
| completedReadAhead = true; | completedReadAhead = true; | ||||
| } | } | ||||
| // Because the complete stream is read into the buffer I can delete | |||||
| // the "skip lines" from back to the beginning. | |||||
| if (skip > 0) { | |||||
| // searching... | |||||
| int i; | |||||
| for (i = buffer.length - 1; skip > 0; i--) { | |||||
| if (buffer[i]=='\n') { | |||||
| skip--; | |||||
| } | |||||
| } | |||||
| // cut the buffer to the new length | |||||
| char[] newBuffer = new char[i]; | |||||
| System.arraycopy(buffer, 0, newBuffer, 0, i); | |||||
| buffer = newBuffer; | |||||
| // don´t forget to set the "lastposition" new | |||||
| bufferPos = i; | |||||
| } | |||||
| ++returnedCharPos; | ++returnedCharPos; | ||||
| if (returnedCharPos >= bufferPos) { | if (returnedCharPos >= bufferPos) { | ||||
| return -1; | return -1; | ||||
| @@ -184,7 +212,7 @@ public final class TailFilter | |||||
| /** | /** | ||||
| * Sets the number of lines to be returned in the filtered stream. | * Sets the number of lines to be returned in the filtered stream. | ||||
| * | |||||
| * | |||||
| * @param lines the number of lines to be returned in the filtered stream | * @param lines the number of lines to be returned in the filtered stream | ||||
| */ | */ | ||||
| public final void setLines(final long lines) { | public final void setLines(final long lines) { | ||||
| @@ -193,26 +221,45 @@ public final class TailFilter | |||||
| /** | /** | ||||
| * Returns the number of lines to be returned in the filtered stream. | * Returns the number of lines to be returned in the filtered stream. | ||||
| * | |||||
| * | |||||
| * @return the number of lines to be returned in the filtered stream | * @return the number of lines to be returned in the filtered stream | ||||
| */ | */ | ||||
| private final long getLines() { | private final long getLines() { | ||||
| return lines; | return lines; | ||||
| } | } | ||||
| /** | |||||
| * Sets the number of lines to be skipped in the filtered stream. | |||||
| * | |||||
| * @param lines the number of lines to be skipped in the filtered stream | |||||
| */ | |||||
| public final void setSkip(final long skip) { | |||||
| this.skip = skip; | |||||
| } | |||||
| /** | |||||
| * Returns the number of lines to be skipped in the filtered stream. | |||||
| * | |||||
| * @return the number of lines to be skipped in the filtered stream | |||||
| */ | |||||
| private final long getSkip() { | |||||
| return skip; | |||||
| } | |||||
| /** | /** | ||||
| * Creates a new TailFilter using the passed in | * Creates a new TailFilter using the passed in | ||||
| * Reader for instantiation. | * Reader for instantiation. | ||||
| * | |||||
| * | |||||
| * @param rdr A Reader object providing the underlying stream. | * @param rdr A Reader object providing the underlying stream. | ||||
| * Must not be <code>null</code>. | * Must not be <code>null</code>. | ||||
| * | |||||
| * | |||||
| * @return a new filter based on this configuration, but filtering | * @return a new filter based on this configuration, but filtering | ||||
| * the specified reader | * the specified reader | ||||
| */ | */ | ||||
| public final Reader chain(final Reader rdr) { | public final Reader chain(final Reader rdr) { | ||||
| TailFilter newFilter = new TailFilter(rdr); | TailFilter newFilter = new TailFilter(rdr); | ||||
| newFilter.setLines(getLines()); | newFilter.setLines(getLines()); | ||||
| newFilter.setSkip(getSkip()); | |||||
| newFilter.setInitialized(true); | newFilter.setInitialized(true); | ||||
| return newFilter; | return newFilter; | ||||
| } | } | ||||
| @@ -229,6 +276,10 @@ public final class TailFilter | |||||
| setLines(new Long(params[i].getValue()).longValue()); | setLines(new Long(params[i].getValue()).longValue()); | ||||
| break; | break; | ||||
| } | } | ||||
| if (SKIP_KEY.equals(params[i].getName())) { | |||||
| skip = new Long(params[i].getValue()).longValue(); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,155 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
| * reserved. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in | |||||
| * the documentation and/or other materials provided with the | |||||
| * distribution. | |||||
| * | |||||
| * 3. The end-user documentation included with the redistribution, if | |||||
| * any, must include the following acknowlegement: | |||||
| * "This product includes software developed by the | |||||
| * Apache Software Foundation (http://www.apache.org/)." | |||||
| * Alternately, this acknowlegement may appear in the software itself, | |||||
| * if and wherever such third-party acknowlegements normally appear. | |||||
| * | |||||
| * 4. The names "Ant" and "Apache Software | |||||
| * Foundation" must not be used to endorse or promote products derived | |||||
| * from this software without prior written permission. For written | |||||
| * permission, please contact apache@apache.org. | |||||
| * | |||||
| * 5. Products derived from this software may not be called "Apache" | |||||
| * nor may "Apache" appear in their names without prior written | |||||
| * permission of the Apache Group. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| * SUCH DAMAGE. | |||||
| * ==================================================================== | |||||
| * | |||||
| * This software consists of voluntary contributions made by many | |||||
| * individuals on behalf of the Apache Software Foundation. For more | |||||
| * information on the Apache Software Foundation, please see | |||||
| * <http://www.apache.org/>. | |||||
| */ | |||||
| package org.apache.tools.ant.filters; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import org.apache.tools.ant.BuildFileTest; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| /** JUnit Testcases for TailFilter and HeadFilter | |||||
| * @author <a href="mailto:jan@materne.de">Jan Matèrne</a> | |||||
| */ | |||||
| /* I wrote the testcases in one java file because I want also to test the | |||||
| * combined behaviour (see end of the class). | |||||
| */ | |||||
| public class HeadTailTest extends BuildFileTest { | |||||
| public HeadTailTest(String name) { | |||||
| super(name); | |||||
| } | |||||
| public void setUp() { | |||||
| configureProject("src/etc/testcases/filters/head-tail.xml"); | |||||
| } | |||||
| public void tearDown() { | |||||
| executeTarget("cleanup"); | |||||
| } | |||||
| public void testHead() throws IOException { | |||||
| executeTarget("testHead"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.head.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.head.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testHead: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testHeadLines() throws IOException { | |||||
| executeTarget("testHeadLines"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.headLines.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.headLines.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testHeadLines: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testHeadSkip() throws IOException { | |||||
| executeTarget("testHeadSkip"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.headSkip.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.headSkip.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testHeadSkip: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testHeadLinesSkip() throws IOException { | |||||
| executeTarget("testHeadLinesSkip"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.headLinesSkip.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.headLinesSkip.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testHeadLinesSkip: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testTail() throws IOException { | |||||
| executeTarget("testTail"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.tail.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.tail.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testTail: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testTailLines() throws IOException { | |||||
| executeTarget("testTailLines"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.tailLines.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.tailLines.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testTailLines: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testTailSkip() throws IOException { | |||||
| executeTarget("testTailSkip"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.tailSkip.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.tailSkip.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testTailSkip: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testTailLinesSkip() throws IOException { | |||||
| executeTarget("testTailLinesSkip"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.tailLinesSkip.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.tailLinesSkip.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testTailLinesSkip: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| public void testHeadTail() throws IOException { | |||||
| executeTarget("testHeadTail"); | |||||
| File expected = getProject().resolveFile("expected/head-tail.headTail.test"); | |||||
| File result = getProject().resolveFile("result/head-tail.headTail.test"); | |||||
| FileUtils fu = FileUtils.newFileUtils(); | |||||
| assertTrue("testHeadTail: Result not like expected", fu.contentEquals(expected, result)); | |||||
| } | |||||
| } | |||||