view src/kryshen/tema/io/TemplateReader.java @ 32:bdd1c8d6b560

Do not read EOF more than once, report unexpected EOF in function data.
author Mikhail Kryshen <mikhail@kryshen.net>
date Fri, 25 Sep 2009 02:37:16 +0400
parents e9d13c7ffeb1
children
line source
1 /*
2 * Copyright 2006-2009 Mikhail Kryshen
3 *
4 * This file is part of Tema.
5 *
6 * Tema is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * Tema is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the
17 * GNU Lesser General Public License along with Tema.
18 * If not, see <http://www.gnu.org/licenses/>.
19 */
21 package kryshen.tema.io;
23 import java.io.FilterReader;
24 import java.io.IOException;
25 import java.io.Reader;
26 import java.io.LineNumberReader;
27 import kryshen.tema.TemplateParser;
29 /**
30 * Reader for Tema templates. Stores data source name (commonly
31 * filename) and tracks line numbers for error reporting.
32 *
33 * @author Mikhail Kryshen
34 */
35 public class TemplateReader extends FilterReader {
36 static final int UNREAD_BUFFER_SIZE;
38 /* Calculate UNREAD_BUFFER_SIZE value. */
39 static {
40 int max = 0;
42 for (String s : TemplateParser.BRACKET_OPEN) {
43 max = Math.max(max, s.length());
44 }
46 for (String s : TemplateParser.BRACKET_CLOSE) {
47 max = Math.max(max, s.length());
48 }
50 max = Math.max(max, TemplateParser.ESCAPE_NEWLINE.length() + 2);
51 max = Math.max(max, TemplateParser.ESCAPE_WHITESPACE.length());
53 UNREAD_BUFFER_SIZE = max + 1;
54 }
56 private final String source;
57 private final LineNumberReader lnReader;
58 private final TemplateReader parentReader;
60 private final int[] unreadBuffer = new int[UNREAD_BUFFER_SIZE];
61 private int unread = 0;
63 public TemplateReader(Reader in) {
64 this(new LineNumberReader(in));
65 }
67 public TemplateReader(Reader in, String source) {
68 this(new LineNumberReader(in), source);
69 }
71 public TemplateReader(LineNumberReader in) {
72 this(in, "");
73 }
75 public TemplateReader(LineNumberReader in, String source) {
76 super(in);
78 this.parentReader = null;
79 this.lnReader = in;
80 this.source = source;
81 }
83 public TemplateReader(Reader in, TemplateReader parent) {
84 super(in);
86 this.parentReader = parent;
87 this.lnReader = null;
88 this.source = null;
89 }
91 public String getSource() {
92 if (source != null)
93 return source;
95 return parentReader.getSource();
96 }
98 public int getLineNumber() {
99 if (lnReader != null)
100 return lnReader.getLineNumber();
102 return parentReader.getLineNumber();
103 }
105 @Override
106 public int read() throws IOException {
107 if (unread == 0) {
108 return super.read();
109 }
111 return unreadBuffer[--unread];
112 }
114 @Override
115 public int read(char[] cbuf, int off, int len) throws IOException {
116 int n = 0;
118 while (unread > 0) {
119 cbuf[off + n++] = (char) unreadBuffer[--unread];
121 if (n == len) {
122 return n;
123 }
124 }
126 return n + super.read(cbuf, off + n, len - n);
127 }
129 @Override
130 public long skip(long n) throws IOException {
131 if (n <= unread) {
132 unread -= n;
133 return n;
134 }
136 n -= unread;
137 long ret = super.skip(n) + unread;
138 unread = 0;
140 return ret;
141 }
144 public void unread(String s) throws IOException {
145 unread(s.toCharArray());
146 }
148 public void unread(int c) {
149 if (unread + 1 > UNREAD_BUFFER_SIZE) {
150 throw new IndexOutOfBoundsException();
151 }
153 unreadBuffer[unread++] = c;
154 }
156 public void unread(char[] buff) {
157 unread(buff, 0, buff.length);
158 }
160 public void unread(char[] buff, int off, int len) {
161 if (unread + len > UNREAD_BUFFER_SIZE) {
162 throw new IndexOutOfBoundsException();
163 }
165 for (int i = off + len - 1; i >= off; i--) {
166 unreadBuffer[unread++] = buff[i];
167 }
168 }
170 @Override
171 public boolean ready() throws IOException {
172 return unread > 0 || super.ready();
173 }
175 @Override
176 public void mark(int readAheadLimit) throws IOException {
177 throw new IOException("Not supported");
178 }
180 @Override
181 public void reset() throws IOException {
182 throw new IOException("Not supported");
183 }
185 @Override
186 public boolean markSupported() {
187 return false;
188 }
189 }