1 | /* |
2 | * $Id: ExamplesXmlBuilder.java,v 1.5 2005/12/01 06:10:00 hastings Exp $ |
3 | * |
4 | * (c) Copyright, Moebius Solutions, Inc., 2004 |
5 | * |
6 | * All Rights Reserved |
7 | * |
8 | * This material may be reproduced by or for the U. S. Government |
9 | * pursuant to the copyright license under the clause at |
10 | * DFARS 252.227-7014 (OCT 2001). |
11 | */ |
12 | package com.moesol.doc; |
13 | |
14 | import java.io.File; |
15 | import java.io.FileReader; |
16 | import java.io.IOException; |
17 | import java.io.OutputStream; |
18 | import java.io.PrintStream; |
19 | |
20 | /** |
21 | * Build an xml file that formats java code as xml |
22 | * Embedded comments |
23 | * <pre> |
24 | * // <frag |
25 | * // </frag |
26 | * </pre> |
27 | * are uncommented to mark fragment sections for inclusion |
28 | * in other documents. |
29 | * |
30 | * @author Hastings |
31 | */ |
32 | public class ExamplesXmlBuilder { |
33 | private int m_indent; |
34 | private PrintStream m_out = System.out; |
35 | private File m_dir = new File("."); |
36 | |
37 | /** |
38 | * @param files |
39 | * @throws IOException |
40 | */ |
41 | // <frag desc="doFiles"> |
42 | public void doFiles(String[] files) throws IOException { |
43 | // <frag desc="inner loop"> |
44 | for (int i = 0; i < files.length; i++) { |
45 | doFile(files[i]); |
46 | } |
47 | // </frag> |
48 | } |
49 | // </frag> |
50 | |
51 | public void startRoot() { |
52 | startEl("examples"); |
53 | } |
54 | |
55 | public void endRoot() { |
56 | endEl("examples"); |
57 | } |
58 | |
59 | private interface State { |
60 | public State process(int c); |
61 | } |
62 | private class StateStart implements State { |
63 | public State process(int c) { |
64 | if (c == '/') { |
65 | return m_one_slash; |
66 | } |
67 | if (c == '<') { |
68 | m_out.print("<"); |
69 | return this; |
70 | } |
71 | if (c == '>') { |
72 | m_out.print(">"); |
73 | return this; |
74 | } |
75 | if (c == '&') { |
76 | m_out.print("&"); |
77 | return this; |
78 | } |
79 | if (c == '\t') { |
80 | m_out.print(" "); |
81 | return this; |
82 | } |
83 | m_out.write(c); |
84 | return this; |
85 | } |
86 | } |
87 | private class StateOneSlash implements State { |
88 | public State process(int c) { |
89 | if (c == '/') { |
90 | return m_two_slash; |
91 | } |
92 | m_out.write('/'); |
93 | m_start.process(c); |
94 | return m_start; |
95 | } |
96 | } |
97 | private class StateTwoSlash implements State { |
98 | public State process(int c) { |
99 | if (c == ' ') { |
100 | return this; // collapse whitespace |
101 | } |
102 | if (c == '\t') { |
103 | return this; // collapse whitespace |
104 | } |
105 | if (c == '<') { |
106 | return m_two_and_lt; |
107 | } |
108 | // output missing stuff, may distort some comments |
109 | m_out.print("// "); |
110 | m_start.process(c); |
111 | return m_start; |
112 | } |
113 | } |
114 | /** |
115 | * State with sub-state tracking how far "frag" has been matched. |
116 | * |
117 | * @author Hastings |
118 | */ |
119 | private class StateTwoAndLt implements State { |
120 | private int m_match_so_far = 0; |
121 | private String m_to_match = "frag"; |
122 | private boolean m_is_end = false; |
123 | |
124 | public State process(int c) { |
125 | if (m_match_so_far == 0 && c == '/') { |
126 | m_is_end = true; |
127 | return this; |
128 | } |
129 | if (c == m_to_match.charAt(m_match_so_far)) { |
130 | return stillMatch(); |
131 | } |
132 | return noMatch(); |
133 | } |
134 | private State noMatch() { |
135 | m_out.print("// "); |
136 | for (int i = 0; i < m_match_so_far; i++) { |
137 | m_out.print(m_to_match.charAt(i)); |
138 | } |
139 | reset(); |
140 | return m_start; |
141 | } |
142 | private State stillMatch() { |
143 | m_match_so_far++; |
144 | if (m_match_so_far == m_to_match.length()) { |
145 | return foundFrag(); |
146 | } |
147 | return this; |
148 | } |
149 | private State foundFrag() { |
150 | // got them all |
151 | m_out.print('<'); |
152 | if (m_is_end) { |
153 | m_out.print('/'); |
154 | } |
155 | m_out.print(m_to_match); |
156 | reset(); |
157 | return m_found; |
158 | } |
159 | private void reset() { |
160 | m_match_so_far = 0; |
161 | m_is_end = false; |
162 | } |
163 | } |
164 | private class StateFoundFrag implements State { |
165 | public State process(int c) { |
166 | m_out.write(c); |
167 | if (c == '\n') { |
168 | return m_start; |
169 | } |
170 | return this; |
171 | } |
172 | } |
173 | private State m_start = new StateStart(); |
174 | private State m_one_slash = new StateOneSlash(); |
175 | private State m_two_slash = new StateTwoSlash(); |
176 | private State m_two_and_lt = new StateTwoAndLt(); |
177 | private State m_found = new StateFoundFrag(); |
178 | private State m_cur_state = m_start; |
179 | |
180 | /** |
181 | * @param fname |
182 | * @throws IOException |
183 | */ |
184 | private void doFile(String fname) throws IOException { |
185 | startEl("file", makeAttr("dir", m_dir.toString()) + " " + makeAttr("name", fname)); |
186 | |
187 | File full_path = new File(m_dir, fname); |
188 | FileReader r = new FileReader(full_path); |
189 | int c; |
190 | while ((c = r.read()) != -1) { |
191 | m_cur_state = m_cur_state.process(c); |
192 | } |
193 | endEl("file"); |
194 | } |
195 | |
196 | /** |
197 | * @param name |
198 | * @param value |
199 | * @return an attribute String of the form {@code name="value"}. |
200 | */ |
201 | private String makeAttr(String name, String value) { |
202 | StringBuffer sb = new StringBuffer(); |
203 | sb.append(name); |
204 | sb.append('='); |
205 | sb.append('"'); |
206 | sb.append(value); |
207 | sb.append('"'); |
208 | return sb.toString(); |
209 | } |
210 | |
211 | /** |
212 | * @param string |
213 | */ |
214 | private void endEl(String string) { |
215 | m_indent--; |
216 | printDent(); |
217 | m_out.println("</" + string + ">"); |
218 | } |
219 | |
220 | /** |
221 | * @param string |
222 | */ |
223 | private void startEl(String string) { |
224 | startEl(string, ""); |
225 | } |
226 | private void startEl(String el, String attrs) { |
227 | printDent(); |
228 | String attr_sep = attrs.length() == 0 ? "" : " "; |
229 | m_out.println("<" + el + attr_sep + attrs + ">"); |
230 | m_indent++; |
231 | } |
232 | |
233 | private void printDent() { |
234 | for (int i = 0; i < m_indent; i++) { |
235 | m_out.print(" "); |
236 | } |
237 | } |
238 | |
239 | /** |
240 | * @param args |
241 | */ |
242 | public static void main(String[] args) { |
243 | ExamplesXmlBuilder app = new ExamplesXmlBuilder(); |
244 | try { |
245 | app.doFiles(args); |
246 | } catch (IOException e) { |
247 | e.printStackTrace(System.err); |
248 | } |
249 | } |
250 | |
251 | /** |
252 | * @param out |
253 | */ |
254 | public void setOut(OutputStream out) { |
255 | if (out == null) { |
256 | m_out = System.out; |
257 | return; |
258 | } |
259 | m_out = new PrintStream(out); |
260 | } |
261 | |
262 | /** |
263 | * @param dir |
264 | */ |
265 | public void setDir(File dir) { |
266 | m_dir = dir; |
267 | } |
268 | } |