OSDN Git Service

eclair snapshot
[android-x86/build.git] / tools / droiddoc / src / SampleTagInfo.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 import org.clearsilver.HDF;
18 import org.clearsilver.CS;
19
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;
26
27 /*
28  * SampleTagInfo copies text from a given file into the javadoc comment.
29  *
30  * The @include tag copies the text verbatim from the given file.
31  *
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.
35  *
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 (_).
41  *
42  * Four examples:
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}
47  *
48  */
49 public class SampleTagInfo extends TagInfo
50 {
51     static final int STATE_BEGIN = 0;
52     static final int STATE_MATCHING = 1;
53
54     static final Pattern TEXT = Pattern.compile(
55                 "[\r\n \t]*([^\r\n \t]*)[\r\n \t]*([0-9A-Za-z_]*)[\r\n \t]*",
56                 Pattern.DOTALL);
57
58     private static final String BEGIN_INCLUDE = "BEGIN_INCLUDE";
59     private static final String END_INCLUDE = "END_INCLUDE";
60
61     private ContainerInfo mBase;
62     private String mIncluded;
63
64     public static String escapeHtml(String str) {
65         return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
66     }
67
68     private static boolean isIncludeLine(String str) {
69         return str.indexOf(BEGIN_INCLUDE)>=0 || str.indexOf(END_INCLUDE)>=0;
70     }
71
72     SampleTagInfo(String name, String kind, String text, ContainerInfo base,
73             SourcePositionInfo position)
74     {
75         super(name, kind, text, position);
76         mBase = base;
77
78         Matcher m = TEXT.matcher(text);
79         if (!m.matches()) {
80             Errors.error(Errors.BAD_INCLUDE_TAG, position, "Bad @include tag: "
81                     + text);
82             return;
83         }
84         String filename = m.group(1);
85         String id = m.group(2);
86         boolean trim = "@sample".equals(name);
87
88         if (id == null || "".equals(id)) {
89             mIncluded = readFile(position, filename, id, trim, true, false);
90         } else {
91             mIncluded = loadInclude(position, filename, id, trim);
92         }
93
94         if (mIncluded == null) {
95             Errors.error(Errors.BAD_INCLUDE_TAG, position, "include tag '" + id
96                     + "' not found in file: " + filename);
97         }
98     }
99
100     static String getTrimString(String line)
101     {
102         int i = 0;
103         int len = line.length();
104         for (; i<len; i++) {
105             char c = line.charAt(i);
106             if (c != ' ' && c != '\t') {
107                 break;
108             }
109         }
110         if (i == len) {
111             return null;
112         } else {
113             return line.substring(0, i);
114         }
115     }
116
117     static String loadInclude(SourcePositionInfo pos, String filename,
118                                 String id, boolean trim)
119     {
120         Reader input = null;
121         StringBuilder result = new StringBuilder();
122
123         String begin = BEGIN_INCLUDE + "(" + id + ")";
124         String end = END_INCLUDE + "(" + id + ")";
125
126         try {
127             input = new FileReader(filename);
128             LineNumberReader lines = new LineNumberReader(input);
129
130             int state = STATE_BEGIN;
131
132             int trimLength = -1;
133             String trimString = null;
134             int trailing = 0;
135
136             while (true) {
137                 String line = lines.readLine();
138                 if (line == null) {
139                     return null;
140                 }
141                 switch (state) {
142                 case STATE_BEGIN:
143                     if (line.indexOf(begin) >= 0) {
144                         state = STATE_MATCHING;
145                     }
146                     break;
147                 case STATE_MATCHING:
148                     if (line.indexOf(end) >= 0) {
149                         return result.substring(0);
150                     } else {
151                         boolean empty = "".equals(line.trim());
152                         if (trim) {
153                             if (isIncludeLine(line)) {
154                                 continue;
155                             }
156                             if (trimLength < 0 && !empty) {
157                                 trimString = getTrimString(line);
158                                 if (trimString != null) {
159                                     trimLength = trimString.length();
160                                 }
161                             }
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;
167                                         break;
168                                     }
169                                 }
170                                 if (trimThisLine) {
171                                     line = line.substring(trimLength);
172                                 }
173                             }
174                             if (trimLength >= 0) {
175                                 if (!empty) {
176                                     for (int i=0; i<trailing; i++) {
177                                         result.append('\n');
178                                     }
179                                     line = escapeHtml(line);
180                                     result.append(line);
181                                     trailing = 1;  // add \n next time, maybe
182                                 } else {
183                                     trailing++;
184                                 }
185                             }
186                         } else {
187                             result.append(line);
188                             result.append('\n');
189                         }
190                     }
191                     break;
192                 }
193             }
194         }
195         catch (IOException e) {
196             Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
197                     + " include \"" + id + "\" " + filename);
198         }
199         finally {
200             if (input != null) {
201                 try {
202                     input.close();
203                 }
204                 catch (IOException ex) {
205                 }
206             }
207         }
208         Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Did not find " + end
209                 + " in file " + filename);
210         return null;
211     }
212
213     static String readFile(SourcePositionInfo pos, String filename,
214                                 String id, boolean trim, boolean escape,
215                                 boolean errorOk)
216     {
217         Reader input = null;
218         StringBuilder result = new StringBuilder();
219         int trailing = 0;
220         boolean started = false;
221         try {
222             input = new FileReader(filename);
223             LineNumberReader lines = new LineNumberReader(input);
224
225             while (true) {
226                 String line = lines.readLine();
227                 if (line == null) {
228                     break;
229                 }
230                 if (trim) {
231                     if (isIncludeLine(line)) {
232                         continue;
233                     }
234                     if (!"".equals(line.trim())) {
235                         if (started) {
236                             for (int i=0; i<trailing; i++) {
237                                 result.append('\n');
238                             }
239                         }
240                         if (escape) {
241                             line = escapeHtml(line);
242                         }
243                         result.append(line);
244                         trailing = 1;  // add \n next time, maybe
245                         started = true;
246                     } else {
247                         if (started) {
248                             trailing++;
249                         }
250                     }
251                 } else {
252                     result.append(line);
253                     result.append('\n');
254                 }
255             }
256         }
257         catch (IOException e) {
258             if (errorOk) {
259                 return null;
260             } else {
261                 Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
262                         + " include \"" + id + "\" " + filename);
263             }
264         }
265         finally {
266             if (input != null) {
267                 try {
268                     input.close();
269                 }
270                 catch (IOException ex) {
271                 }
272             }
273         }
274         return result.substring(0);
275     }
276
277     @Override
278     public void makeHDF(HDF data, String base)
279     {
280         data.setValue(base + ".name", name());
281         data.setValue(base + ".kind", kind());
282         if (mIncluded != null) {
283             data.setValue(base + ".text", mIncluded);
284         } else {
285             data.setValue(base + ".text", "INCLUDE_ERROR");
286         }
287     }
288 }
289