001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.filters;
019:
020: import java.io.IOException;
021: import java.io.Reader;
022: import org.apache.tools.ant.util.LineTokenizer;
023: import org.apache.tools.ant.types.Parameter;
024:
025: /**
026: * Reads the first <code>n</code> lines of a stream.
027: * (Default is first 10 lines.)
028: * <p>
029: * Example:
030: * <pre><headfilter lines="3"/></pre>
031: * Or:
032: * <pre><filterreader classname="org.apache.tools.ant.filters.HeadFilter">
033: * <param name="lines" value="3"/>
034: * </filterreader></pre>
035: *
036: */
037: public final class HeadFilter extends BaseParamFilterReader implements
038: ChainableReader {
039: /** Parameter name for the number of lines to be returned. */
040: private static final String LINES_KEY = "lines";
041:
042: /** Parameter name for the number of lines to be skipped. */
043: private static final String SKIP_KEY = "skip";
044:
045: /** Number of lines currently read in. */
046: private long linesRead = 0;
047:
048: /** Default number of lines to show */
049: private static final int DEFAULT_NUM_LINES = 10;
050:
051: /** Number of lines to be returned in the filtered stream. */
052: private long lines = DEFAULT_NUM_LINES;
053:
054: /** Number of lines to be skipped. */
055: private long skip = 0;
056:
057: /** A line tokenizer */
058: private LineTokenizer lineTokenizer = null;
059:
060: /** the current line from the input stream */
061: private String line = null;
062: /** the position in the current line */
063: private int linePos = 0;
064:
065: /**
066: * Constructor for "dummy" instances.
067: *
068: * @see BaseFilterReader#BaseFilterReader()
069: */
070: public HeadFilter() {
071: super ();
072: }
073:
074: /**
075: * Creates a new filtered reader.
076: *
077: * @param in A Reader object providing the underlying stream.
078: * Must not be <code>null</code>.
079: */
080: public HeadFilter(final Reader in) {
081: super (in);
082: lineTokenizer = new LineTokenizer();
083: lineTokenizer.setIncludeDelims(true);
084: }
085:
086: /**
087: * Returns the next character in the filtered stream. If the desired
088: * number of lines have already been read, the resulting stream is
089: * effectively at an end. Otherwise, the next character from the
090: * underlying stream is read and returned.
091: *
092: * @return the next character in the resulting stream, or -1
093: * if the end of the resulting stream has been reached
094: *
095: * @exception IOException if the underlying stream throws an IOException
096: * during reading
097: */
098: public int read() throws IOException {
099: if (!getInitialized()) {
100: initialize();
101: setInitialized(true);
102: }
103:
104: while (line == null || line.length() == 0) {
105: line = lineTokenizer.getToken(in);
106: if (line == null) {
107: return -1;
108: }
109: line = headFilter(line);
110: linePos = 0;
111: }
112:
113: int ch = line.charAt(linePos);
114: linePos++;
115: if (linePos == line.length()) {
116: line = null;
117: }
118: return ch;
119: }
120:
121: /**
122: * Sets the number of lines to be returned in the filtered stream.
123: *
124: * @param lines the number of lines to be returned in the filtered stream
125: */
126: public void setLines(final long lines) {
127: this .lines = lines;
128: }
129:
130: /**
131: * Returns the number of lines to be returned in the filtered stream.
132: *
133: * @return the number of lines to be returned in the filtered stream
134: */
135: private long getLines() {
136: return lines;
137: }
138:
139: /**
140: * Sets the number of lines to be skipped in the filtered stream.
141: *
142: * @param skip the number of lines to be skipped in the filtered stream
143: */
144: public void setSkip(final long skip) {
145: this .skip = skip;
146: }
147:
148: /**
149: * Returns the number of lines to be skipped in the filtered stream.
150: *
151: * @return the number of lines to be skipped in the filtered stream
152: */
153: private long getSkip() {
154: return skip;
155: }
156:
157: /**
158: * Creates a new HeadFilter using the passed in
159: * Reader for instantiation.
160: *
161: * @param rdr A Reader object providing the underlying stream.
162: * Must not be <code>null</code>.
163: *
164: * @return a new filter based on this configuration, but filtering
165: * the specified reader
166: */
167: public Reader chain(final Reader rdr) {
168: HeadFilter newFilter = new HeadFilter(rdr);
169: newFilter.setLines(getLines());
170: newFilter.setSkip(getSkip());
171: newFilter.setInitialized(true);
172: return newFilter;
173: }
174:
175: /**
176: * Scans the parameters list for the "lines" parameter and uses
177: * it to set the number of lines to be returned in the filtered stream.
178: * also scan for skip parameter.
179: */
180: private void initialize() {
181: Parameter[] params = getParameters();
182: if (params != null) {
183: for (int i = 0; i < params.length; i++) {
184: if (LINES_KEY.equals(params[i].getName())) {
185: lines = new Long(params[i].getValue()).longValue();
186: continue;
187: }
188: if (SKIP_KEY.equals(params[i].getName())) {
189: skip = new Long(params[i].getValue()).longValue();
190: continue;
191: }
192: }
193: }
194: }
195:
196: /**
197: * implements a head filter on the input stream
198: */
199: private String headFilter(String line) {
200: linesRead++;
201: if (skip > 0) {
202: if ((linesRead - 1) < skip) {
203: return null;
204: }
205: }
206:
207: if (lines > 0) {
208: if (linesRead > (lines + skip)) {
209: return null;
210: }
211: }
212: return line;
213: }
214: }
|