1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
---|
2 | /* ***** BEGIN LICENSE BLOCK *****
|
---|
3 | * Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | *
|
---|
5 | * The contents of this file are subject to the Netscape Public License
|
---|
6 | * Version 1.1 (the "License"); you may not use this file except in
|
---|
7 | * compliance with the License. You may obtain a copy of the License at
|
---|
8 | * http://www.mozilla.org/NPL/
|
---|
9 | *
|
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | * for the specific language governing rights and limitations under the
|
---|
13 | * License.
|
---|
14 | *
|
---|
15 | * The Original Code is mozilla.org code.
|
---|
16 | *
|
---|
17 | * The Initial Developer of the Original Code is
|
---|
18 | * Netscape Communications Corporation.
|
---|
19 | * Portions created by the Initial Developer are Copyright (C) 1998
|
---|
20 | * the Initial Developer. All Rights Reserved.
|
---|
21 | *
|
---|
22 | * Contributor(s):
|
---|
23 | *
|
---|
24 | * Alternatively, the contents of this file may be used under the terms of
|
---|
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
|
---|
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
28 | * of those above. If you wish to allow use of your version of this file only
|
---|
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
30 | * use your version of this file under the terms of the NPL, indicate your
|
---|
31 | * decision by deleting the provisions above and replace them with the notice
|
---|
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
33 | * the provisions above, a recipient may use your version of this file under
|
---|
34 | * the terms of any one of the NPL, the GPL or the LGPL.
|
---|
35 | *
|
---|
36 | * ***** END LICENSE BLOCK ***** */
|
---|
37 |
|
---|
38 | #include "xpidl.h"
|
---|
39 |
|
---|
40 | /*
|
---|
41 | * Generates documentation from javadoc-style comments in XPIDL files.
|
---|
42 | */
|
---|
43 |
|
---|
44 | static gboolean
|
---|
45 | doc_prolog(TreeState *state)
|
---|
46 | {
|
---|
47 | fprintf(state->file, "<html>\n");
|
---|
48 | fprintf(state->file, "<head>\n");
|
---|
49 |
|
---|
50 | fprintf(state->file,
|
---|
51 | "<!-- this file is generated from %s.idl -->\n",
|
---|
52 | state->basename);
|
---|
53 | fprintf(state->file, "<title>documentation for %s.idl interfaces</title>\n",
|
---|
54 | state->basename);
|
---|
55 | fprintf(state->file, "</head>\n\n");
|
---|
56 | fprintf(state->file, "<body>\n");
|
---|
57 |
|
---|
58 | return TRUE;
|
---|
59 | }
|
---|
60 |
|
---|
61 | static gboolean
|
---|
62 | doc_epilog(TreeState *state)
|
---|
63 | {
|
---|
64 | fprintf(state->file, "</body>\n");
|
---|
65 | fprintf(state->file, "</html>\n");
|
---|
66 |
|
---|
67 | return TRUE;
|
---|
68 | }
|
---|
69 |
|
---|
70 |
|
---|
71 | static gboolean
|
---|
72 | doc_list(TreeState *state)
|
---|
73 | {
|
---|
74 | IDL_tree iter;
|
---|
75 | for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
|
---|
76 | state->tree = IDL_LIST(iter).data;
|
---|
77 | if (!xpidl_process_node(state))
|
---|
78 | return FALSE;
|
---|
79 | }
|
---|
80 | return TRUE;
|
---|
81 | }
|
---|
82 |
|
---|
83 | static gboolean
|
---|
84 | print_list(FILE *outfile, IDL_tree list)
|
---|
85 | {
|
---|
86 | if (list == NULL)
|
---|
87 | return TRUE;
|
---|
88 |
|
---|
89 | fprintf(outfile, "<ul>\n");
|
---|
90 | while (list != NULL) {
|
---|
91 | fprintf(outfile, " <li>%s\n",
|
---|
92 | IDL_IDENT(IDL_LIST(list).data).str);
|
---|
93 | list = IDL_LIST(list).next;
|
---|
94 | }
|
---|
95 | fprintf(outfile, "</ul>\n");
|
---|
96 | return TRUE;
|
---|
97 | }
|
---|
98 |
|
---|
99 | static gboolean
|
---|
100 | doc_interface(TreeState *state)
|
---|
101 | {
|
---|
102 | IDL_tree iface = state->tree;
|
---|
103 | IDL_tree iter;
|
---|
104 | IDL_tree orig;
|
---|
105 | char *classname = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
|
---|
106 | GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
|
---|
107 |
|
---|
108 | fprintf(state->file, "interface %s<br>\n", classname);
|
---|
109 |
|
---|
110 | /* Much more could happen at this step. */
|
---|
111 | /*
|
---|
112 | * If parsing doc comments, you might need to take some care with line
|
---|
113 | * endings, as the xpidl frontend will return comments containing of /r,
|
---|
114 | * /n, /r/n depending on the platform. It's best to leave out platform
|
---|
115 | * #defines and just treat them all as equivalent.
|
---|
116 | */
|
---|
117 | if (doc_comments != NULL) {
|
---|
118 | fprintf(state->file, "doc comments:<br>\n");
|
---|
119 | fprintf(state->file, "<pre>\n");
|
---|
120 | printlist(state->file, doc_comments);
|
---|
121 | fprintf(state->file, "</pre>\n");
|
---|
122 | fprintf(state->file, "<br>\n");
|
---|
123 | }
|
---|
124 |
|
---|
125 | /* inherits from */
|
---|
126 | /*
|
---|
127 | * Note that we accept multiple inheritance here (for e.g. gnome idl)
|
---|
128 | * even though the header backend (specific to mozilla idl) rejects it.
|
---|
129 | */
|
---|
130 | if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
|
---|
131 | fprintf(state->file, "%s inherits from:<br>\n", classname);
|
---|
132 | print_list(state->file, iter);
|
---|
133 | fprintf(state->file, "<br>\n");
|
---|
134 | }
|
---|
135 |
|
---|
136 | /*
|
---|
137 | * Call xpidl_process_node to recur through list of declarations in
|
---|
138 | * interface body; another option would be to explicitly iterate through
|
---|
139 | * the list. xpidl_process_node currently requires twiddling the state to
|
---|
140 | * get the right node; I'll fix that soon to just take the node. Makes it
|
---|
141 | * easier to follow what's going on, I think...
|
---|
142 | */
|
---|
143 | orig = state->tree;
|
---|
144 | state->tree = IDL_INTERFACE(iface).body;
|
---|
145 | if (state->tree && !xpidl_process_node(state))
|
---|
146 | return FALSE;
|
---|
147 | state->tree = orig;
|
---|
148 |
|
---|
149 | return TRUE;
|
---|
150 | }
|
---|
151 |
|
---|
152 | /*
|
---|
153 | * Copied from xpidl_header.c. You'll probably want to change it; if you can
|
---|
154 | * use it verbatim or abstract it, we could move it to xpidl_util.c and share
|
---|
155 | * it from there.
|
---|
156 | */
|
---|
157 | static gboolean
|
---|
158 | write_type(IDL_tree type_tree, FILE *outfile)
|
---|
159 | {
|
---|
160 | if (!type_tree) {
|
---|
161 | fputs("void", outfile);
|
---|
162 | return TRUE;
|
---|
163 | }
|
---|
164 |
|
---|
165 | switch (IDL_NODE_TYPE(type_tree)) {
|
---|
166 | case IDLN_TYPE_INTEGER: {
|
---|
167 | gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
|
---|
168 | switch (IDL_TYPE_INTEGER(type_tree).f_type) {
|
---|
169 | case IDL_INTEGER_TYPE_SHORT:
|
---|
170 | fputs(sign ? "PRInt16" : "PRUint16", outfile);
|
---|
171 | break;
|
---|
172 | case IDL_INTEGER_TYPE_LONG:
|
---|
173 | fputs(sign ? "PRInt32" : "PRUint32", outfile);
|
---|
174 | break;
|
---|
175 | case IDL_INTEGER_TYPE_LONGLONG:
|
---|
176 | fputs(sign ? "PRInt64" : "PRUint64", outfile);
|
---|
177 | break;
|
---|
178 | default:
|
---|
179 | g_error("Unknown integer type %d\n",
|
---|
180 | IDL_TYPE_INTEGER(type_tree).f_type);
|
---|
181 | return FALSE;
|
---|
182 | }
|
---|
183 | break;
|
---|
184 | }
|
---|
185 | case IDLN_TYPE_CHAR:
|
---|
186 | fputs("char", outfile);
|
---|
187 | break;
|
---|
188 | case IDLN_TYPE_WIDE_CHAR:
|
---|
189 | fputs("PRUnichar", outfile); /* wchar_t? */
|
---|
190 | break;
|
---|
191 | case IDLN_TYPE_WIDE_STRING:
|
---|
192 | fputs("PRUnichar *", outfile);
|
---|
193 | break;
|
---|
194 | case IDLN_TYPE_STRING:
|
---|
195 | fputs("char *", outfile);
|
---|
196 | break;
|
---|
197 | case IDLN_TYPE_BOOLEAN:
|
---|
198 | fputs("PRBool", outfile);
|
---|
199 | break;
|
---|
200 | case IDLN_TYPE_OCTET:
|
---|
201 | fputs("PRUint8", outfile);
|
---|
202 | break;
|
---|
203 | case IDLN_TYPE_FLOAT:
|
---|
204 | switch (IDL_TYPE_FLOAT(type_tree).f_type) {
|
---|
205 | case IDL_FLOAT_TYPE_FLOAT:
|
---|
206 | fputs("float", outfile);
|
---|
207 | break;
|
---|
208 | case IDL_FLOAT_TYPE_DOUBLE:
|
---|
209 | fputs("double", outfile);
|
---|
210 | break;
|
---|
211 | /* XXX 'long double' just ignored, or what? */
|
---|
212 | default:
|
---|
213 | fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
|
---|
214 | break;
|
---|
215 | }
|
---|
216 | break;
|
---|
217 | case IDLN_IDENT:
|
---|
218 | if (UP_IS_NATIVE(type_tree)) {
|
---|
219 | fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
|
---|
220 | if (IDL_tree_property_get(type_tree, "ptr")) {
|
---|
221 | fputs(" *", outfile);
|
---|
222 | } else if (IDL_tree_property_get(type_tree, "ref")) {
|
---|
223 | fputs(" &", outfile);
|
---|
224 | }
|
---|
225 | } else {
|
---|
226 | fputs(IDL_IDENT(type_tree).str, outfile);
|
---|
227 | }
|
---|
228 | if (UP_IS_AGGREGATE(type_tree))
|
---|
229 | fputs(" *", outfile);
|
---|
230 | break;
|
---|
231 | default:
|
---|
232 | fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
|
---|
233 | break;
|
---|
234 | }
|
---|
235 | return TRUE;
|
---|
236 | }
|
---|
237 |
|
---|
238 | /* handle ATTR_DCL (attribute declaration) nodes */
|
---|
239 | static gboolean
|
---|
240 | doc_attribute_declaration(TreeState *state)
|
---|
241 | {
|
---|
242 | IDL_tree attr = state->tree;
|
---|
243 |
|
---|
244 | if (!verify_attribute_declaration(attr))
|
---|
245 | return FALSE;
|
---|
246 | /*
|
---|
247 | * Attribute idents can also take doc comments. They're ignored here;
|
---|
248 | * should they be?
|
---|
249 | */
|
---|
250 |
|
---|
251 | if (IDL_ATTR_DCL(attr).f_readonly)
|
---|
252 | fprintf(state->file, "readonly ");
|
---|
253 |
|
---|
254 | fprintf(state->file, "attribute ");
|
---|
255 |
|
---|
256 | if (!write_type(IDL_ATTR_DCL(attr).param_type_spec, state->file))
|
---|
257 | return FALSE;
|
---|
258 |
|
---|
259 | fprintf(state->file, "\n");
|
---|
260 | print_list(state->file, IDL_ATTR_DCL(attr).simple_declarations);
|
---|
261 | fprintf(state->file, "<br>\n");
|
---|
262 |
|
---|
263 | return TRUE;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /* handle OP_DCL (method declaration) nodes */
|
---|
267 | static gboolean
|
---|
268 | doc_method_declaration(TreeState *state)
|
---|
269 | {
|
---|
270 | /*
|
---|
271 | * Doc comment for attributes also applies here.
|
---|
272 | */
|
---|
273 |
|
---|
274 | /*
|
---|
275 | * Look at 'write_method_signature' in xpidl_header.c for an example of how
|
---|
276 | * to navigate parse trees for methods. For here, I just print the method
|
---|
277 | * name.
|
---|
278 | */
|
---|
279 |
|
---|
280 | fprintf(state->file,
|
---|
281 | "method %s<br>\n",
|
---|
282 | IDL_IDENT(IDL_OP_DCL(state->tree).ident).str);
|
---|
283 |
|
---|
284 | return TRUE;
|
---|
285 | }
|
---|
286 |
|
---|
287 | backend *
|
---|
288 | xpidl_doc_dispatch(void)
|
---|
289 | {
|
---|
290 | static backend result;
|
---|
291 | static nodeHandler table[IDLN_LAST];
|
---|
292 | static gboolean initialized = FALSE;
|
---|
293 |
|
---|
294 | result.emit_prolog = doc_prolog;
|
---|
295 | result.emit_epilog = doc_epilog;
|
---|
296 |
|
---|
297 | if (!initialized) {
|
---|
298 | /* Initialize non-NULL elements */
|
---|
299 |
|
---|
300 | /* I just handle a few... many still to be filled in! */
|
---|
301 |
|
---|
302 | table[IDLN_LIST] = doc_list;
|
---|
303 | table[IDLN_INTERFACE] = doc_interface;
|
---|
304 | table[IDLN_ATTR_DCL] = doc_attribute_declaration;
|
---|
305 | table[IDLN_OP_DCL] = doc_method_declaration;
|
---|
306 |
|
---|
307 | initialized = TRUE;
|
---|
308 | }
|
---|
309 |
|
---|
310 | result.dispatch_table = table;
|
---|
311 | return &result;
|
---|
312 | }
|
---|