view src/kryshen/tema/FunctionDataParser.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 584c2f18bb48
children b637a4491862
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;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.StringWriter;
26 import java.io.Writer;
27 import java.util.ArrayList;
28 import java.util.List;
29 import kryshen.tema.TemplateParser.DataFormat;
30 import static kryshen.tema.TemplateParser.Terminator;
31 import kryshen.tema.io.CopyWriter;
32 import kryshen.tema.io.NullWriter;
33 import kryshen.tema.io.TemplateReader;
35 /**
36 * Parser for a function data.
37 *
38 * @author Mikhail Kryshen
39 */
40 public class FunctionDataParser {
41 static final char[] ARG_SEPARATORS = TemplateParser.LIST_SEPARATORS;
43 private final TemplateParser tp;
44 private final DataFormat fd;
45 private final TemplateReader in;
46 private final String name;
48 private boolean available = true;
50 private int lastReturnCode = 0;
52 FunctionDataParser(TemplateParser tp, DataFormat fd, TemplateReader in,
53 String name) throws IOException, TemplateException {
54 this.tp = tp;
55 this.fd = fd;
56 this.in = in;
57 this.name = name;
59 // Check for empty function data.
60 checkAvailable();
61 }
63 private void checkAvailable() throws IOException, TemplateException {
64 if (tp.checkCloseBracket(in)) {
65 // Complete parsing the instruction.
66 skipData();
67 }
68 }
70 private int parseData(Writer out, boolean argument, boolean skip)
71 throws IOException, TemplateException {
73 if (!available)
74 throw new TemplateException
75 ("Unexpected end of instruction data.", in);
77 DataFormat fd = skip ? this.fd.noInvoke() : this.fd;
79 TemplateParser.Result r;
81 // if (fd.subfunction && argument) {
82 // // Allow subfunction to pass a list of arguments
83 // StringWriter sw = new StringWriter();
84 // tp.parse(in, sw, fd);
85 // sw.close();
86 // in = new TemplateReader(new StringReader(sw.toString()), in);
87 // this.fd = DataFormat.VERBATIM;
88 // r = parseData(out, true, false);
89 // } else
90 if (fd.subfunction) {
91 r = tp.parse(in, out, fd);
92 } else if (argument) {
93 // Skip duplicate separators before argument.
94 tp.skip(in, ARG_SEPARATORS);
96 r = tp.parse(in, out, fd, ARG_SEPARATORS);
98 // Skip duplicate separators after argument.
99 if (r.terminator == Terminator.SEPARATOR) {
100 tp.skip(in, ARG_SEPARATORS);
101 checkAvailable();
102 }
103 } else {
104 r = tp.parse(in, out, fd, null);
105 }
107 if (r.terminator == Terminator.EOF) {
108 throw new TemplateException
109 ("Unexpected end of instruction data", in);
110 }
112 if (r.terminator != Terminator.SEPARATOR)
113 available = false; // No more function data available.
115 lastReturnCode = r.retCode;
116 return r.retCode;
117 }
119 /**
120 * Parse function data.
121 */
122 public int parseData(Writer out) throws IOException, TemplateException {
123 return parseData(out, false, false);
124 }
126 /**
127 * Skip function data (do not call any functions).
128 */
129 public void skipData() throws IOException, TemplateException {
130 parseData(NullWriter.INSTANCE, false, true);
131 }
133 /**
134 * Get function data as string.
135 */
136 public String getData() throws IOException, TemplateException {
137 StringWriter sw = new StringWriter();
138 parseData(sw);
139 sw.close();
140 return sw.toString();
141 }
143 /**
144 * Parse function data into specified <code>Writer</code>.
145 * Returns copy of the parsed data as string.
146 */
147 public String getData(Writer out) throws IOException, TemplateException {
148 StringWriter sw = new StringWriter();
149 parseData(new CopyWriter(sw, out));
150 sw.close();
151 return sw.toString();
152 }
154 public int parseNextArg(Writer out) throws IOException, TemplateException {
155 return parseData(out, true, false);
156 }
158 public void skipNextArg() throws IOException, TemplateException {
159 parseData(NullWriter.INSTANCE, true, true);
160 }
162 public String getNextArg() throws IOException, TemplateException {
163 StringWriter sw = new StringWriter();
164 parseNextArg(sw);
165 sw.close();
166 return sw.toString();
167 }
169 public List<String> getArgs() throws IOException, TemplateException {
170 List<String> l = new ArrayList<String>();
172 while (available) {
173 l.add(getNextArg());
174 }
176 return l;
177 }
179 public boolean hasMoreData() {
180 return available;
181 }
183 public int getLastReturnCode() {
184 return lastReturnCode;
185 }
187 public TemplateParser getTemplateParser() {
188 return tp;
189 }
191 public Context getContext() {
192 return tp.getContext();
193 }
195 public TemplateReader getTemplateReader() {
196 return in;
197 }
199 public String getName() {
200 return name;
201 }
203 public void warning(String message) {
204 System.err.println(in.getSource() + ":" + (in.getLineNumber() + 1) +
205 ": " + name + ": " + message);
206 }
208 public File createFile(String path) {
209 File file = new File(path);
211 if (file.isAbsolute())
212 return file;
214 File base = tp.getContext().getBaseDirectory();
216 return base.getPath().isEmpty()
217 ? new File(path)
218 : new File(base, path);
219 }
220 }