ebd563cd29ee8029ce0ffc26e01439f701cb4237
[WebKit-https.git] / Tools / gtk / webkitdom.py
1 #!/usr/bin/env python
2 # Copyright (C) 2013 Igalia S.L.
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 # 02110-1301  USA
18
19 import common
20 import errno
21 import os
22 import re
23 import sys
24
25 from ConfigParser import SafeConfigParser
26
27
28 class WebKitDOMDocGenerator(object):
29
30     def __init__(self, symbol_files, file_handle):
31         self._symbol_files = symbol_files
32         self._file_handle = file_handle
33
34     def write_header(self):
35         pass
36
37     def write_section(self, symbol_file):
38         raise NotImplementedError
39
40     def write_footer(self):
41         pass
42
43     def write(self, string):
44         self._file_handle.write(string)
45
46     def generate(self):
47         self.write_header()
48         for symbol_file in self._symbol_files:
49             self.write_section(symbol_file)
50         self.write_footer()
51
52
53 class WebKitDOMDocGeneratorSGML(WebKitDOMDocGenerator):
54     def write_header(self):
55         self.write('''<?xml version="1.0"?>
56 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
57                "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
58 <!ENTITY version SYSTEM "version.xml">
59 ]>
60 <book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
61   <bookinfo>
62     <title>WebKitDOMGTK+ Reference Manual</title>
63     <releaseinfo>for WebKitDOMGTK+ &version;</releaseinfo>
64   </bookinfo>
65
66   <chapter>
67     <title>Class Overview</title>
68 ''')
69
70     def write_section(self, symbol_file):
71         basename = os.path.basename(symbol_file)
72         self.write('    <xi:include href="xml/%s"/>\n' % basename.replace(".symbols", ".xml"))
73
74     def write_footer(self):
75         self.write('''  </chapter>
76
77   <index id="index-all">
78     <title>Index</title>
79     <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
80   </index>
81
82   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
83 </book>
84 ''')
85
86
87 class WebKitDOMDocGeneratorSections(WebKitDOMDocGenerator):
88     def __init__(self, symbol_files, file_handle):
89         super(WebKitDOMDocGeneratorSections, self).__init__(symbol_files, file_handle)
90
91         self._first_decamelize_re = re.compile('(.)([A-Z][a-z]+)')
92         self._second_decamelize_re = re.compile('([a-z0-9])([A-Z])')
93         self._dom_class_re = re.compile('(^WebKitDOM)(.+)$')
94         self._function_re = re.compile('^.+ (.+)\((.+)\)$')
95         self._constant_re = re.compile('^[A-Z_]+$')
96
97     def _dom_class(self, class_name):
98         return self._dom_class_re.sub(r'\2', class_name)
99
100     def _dom_class_decamelize(self, class_name):
101         s1 = self._first_decamelize_re.sub(r'\1_\2', self._dom_class(class_name))
102         retval = self._second_decamelize_re.sub(r'\1_\2', s1)
103
104         # Fix some exceptions.
105         retval = retval.replace('Web_Kit', 'WebKit')
106         retval = retval.replace('X_Path', 'XPath')
107         retval = retval.replace('HTMLI_Frame', 'HTML_IFrame')
108         retval = retval.replace('HTMLBR', 'HTML_BR')
109         retval = retval.replace('HTMLHR', 'HTML_HR')
110         retval = retval.replace('HTMLLI', 'HTML_LI')
111         retval = retval.replace('HTMLD', 'HTML_D')
112         retval = retval.replace('HTMLO', 'HTML_O')
113         retval = retval.replace('HTMLU', 'HTML_U')
114
115         return retval
116
117     def _symbol_list(self, symbol_file):
118         retval = []
119         f = open(symbol_file, 'r')
120         for line in f.readlines():
121             match = self._constant_re.match(line)
122             if match:
123                 retval.append(line.strip('\n'))
124                 continue
125
126             match = self._function_re.match(line)
127             if not match or match.group(1).endswith('get_type'):
128                 continue
129             retval.append(match.group(1))
130
131         return retval
132
133     def write_section(self, symbol_file):
134         class_name = os.path.basename(symbol_file).replace(".symbols", "")
135         is_custom = class_name == 'WebKitDOMCustom'
136         is_interface = class_name in ['WebKitDOMEventTarget', 'WebKitDOMNodeFilter', 'WebKitDOMXPathNSResolver']
137         is_object = class_name == 'WebKitDOMObject'
138         self.write('<SECTION>\n')
139         self.write('<FILE>%s</FILE>\n<TITLE>%s</TITLE>\n' % (class_name, class_name))
140         if not is_custom:
141             self.write('%s\n' % class_name)
142         self.write('\n')
143         self.write('\n'.join(self._symbol_list(symbol_file)) + '\n')
144         if not is_custom:
145             self.write('\n<SUBSECTION Standard>\n')
146             if is_interface:
147                 self.write('%sIface\n' % class_name)
148             else:
149                 self.write('%sClass\n' % class_name)
150             dom_class = self._dom_class_decamelize(class_name).upper()
151             self.write('WEBKIT_DOM_TYPE_%s\n' % dom_class)
152             self.write('WEBKIT_DOM_%s\n' % dom_class)
153             self.write('WEBKIT_DOM_IS_%s\n' % dom_class)
154             self.write('WEBKIT_DOM_%s_CLASS\n' % dom_class)
155             if is_interface:
156                 self.write('WEBKIT_DOM_%s_GET_IFACE\n' % dom_class)
157             else:
158                 self.write('WEBKIT_DOM_IS_%s_CLASS\n' % dom_class)
159                 self.write('WEBKIT_DOM_%s_GET_CLASS\n' % dom_class)
160             self.write('\n<SUBSECTION Private>\n')
161             if is_object:
162                 self.write('%sPrivate\n' % class_name)
163             self.write('webkit_dom_%s_get_type\n' % dom_class.lower())
164         self.write('</SECTION>\n\n')
165
166     def write_footer(self):
167         self.write('<SECTION>\n')
168         self.write('<FILE>webkitdomdefines</FILE>\n<TITLE>WebKitDOMDefines</TITLE>\n')
169         self.write('<SUBSECTION Private>\n')
170         self.write('WEBKIT_API\nWEBKIT_DEPRECATED\nWEBKIT_DEPRECATED_FOR\n')
171         self.write('</SECTION>\n\n')
172
173
174 def write_doc_files():
175     doc_dir = common.build_path('DerivedSources', 'webkitdom', 'docs')
176
177     try:
178         os.mkdir(doc_dir)
179     except OSError, e:
180         if e.errno != errno.EEXIST or not os.path.isdir(doc_dir):
181             sys.stderr.write("Could not create doc dir at %s: %s\n" % (doc_dir, str(e)))
182             sys.exit(1)
183
184     with open(os.path.join(doc_dir, 'webkitdomgtk-sections.txt'), 'w') as sections_file:
185         generator = WebKitDOMDocGeneratorSections(get_all_webkitdom_symbol_files(), sections_file)
186         generator.generate()
187     with open(os.path.join(doc_dir, 'webkitdomgtk-docs.sgml'), 'w') as sgml_file:
188         generator = WebKitDOMDocGeneratorSGML(get_all_webkitdom_symbol_files(), sgml_file)
189         generator.generate()
190
191
192 def header_name_list_from_gtkdoc_config_file():
193     config_file = common.build_path('gtkdoc-webkitdom.cfg')
194     if not os.path.isfile(config_file):
195         sys.stderr.write("Could not find config file at %s\n" % config_file)
196         return sys.exit(1)
197
198     config = SafeConfigParser()
199     config.read(config_file)
200     module_name = config.sections()[0]
201     return [os.path.basename(f) for f in str(config.get(module_name, 'headers')).replace(';', ' ').split()]
202
203
204 def get_all_webkitdom_symbol_files():
205     static_symbol_files_path = common.top_level_path('Source', 'WebCore', 'bindings', 'gobject')
206     generated_symbol_files_path = common.build_path('DerivedSources', 'webkitdom')
207
208     symbol_files = []
209     for header_name in header_name_list_from_gtkdoc_config_file():
210         # webkitdomdefines.h doesn't have a corresponding symbols file and webkitdom.symbols is a
211         # file containing the expected symbols results.
212         if header_name in ("webkitdom.h", "webkitdomdefines.h"):
213             continue
214
215         symbol_file = header_name.replace(".h", ".symbols")
216         path = os.path.join(static_symbol_files_path, symbol_file)
217         if os.path.exists(path):
218             symbol_files.append(path)
219             continue
220         path = os.path.join(generated_symbol_files_path, symbol_file)
221         if os.path.exists(path):
222             symbol_files.append(path)
223             continue
224
225     return symbol_files