2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 import org.clearsilver.HDF;
18 import org.clearsilver.CS;
20 import java.io.Reader;
21 import java.io.IOException;
22 import java.io.FileReader;
23 import java.io.LineNumberReader;
24 import java.util.regex.Pattern;
25 import java.util.regex.Matcher;
28 * SampleTagInfo copies text from a given file into the javadoc comment.
30 * The @include tag copies the text verbatim from the given file.
32 * The @sample tag copies the text from the given file, stripping leading and
33 * trailing whitespace, and reducing the indent level of the text to the indent
34 * level of the first non-whitespace line.
36 * Both tags accept either a filename and an id or just a filename. If no id
37 * is provided, the entire file is copied. If an id is provided, the lines
38 * in the given file between the first two lines containing BEGIN_INCLUDE(id)
39 * and END_INCLUDE(id), for the given id, are copied. The id may be only
40 * letters, numbers and underscore (_).
43 * {@include samples/ApiDemos/src/com/google/app/Notification1.java}
44 * {@sample samples/ApiDemos/src/com/google/app/Notification1.java}
45 * {@include samples/ApiDemos/src/com/google/app/Notification1.java Bleh}
46 * {@sample samples/ApiDemos/src/com/google/app/Notification1.java Bleh}
49 public class SampleTagInfo extends TagInfo
51 static final int STATE_BEGIN = 0;
52 static final int STATE_MATCHING = 1;
54 static final Pattern TEXT = Pattern.compile(
55 "[\r\n \t]*([^\r\n \t]*)[\r\n \t]*([0-9A-Za-z_]*)[\r\n \t]*",
58 private static final String BEGIN_INCLUDE = "BEGIN_INCLUDE";
59 private static final String END_INCLUDE = "END_INCLUDE";
61 private ContainerInfo mBase;
62 private String mIncluded;
64 public static String escapeHtml(String str) {
65 return str.replace("&", "&").replace("<", "<").replace(">", ">");
68 private static boolean isIncludeLine(String str) {
69 return str.indexOf(BEGIN_INCLUDE)>=0 || str.indexOf(END_INCLUDE)>=0;
72 SampleTagInfo(String name, String kind, String text, ContainerInfo base,
73 SourcePositionInfo position)
75 super(name, kind, text, position);
78 Matcher m = TEXT.matcher(text);
80 Errors.error(Errors.BAD_INCLUDE_TAG, position, "Bad @include tag: "
84 String filename = m.group(1);
85 String id = m.group(2);
86 boolean trim = "@sample".equals(name);
88 if (id == null || "".equals(id)) {
89 mIncluded = readFile(position, filename, id, trim, true, false);
91 mIncluded = loadInclude(position, filename, id, trim);
94 if (mIncluded == null) {
95 Errors.error(Errors.BAD_INCLUDE_TAG, position, "include tag '" + id
96 + "' not found in file: " + filename);
100 static String getTrimString(String line)
103 int len = line.length();
105 char c = line.charAt(i);
106 if (c != ' ' && c != '\t') {
113 return line.substring(0, i);
117 static String loadInclude(SourcePositionInfo pos, String filename,
118 String id, boolean trim)
121 StringBuilder result = new StringBuilder();
123 String begin = BEGIN_INCLUDE + "(" + id + ")";
124 String end = END_INCLUDE + "(" + id + ")";
127 input = new FileReader(filename);
128 LineNumberReader lines = new LineNumberReader(input);
130 int state = STATE_BEGIN;
133 String trimString = null;
137 String line = lines.readLine();
143 if (line.indexOf(begin) >= 0) {
144 state = STATE_MATCHING;
148 if (line.indexOf(end) >= 0) {
149 return result.substring(0);
151 boolean empty = "".equals(line.trim());
153 if (isIncludeLine(line)) {
156 if (trimLength < 0 && !empty) {
157 trimString = getTrimString(line);
158 if (trimString != null) {
159 trimLength = trimString.length();
162 if (trimLength >= 0 && line.length() > trimLength) {
163 boolean trimThisLine = true;
164 for (int i=0; i<trimLength; i++) {
165 if (line.charAt(i) != trimString.charAt(i)){
166 trimThisLine = false;
171 line = line.substring(trimLength);
174 if (trimLength >= 0) {
176 for (int i=0; i<trailing; i++) {
179 line = escapeHtml(line);
181 trailing = 1; // add \n next time, maybe
195 catch (IOException e) {
196 Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
197 + " include \"" + id + "\" " + filename);
204 catch (IOException ex) {
208 Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Did not find " + end
209 + " in file " + filename);
213 static String readFile(SourcePositionInfo pos, String filename,
214 String id, boolean trim, boolean escape,
218 StringBuilder result = new StringBuilder();
220 boolean started = false;
222 input = new FileReader(filename);
223 LineNumberReader lines = new LineNumberReader(input);
226 String line = lines.readLine();
231 if (isIncludeLine(line)) {
234 if (!"".equals(line.trim())) {
236 for (int i=0; i<trailing; i++) {
241 line = escapeHtml(line);
244 trailing = 1; // add \n next time, maybe
257 catch (IOException e) {
261 Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
262 + " include \"" + id + "\" " + filename);
270 catch (IOException ex) {
274 return result.substring(0);
278 public void makeHDF(HDF data, String base)
280 data.setValue(base + ".name", name());
281 data.setValue(base + ".kind", kind());
282 if (mIncluded != null) {
283 data.setValue(base + ".text", mIncluded);
285 data.setValue(base + ".text", "INCLUDE_ERROR");