1. /*
  2. * Copyright 2002-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. */
  17. package org.apache.tools.ant.filters;
  18. import java.io.IOException;
  19. import java.io.Reader;
  20. import org.apache.tools.ant.util.LineTokenizer;
  21. import org.apache.tools.ant.types.Parameter;
  22. /**
  23. * Reads the first <code>n</code> lines of a stream.
  24. * (Default is first 10 lines.)
  25. * <p>
  26. * Example:
  27. * <pre><headfilter lines="3"/></pre>
  28. * Or:
  29. * <pre><filterreader classname="org.apache.tools.ant.filters.HeadFilter">
  30. * <param name="lines" value="3"/>
  31. * </filterreader></pre>
  32. *
  33. */
  34. public final class HeadFilter extends BaseParamFilterReader
  35. implements ChainableReader {
  36. /** Parameter name for the number of lines to be returned. */
  37. private static final String LINES_KEY = "lines";
  38. /** Parameter name for the number of lines to be skipped. */
  39. private static final String SKIP_KEY = "skip";
  40. /** Number of lines currently read in. */
  41. private long linesRead = 0;
  42. /** Default number of lines to show */
  43. private static final int DEFAULT_NUM_LINES = 10;
  44. /** Number of lines to be returned in the filtered stream. */
  45. private long lines = DEFAULT_NUM_LINES;
  46. /** Number of lines to be skipped. */
  47. private long skip = 0;
  48. /** A line tokenizer */
  49. private LineTokenizer lineTokenizer = null;
  50. /** the current line from the input stream */
  51. private String line = null;
  52. /** the position in the current line */
  53. private int linePos = 0;
  54. /**
  55. * Constructor for "dummy" instances.
  56. *
  57. * @see BaseFilterReader#BaseFilterReader()
  58. */
  59. public HeadFilter() {
  60. super();
  61. }
  62. /**
  63. * Creates a new filtered reader.
  64. *
  65. * @param in A Reader object providing the underlying stream.
  66. * Must not be <code>null</code>.
  67. */
  68. public HeadFilter(final Reader in) {
  69. super(in);
  70. lineTokenizer = new LineTokenizer();
  71. lineTokenizer.setIncludeDelims(true);
  72. }
  73. /**
  74. * Returns the next character in the filtered stream. If the desired
  75. * number of lines have already been read, the resulting stream is
  76. * effectively at an end. Otherwise, the next character from the
  77. * underlying stream is read and returned.
  78. *
  79. * @return the next character in the resulting stream, or -1
  80. * if the end of the resulting stream has been reached
  81. *
  82. * @exception IOException if the underlying stream throws an IOException
  83. * during reading
  84. */
  85. public final int read() throws IOException {
  86. if (!getInitialized()) {
  87. initialize();
  88. setInitialized(true);
  89. }
  90. while (line == null || line.length() == 0) {
  91. line = lineTokenizer.getToken(in);
  92. if (line == null) {
  93. return -1;
  94. }
  95. line = headFilter(line);
  96. linePos = 0;
  97. }
  98. int ch = line.charAt(linePos);
  99. linePos++;
  100. if (linePos == line.length()) {
  101. line = null;
  102. }
  103. return ch;
  104. }
  105. /**
  106. * Sets the number of lines to be returned in the filtered stream.
  107. *
  108. * @param lines the number of lines to be returned in the filtered stream
  109. */
  110. public final void setLines(final long lines) {
  111. this.lines = lines;
  112. }
  113. /**
  114. * Returns the number of lines to be returned in the filtered stream.
  115. *
  116. * @return the number of lines to be returned in the filtered stream
  117. */
  118. private final long getLines() {
  119. return lines;
  120. }
  121. /**
  122. * Sets the number of lines to be skipped in the filtered stream.
  123. *
  124. * @param skip the number of lines to be skipped in the filtered stream
  125. */
  126. public final void setSkip(final long skip) {
  127. this.skip = skip;
  128. }
  129. /**
  130. * Returns the number of lines to be skipped in the filtered stream.
  131. *
  132. * @return the number of lines to be skipped in the filtered stream
  133. */
  134. private final long getSkip() {
  135. return skip;
  136. }
  137. /**
  138. * Creates a new HeadFilter using the passed in
  139. * Reader for instantiation.
  140. *
  141. * @param rdr A Reader object providing the underlying stream.
  142. * Must not be <code>null</code>.
  143. *
  144. * @return a new filter based on this configuration, but filtering
  145. * the specified reader
  146. */
  147. public final Reader chain(final Reader rdr) {
  148. HeadFilter newFilter = new HeadFilter(rdr);
  149. newFilter.setLines(getLines());
  150. newFilter.setSkip(getSkip());
  151. newFilter.setInitialized(true);
  152. return newFilter;
  153. }
  154. /**
  155. * Scans the parameters list for the "lines" parameter and uses
  156. * it to set the number of lines to be returned in the filtered stream.
  157. * also scan for skip parameter.
  158. */
  159. private final void initialize() {
  160. Parameter[] params = getParameters();
  161. if (params != null) {
  162. for (int i = 0; i < params.length; i++) {
  163. if (LINES_KEY.equals(params[i].getName())) {
  164. lines = new Long(params[i].getValue()).longValue();
  165. continue;
  166. }
  167. if (SKIP_KEY.equals(params[i].getName())) {
  168. skip = new Long(params[i].getValue()).longValue();
  169. continue;
  170. }
  171. }
  172. }
  173. }
  174. /**
  175. * implements a head filter on the input stream
  176. */
  177. private String headFilter(String line) {
  178. linesRead++;
  179. if (skip > 0) {
  180. if ((linesRead - 1) < skip) {
  181. return null;
  182. }
  183. }
  184. if (lines > 0) {
  185. if (linesRead > (lines + skip)) {
  186. return null;
  187. }
  188. }
  189. return line;
  190. }
  191. }