Back to index

lightning-sunbird  0.9+nobinonly
xpidl_doc.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "xpidl.h"
00039 
00040 /*
00041  * Generates documentation from javadoc-style comments in XPIDL files.
00042  */
00043 
00044 static gboolean
00045 doc_prolog(TreeState *state)
00046 {
00047     fprintf(state->file, "<html>\n");
00048     fprintf(state->file, "<head>\n");
00049 
00050     fprintf(state->file,
00051             "<!-- this file is generated from %s.idl -->\n",
00052             state->basename);
00053     fprintf(state->file, "<title>documentation for %s.idl interfaces</title>\n",
00054             state->basename);
00055     fprintf(state->file, "</head>\n\n");
00056     fprintf(state->file, "<body>\n");
00057 
00058     return TRUE;
00059 }
00060 
00061 static gboolean
00062 doc_epilog(TreeState *state)
00063 {
00064     fprintf(state->file, "</body>\n");
00065     fprintf(state->file, "</html>\n");
00066 
00067     return TRUE;
00068 }
00069 
00070 
00071 static gboolean
00072 doc_list(TreeState *state)
00073 {
00074     IDL_tree iter;
00075     for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
00076         state->tree = IDL_LIST(iter).data;
00077         if (!xpidl_process_node(state))
00078             return FALSE;
00079     }
00080     return TRUE;
00081 }
00082 
00083 static gboolean
00084 print_list(FILE *outfile, IDL_tree list)
00085 {
00086     if (list == NULL)
00087         return TRUE;
00088 
00089     fprintf(outfile, "<ul>\n");
00090     while (list != NULL) {
00091         fprintf(outfile, "    <li>%s\n",
00092                 IDL_IDENT(IDL_LIST(list).data).str);
00093         list = IDL_LIST(list).next;
00094     }
00095     fprintf(outfile, "</ul>\n");
00096     return TRUE;
00097 }
00098 
00099 static gboolean
00100 doc_interface(TreeState *state)
00101 {
00102     IDL_tree iface = state->tree;
00103     IDL_tree iter;
00104     IDL_tree orig;
00105     char *classname = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
00106     GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
00107 
00108     fprintf(state->file, "interface %s<br>\n", classname);
00109 
00110     /* Much more could happen at this step. */
00111     /*
00112      * If parsing doc comments, you might need to take some care with line
00113      * endings, as the xpidl frontend will return comments containing of /r,
00114      * /n, /r/n depending on the platform.  It's best to leave out platform
00115      * #defines and just treat them all as equivalent.
00116      */
00117     if (doc_comments != NULL) {
00118         fprintf(state->file, "doc comments:<br>\n");
00119         fprintf(state->file, "<pre>\n");
00120         printlist(state->file, doc_comments);
00121         fprintf(state->file, "</pre>\n");
00122         fprintf(state->file, "<br>\n");
00123     }
00124     
00125     /* inherits from */
00126     /*
00127      * Note that we accept multiple inheritance here (for e.g. gnome idl)
00128      * even though the header backend (specific to mozilla idl) rejects it.
00129      */
00130     if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
00131         fprintf(state->file, "%s inherits from:<br>\n", classname);
00132         print_list(state->file, iter);
00133         fprintf(state->file, "<br>\n");
00134     }
00135 
00136     /*
00137      * Call xpidl_process_node to recur through list of declarations in
00138      * interface body; another option would be to explicitly iterate through
00139      * the list.  xpidl_process_node currently requires twiddling the state to
00140      * get the right node; I'll fix that soon to just take the node.  Makes it
00141      * easier to follow what's going on, I think...
00142      */
00143     orig = state->tree;
00144     state->tree = IDL_INTERFACE(iface).body;
00145     if (state->tree && !xpidl_process_node(state))
00146         return FALSE;
00147     state->tree = orig;
00148 
00149     return TRUE;
00150 }
00151 
00152 /*
00153  * Copied from xpidl_header.c.  You'll probably want to change it; if you can
00154  * use it verbatim or abstract it, we could move it to xpidl_util.c and share
00155  * it from there.
00156  */
00157 static gboolean
00158 write_type(IDL_tree type_tree, FILE *outfile)
00159 {
00160     if (!type_tree) {
00161         fputs("void", outfile);
00162         return TRUE;
00163     }
00164 
00165     switch (IDL_NODE_TYPE(type_tree)) {
00166       case IDLN_TYPE_INTEGER: {
00167         gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
00168         switch (IDL_TYPE_INTEGER(type_tree).f_type) {
00169           case IDL_INTEGER_TYPE_SHORT:
00170             fputs(sign ? "PRInt16" : "PRUint16", outfile);
00171             break;
00172           case IDL_INTEGER_TYPE_LONG:
00173             fputs(sign ? "PRInt32" : "PRUint32", outfile);
00174             break;
00175           case IDL_INTEGER_TYPE_LONGLONG:
00176             fputs(sign ? "PRInt64" : "PRUint64", outfile);
00177             break;
00178           default:
00179             g_error("Unknown integer type %d\n",
00180                     IDL_TYPE_INTEGER(type_tree).f_type);
00181             return FALSE;
00182         }
00183         break;
00184       }
00185       case IDLN_TYPE_CHAR:
00186         fputs("char", outfile);
00187         break;
00188       case IDLN_TYPE_WIDE_CHAR:
00189         fputs("PRUnichar", outfile); /* wchar_t? */
00190         break;
00191       case IDLN_TYPE_WIDE_STRING:
00192         fputs("PRUnichar *", outfile);
00193         break;
00194       case IDLN_TYPE_STRING:
00195         fputs("char *", outfile);
00196         break;
00197       case IDLN_TYPE_BOOLEAN:
00198         fputs("PRBool", outfile);
00199         break;
00200       case IDLN_TYPE_OCTET:
00201         fputs("PRUint8", outfile);
00202         break;
00203       case IDLN_TYPE_FLOAT:
00204         switch (IDL_TYPE_FLOAT(type_tree).f_type) {
00205           case IDL_FLOAT_TYPE_FLOAT:
00206             fputs("float", outfile);
00207             break;
00208           case IDL_FLOAT_TYPE_DOUBLE:
00209             fputs("double", outfile);
00210             break;
00211           /* XXX 'long double' just ignored, or what? */
00212           default:
00213             fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
00214             break;
00215         }
00216         break;
00217       case IDLN_IDENT:
00218         if (UP_IS_NATIVE(type_tree)) {
00219             fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
00220             if (IDL_tree_property_get(type_tree, "ptr")) {
00221                 fputs(" *", outfile);
00222             } else if (IDL_tree_property_get(type_tree, "ref")) {
00223                 fputs(" &", outfile);
00224             }
00225         } else {
00226             fputs(IDL_IDENT(type_tree).str, outfile);
00227         }
00228         if (UP_IS_AGGREGATE(type_tree))
00229             fputs(" *", outfile);
00230         break;
00231       default:
00232         fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
00233         break;
00234     }
00235     return TRUE;
00236 }
00237 
00238 /* handle ATTR_DCL (attribute declaration) nodes */
00239 static gboolean
00240 doc_attribute_declaration(TreeState *state)
00241 {
00242     IDL_tree attr = state->tree;
00243 
00244     if (!verify_attribute_declaration(attr))
00245         return FALSE;
00246     /*
00247      * Attribute idents can also take doc comments.  They're ignored here;
00248      * should they be?
00249      */
00250 
00251     if (IDL_ATTR_DCL(attr).f_readonly)
00252         fprintf(state->file, "readonly ");
00253 
00254     fprintf(state->file, "attribute ");
00255 
00256     if (!write_type(IDL_ATTR_DCL(attr).param_type_spec, state->file))
00257         return FALSE;
00258 
00259     fprintf(state->file, "\n");
00260     print_list(state->file, IDL_ATTR_DCL(attr).simple_declarations);
00261     fprintf(state->file, "<br>\n");
00262 
00263     return TRUE;
00264 }
00265 
00266 /* handle OP_DCL (method declaration) nodes */
00267 static gboolean
00268 doc_method_declaration(TreeState *state)
00269 {
00270     /*
00271      * Doc comment for attributes also applies here.
00272      */
00273 
00274     /*
00275      * Look at 'write_method_signature' in xpidl_header.c for an example of how
00276      * to navigate parse trees for methods.  For here, I just print the method
00277      * name.
00278      */
00279 
00280     fprintf(state->file,
00281             "method %s<br>\n",
00282             IDL_IDENT(IDL_OP_DCL(state->tree).ident).str);
00283 
00284     return TRUE;
00285 }
00286 
00287 backend *
00288 xpidl_doc_dispatch(void)
00289 {
00290     static backend result;
00291     static nodeHandler table[IDLN_LAST];
00292     static gboolean initialized = FALSE;
00293 
00294     result.emit_prolog = doc_prolog;
00295     result.emit_epilog = doc_epilog;
00296 
00297     if (!initialized) {
00298         /* Initialize non-NULL elements */
00299 
00300         /* I just handle a few... many still to be filled in! */
00301 
00302         table[IDLN_LIST] = doc_list;
00303         table[IDLN_INTERFACE] = doc_interface;
00304         table[IDLN_ATTR_DCL] = doc_attribute_declaration;
00305         table[IDLN_OP_DCL] = doc_method_declaration;
00306 
00307         initialized = TRUE;
00308     }
00309   
00310     result.dispatch_table = table;
00311     return &result;
00312 }