001: /* ====================================================================
002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
003: * ====================================================================
004: * The Tea Software License, Version 1.1
005: *
006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Walt Disney Internet Group (http://opensource.go.com/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact opensource@dig.com.
031: *
032: * 5. Products derived from this software may not be called "Tea",
033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
035: * written permission of the Walt Disney Internet Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048: * ====================================================================
049: *
050: * For more information about Tea, please see http://opensource.go.com/.
051: */
052:
053: package com.go.tea.io;
054:
055: import java.io.*;
056:
057: /******************************************************************************
058: * The SourceReader provides several services for reading source input.
059: * It calculates line numbers, position in the source file, supports two
060: * character pushback, extracts code from text that allows mixed code and
061: * plain text, and it processes unicode escape sequences that appear in
062: * source code.
063: *
064: * <p>Readers return -1 when the end of the stream, has been reached, and so
065: * does SourceReader. SourceReader will also return other special negative
066: * values to indicate a tag substitution. ENTER_CODE is returned to indicate
067: * that characters read are in source code, and ENTER_TEXT is returned to
068: * indicate that characters read are in plain text. The first character read
069: * from a SourceReader is either ENTER_CODE or ENTER_TEXT;
070: *
071: * @author Brian S O'Neill
072: * @version
073: * <!--$$Revision:--> 16 <!-- $-->, <!--$$JustDate:--> 12/11/00 <!-- $-->
074: * @deprecated Moved to com.go.trove.io package.
075: */
076: public class SourceReader extends PushbackPositionReader {
077: public static final int ENTER_CODE = -2;
078: public static final int ENTER_TEXT = -3;
079:
080: private static Reader createReader(Reader source, String beginTag,
081: String endTag) {
082: String[] tags = new String[4];
083: int[] codes = new int[4];
084:
085: int i = 0;
086: // Convert different kinds of line breaks into the newline character.
087: tags[i] = "\r\n";
088: codes[i++] = '\n';
089: tags[i] = "\r";
090: codes[i++] = '\n';
091:
092: if (beginTag != null && beginTag.length() > 0) {
093: tags[i] = beginTag;
094: codes[i++] = ENTER_CODE;
095: }
096:
097: if (endTag != null && endTag.length() > 0) {
098: tags[i] = endTag;
099: codes[i++] = ENTER_TEXT;
100: }
101:
102: if (i < 4) {
103: String[] newTags = new String[i];
104: System.arraycopy(tags, 0, newTags, 0, i);
105: tags = newTags;
106:
107: int[] newCodes = new int[i];
108: System.arraycopy(codes, 0, newCodes, 0, i);
109: codes = newCodes;
110: }
111:
112: return new UnicodeReader(new TagReader(source, tags, codes));
113: }
114:
115: private UnicodeReader mUnicodeReader;
116: private TagReader mTagReader;
117: private boolean mClosed = false;
118:
119: // The current line in the source. (1..)
120: private int mLine = 1;
121:
122: private int mFirst;
123:
124: private String mBeginTag;
125: private String mEndTag;
126:
127: /**
128: * The begin and end tags for a SourceReader are optional. If the begin
129: * tag is null or has zero length, then the SourceReader starts reading
130: * characters as if they were source code.
131: *
132: * <p>If the end tag is null or has zero length, then a source code
133: * region continues to the end of the input Reader's characters.
134: *
135: * @param source the source reader
136: * @param beginTag tag that marks the beginning of a source code region
137: * @param endTag tag that marks the end of a source code region
138: */
139: public SourceReader(Reader source, String beginTag, String endTag) {
140: super (createReader(source, beginTag, endTag), 2);
141: mUnicodeReader = (UnicodeReader) in;
142: mTagReader = (TagReader) mUnicodeReader.getOriginalSource();
143:
144: boolean codeMode = (beginTag == null || beginTag.length() == 0);
145: mFirst = (codeMode) ? ENTER_CODE : ENTER_TEXT;
146:
147: mBeginTag = beginTag;
148: mEndTag = endTag;
149: }
150:
151: public String getBeginTag() {
152: return mBeginTag;
153: }
154:
155: public String getEndTag() {
156: return mEndTag;
157: }
158:
159: /**
160: * All newline character patterns are are converted to \n.
161: */
162: public int read() throws IOException {
163: int c;
164:
165: if (mFirst != 0) {
166: c = mFirst;
167: mFirst = 0;
168: } else {
169: c = super .read();
170: }
171:
172: if (c == '\n') {
173: mLine++;
174: } else if (c == ENTER_CODE) {
175: mUnicodeReader.setEscapesEnabled(true);
176: } else if (c == ENTER_TEXT) {
177: mUnicodeReader.setEscapesEnabled(false);
178: }
179:
180: return c;
181: }
182:
183: public int getLineNumber() {
184: return mLine;
185: }
186:
187: /**
188: * The position in the reader where the last read character ended. The
189: * position of the first character read from a Reader is zero.
190: *
191: * <p>The end position is usually the same as the start position, but
192: * sometimes a SourceReader may combine multiple characters into a
193: * single one.
194: *
195: * @return the end position where the last character was read
196: */
197: public int getEndPosition() {
198: int e = getNextPosition() - 1;
199: return (e < getStartPosition()) ? getStartPosition() : e;
200: }
201:
202: public void ignoreTags(boolean ignore) {
203: mTagReader.setEscapesEnabled(!ignore);
204: }
205:
206: public boolean isClosed() {
207: return mClosed;
208: }
209:
210: public void close() throws IOException {
211: mClosed = true;
212: super .close();
213: }
214:
215: protected void unreadHook(int c) {
216: if (c == '\n') {
217: mLine--;
218: } else if (c == ENTER_CODE) {
219: mUnicodeReader.setEscapesEnabled(false);
220: } else if (c == ENTER_TEXT) {
221: mUnicodeReader.setEscapesEnabled(true);
222: }
223: }
224:
225: /**
226: * Simple test program
227: */
228: public static void main(String[] arg) throws Exception {
229: Tester.test(arg);
230: }
231:
232: private static class Tester {
233: public static void test(String[] arg) throws Exception {
234: String str = "This is \\" + "u0061 test.\n" + "This is \\"
235: + "u00612 test.\n" + "This is \\" + "u0061" + "\\"
236: + "u0061" + " test.\n" + "This is \\"
237: + "u061 test.\n" + "This is \\\\" + "u0061 test.\n"
238: + "This is \\" + "a test.\n"
239: + "Plain text <%put code here%> plain text.\n"
240: + "Plain text <\\"
241: + "u0025put code here%> plain text.\n"
242: + "Plain text <%put code here\\"
243: + "u0025> plain text.\n";
244:
245: Reader reader;
246:
247: if (arg.length > 0) {
248: reader = new java.io.FileReader(arg[0]);
249: } else {
250: System.out.println("\nOriginal:\n");
251:
252: reader = new StringReader(str);
253:
254: int c;
255: while ((c = reader.read()) != -1) {
256: System.out.print((char) c);
257: }
258: }
259:
260: System.out.println("\nTest 1:\n");
261:
262: if (arg.length > 0) {
263: reader = new java.io.FileReader(arg[0]);
264: } else {
265: reader = new StringReader(str);
266: }
267:
268: SourceReader sr = new SourceReader(reader, "<%", "%>");
269:
270: int c;
271: while ((c = sr.read()) != -1) {
272: System.out.print((char) c);
273: System.out.print("\t" + c);
274: System.out.print("\t" + sr.getLineNumber());
275: System.out.print("\t" + sr.getStartPosition());
276: System.out.println("\t" + sr.getEndPosition());
277: }
278:
279: System.out.println("\nTest 2:\n");
280: if (arg.length > 0) {
281: reader = new java.io.FileReader(arg[0]);
282: } else {
283: reader = new StringReader(str);
284: }
285:
286: sr = new SourceReader(reader, null, null);
287:
288: while ((c = sr.read()) != -1) {
289: System.out.print((char) c);
290: System.out.print("\t" + c);
291: System.out.print("\t" + sr.getLineNumber());
292: System.out.print("\t" + sr.getStartPosition());
293: System.out.println("\t" + sr.getEndPosition());
294: }
295: }
296: }
297: }
|