################################################################## ## GenCIDocs.py ## XPCOM Component Interface HTML Reference ## Generator ## ## Version 0.8, 23-Feb-2001 ## ## About: ## Generates html documentation for ## all registered XPCOM components ## and interfaces. ## ## Requirements: ## Requires PyXPCOM ## http://www.activestate.com/Products/Komodo/PyXPCOM/ ## Tested on WinNT4 but should work everywhere ## where PyXPCOM works. ## ## Usage: ## Takes no parameters. Execute ## directly to produce all html ## docs in current directory ## ## Warning: Built incrementally ## with focus only on getting results ## (read as: dirty code and bad design, ## but copyright anyway :-) ## ## Todo: ## - Templatize html generation so ## style of produced html pages ## can be easily changed ## - Generate docs only for a specified ## set of interfaces and/or components ## - Think about producing XML instead ## - Also generate a frames version ## - Give more info in generated docs: ## - library filename (.dll or .so) ## containing a component ## - typelib filename (.xpt) contaning ## an interface definition ## ## Copyright (c) 2001, Shalabh Chaturvedi ## ## Released under the MPLv1.1 ## http://www.mozilla.org/MPL/MPL-1.1.html ## ################################################################## import glob import os import sys import string import re from xpcom import components from xpcom import xpt import xpcom ####################################### ## ## HTML snippet generation functions ## ####################################### def get_links_html(): return """

All interfaces | Interfaces hierarchy | All components

""" def get_html_hierarchy_snippet(interface): global interfaces2interfaces html = "" if interfaces2interfaces.has_key(interface): for child in interfaces2interfaces[interface]: html = html + get_html_hierarchy_snippet(child) html = """""" % (interface,interface,html) return html def get_interface_basicinfo_html(interface): global interfaces2interfaces parent = interface.GetParent() if parent!=None: parent = parent.GetName() parents = '%s ' % (parent,parent) else: parents ="None" children = "None" if interfaces2interfaces.has_key(interface.GetName()): children = interfaces2interfaces[interface.GetName()] children = string.join(map(lambda x: " %s" % (x,x), children),',') iid = 'Unknown' iid = '%s' % ( interface.GetIID()) if interface.IsScriptable(): scriptable = 'Scriptable' else: scriptable = 'Not scriptable' info_html = """
IID %s
Parents %s
Children %s
%s
""" % (iid,parents,children, scriptable) return info_html def get_interface_methods_attributes_html(interface): global interfaces_list interface_methods_html = "" methods = xpt.Methods(interface) startnum = 0 if interface.GetName() != 'nsISupports': startnum = 3 attributesinfo = {} for i in range(startnum ,len(methods)): # leave out first 3 (queryinterface etc) for all except nsISupports m = methods[i] returntype = xpt.TypeDescriber(m.result_desc[0],None).Describe() if returntype in interfaces_list : returntype = '%s' % (returntype, returntype) name = m.name isAttribute = 0 if m.IsGetter() or m.IsSetter(): isAttribute = 1 if not attributesinfo.has_key(name): attributesinfo[name] = {} if m.IsGetter(): attributesinfo[name]['read'] = 1 attributesinfo[name]['type'] = xpt.TypeDescriber(m.params[0].type_desc[0],m.params[0]).Describe() if m.IsSetter(): attributesinfo[name]['write'] = 1 attributesinfo[name]['type'] = xpt.TypeDescriber(m.params[0].type_desc[0],m.params[0]).Describe() if not isAttribute: parameters = [] for p in m.params: pdesc = p.Describe() pparts = string.split(pdesc,' ') for i in range(0,len(pparts)): part = pparts[i] if part in interfaces_list: pparts[i]= '%s' % (part,part) parameters.append(string.join(pparts,' ')) parameters = string.join(parameters,',') interface_methods_html = interface_methods_html + """ %s %s (%s) """ % (returntype,name,parameters) if interface_methods_html == "": interface_methods_html = "None" else: interface_methods_html = """ %s
""" % (interface_methods_html) interface_attributes_html = "" for a in attributesinfo.keys(): attrtype = attributesinfo[a]['type'] if attrtype in interfaces_list: attrtype = '%s' % (attrtype, attrtype) flags = '' if attributesinfo[a].has_key('read'): if attributesinfo[a].has_key('write'): flags = '' else: flags = 'read-only' elif attributesinfo[a].has_key('write'): flags = 'write-only' interface_attributes_html = interface_attributes_html + """ %s %s %s """ % (attrtype,a,flags) if interface_attributes_html == "": interface_attributes_html = "None" else: interface_attributes_html = """ %s
""" % (interface_attributes_html) return (interface_methods_html, interface_attributes_html) def get_interface_constants_html(interface): interface_constants_html = "" cs = xpt.Constants(interface) for c in cs: interface_constants_html = interface_constants_html +""" %s """ % (c.Describe()) if interface_constants_html == "": interface_constants_html = "None" else: interface_constants_html = """ %s
""" % (interface_constants_html) return interface_constants_html def get_interface_components_html(interface): global interfaces2components ifacename = interface.GetName() if not interfaces2components.has_key(ifacename): return "None" html = reduce(lambda x,y: x + '%s\n' % (anotherNameFromContractID(y),y),interfaces2components[ifacename],'') html = """ %s
""" % (html) return html def get_component_basicinfo_html(contractid): clsid = "%s" % (components.classes[contractid].clsid) info_html = """
CLSID %s
""" % (clsid[1:-1]) return info_html def get_component_interfaces_html(contractid): global components2interfaces if not components2interfaces.has_key(contractid): return "None" html = reduce(lambda x,y: x + '%s\n' % (y,y),components2interfaces[contractid],'') html = """ %s
""" % (html) return html ##################################### ## ## HTML file generation functions ## ##################################### def generateInterfacesHierarchyFile(): "Creates interfaces_hierarchy.html" interfacesdone = {} f = open('interfaces-hierarchy.html','w') html = """ All Interfaces Hierarchy %s

Interfaces Hierarchy

%s %s """ % (get_links_html(),get_html_hierarchy_snippet('nsISupports'),get_links_html()) f.write(html) f.close() def generateComponentsHtmlFiles(): "Generates components.html and all components pages" l = components.classes.keys() l.sort() components_links_html = '' count = 1 for n in l: components_links_html = components_links_html + "%s %s\n" % (count, anotherNameFromContractID(n),n) count = count + 1 all_components_html = """ All Components %s

All Components

%s

%s """ % (get_links_html(),components_links_html,get_links_html()) f = open('components.html','w') f.write(all_components_html) f.close() for c in components.classes.keys(): components_html = """ Component: %s %s

%s

%s

Implements Interfaces

%s %s """ % (c,get_links_html(),c,get_component_basicinfo_html(c),get_component_interfaces_html(c),get_links_html()) filename = anotherNameFromContractID(c) + '.html' print 'Writing',filename f = open(filename, "w") f.write(components_html) f.close() def generateInterfacesHtmlFiles(): "Generates interfaces.html and all interfaces pages" l = components.interfaces.keys() l.sort() interfaces_links_html = '' count = 1 for n in l: interfaces_links_html = interfaces_links_html + "%s%s\n" % (count,n,n) count = count + 1 all_interfaces_html = """ All Interfaces %s

All Interfaces

%s

%s """ % (get_links_html(),interfaces_links_html,get_links_html()) f = open('interfaces.html','w') f.write(all_interfaces_html) f.close() for iface in components.interfaces.keys(): ifaceobject = xpt.Interface(iface) interface_html = """ Interface: %s %s

%s

%s

Methods

%s

Attributes

%s

Constants

%s

Implemented by Components

%s %s """ % (iface,get_links_html(),iface, get_interface_basicinfo_html(ifaceobject), get_interface_methods_attributes_html(ifaceobject)[0], get_interface_methods_attributes_html(ifaceobject)[1], get_interface_constants_html(ifaceobject), get_interface_components_html(ifaceobject), get_links_html()) print 'Writing',iface+'.html' f = open(iface+'.html','w') f.write(interface_html) f.close() def anotherNameFromContractID(contractID): "Converts all funny charachters in contractID to '-' (so the name can be used as a filename)" name = re.sub('\\W','',contractID,1) name = re.sub('\\W',"-",name) return name ################################## ## ## Relation determining functions ## ################################## def createInterfacesComponentsRelations(): global interfaces2components,components2interfaces, crashers allifaces = components.interfaces.keys() for c in components.classes.keys(): if c not in crashers: l = getSupportedInterfaceNames(c,allifaces) components2interfaces[c] = l for ifacename in l: if not interfaces2components.has_key(ifacename): interfaces2components[ifacename] = [] interfaces2components[ifacename].append(c) def createInterfacesInterfacesRelation(): global interfaces2interfaces for i in components.interfaces.keys(): iface = xpt.Interface(i) p = iface.GetParent() if p is not None: pname = p.GetName() if not interfaces2interfaces.has_key(pname): interfaces2interfaces[pname] = [] interfaces2interfaces[pname].append(i) def getSupportedInterfaceNames(contractID, interfaceNamesList): "Returns a list of supported interfaces for a component" if not len(contractID): return [] try: c = components.classes[contractID] o = c.createInstance() except: print 'failed to check component:', contractID return [] supportedInterfaceNames = [] for i in interfaceNamesList: try: iface = components.interfaces[i] o.queryInterface(iface) supportedInterfaceNames.append(i) except: pass return supportedInterfaceNames ################################## ## ## Global variables ## ################################## interfaces2components = {} components2interfaces = {} interfaces2interfaces = {} interfaces_list = components.interfaces.keys() # crashers are components that crash xpcom when # queryInterfaced, as a result crash this script # midway through crashers = ['@mozilla.org/addressbook/services/addbookurl;1', '@mozilla.org/rdf/resource-factory;1?name=imap_message', '@mozilla.org/messenger/msgFolderCache;1', '@mozilla.org/messenger/nntpnewsgrouplist;1', '@mozilla.org/rdf/resource-factory;1?name=imap', '@mozilla.org/rdf/resource-factory;1?name=mailbox', '@mozilla.org/rdf/resource-factory;1?name=dom', '@mozilla.org/rdf/resource-factory;1?name=abcard', '@mozilla.org/rdf/resource-factory;1?name=mailbox_message', '@mozilla.org/appshell/component/unknownContentType;1', '@mozilla.org/rdf/resource-factory;1?name=abdirectory', '@mozilla.org/messenger/server;1?type=nntp', '@mozilla.org/rdf/resource-factory;1?name=news', '@mozilla.org/thread-pool;1', '@mozilla.org/rdf/resource-factory;1?name=news_message'] def main(): print "Checking components for supported interfaces..." createInterfacesComponentsRelations() print "Figuring relation between interfaces..." createInterfacesInterfacesRelation() print "Generating Interfaces Hierarchy page..." generateInterfacesHierarchyFile() print "Generating Interfaces pages..." generateInterfacesHtmlFiles() print "Generating Components pages..." generateComponentsHtmlFiles() print "Done" main()