#!/usr/bin/env python
# Copyright (C) 2013 Igalia S.L.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import common
import errno
import os
import re
import sys
from ConfigParser import SafeConfigParser
class WebKitDOMDocGenerator(object):
DELETED_CLASSES = ["WebKitDOMEntityReference", "WebKitDOMHTMLBaseFontElement"]
def __init__(self, symbol_files, file_handle):
self._symbol_files = symbol_files
self._file_handle = file_handle
def write_header(self):
pass
def write_section(self, symbol_file):
raise NotImplementedError
def write_deleted_classes(self):
raise NotImplementedError
def write_footer(self):
pass
def write(self, string):
self._file_handle.write(string)
@staticmethod
def is_deprecated_symbol_file(file_path):
return 'WebKitDOMDeprecated' in file_path
def generate(self):
self.write_header()
for symbol_file in self._symbol_files:
if WebKitDOMDocGenerator.is_deprecated_symbol_file(symbol_file):
continue
self.write_section(symbol_file)
self.write_deleted_classes()
self.write_footer()
class WebKitDOMDocGeneratorSGML(WebKitDOMDocGenerator):
def write_header(self):
self.write('''
]>
WebKitDOMGTK+ Reference Manual
for WebKitDOMGTK+ &version;
Class Overview
''')
def write_section(self, symbol_file):
basename = os.path.basename(symbol_file)
self.write(' \n' % basename.replace(".symbols", ".xml"))
def write_deleted_classes(self):
for class_name in self.DELETED_CLASSES:
self.write(' \n' % class_name)
def write_footer(self):
self.write('''
Index
Index of deprecated symbols
''')
class WebKitDOMDocGeneratorSections(WebKitDOMDocGenerator):
def __init__(self, symbol_files, file_handle):
super(WebKitDOMDocGeneratorSections, self).__init__(symbol_files, file_handle)
self._first_decamelize_re = re.compile('(.)([A-Z][a-z]+)')
self._second_decamelize_re = re.compile('([a-z0-9])([A-Z])')
self._dom_class_re = re.compile('(^WebKitDOM)(.+)$')
self._function_re = re.compile('^.+ (.+)\((.+)\)$')
self._constant_re = re.compile('^[A-Z_]+$')
self.deprecated_symbols = {}
for symbol_file in symbol_files:
if WebKitDOMDocGenerator.is_deprecated_symbol_file(symbol_file):
self._deprecated_symbols = self._find_deprecated_symbols(symbol_file)
def _dom_class(self, class_name):
return self._dom_class_re.sub(r'\2', class_name)
def _dom_class_decamelize(self, class_name):
s1 = self._first_decamelize_re.sub(r'\1_\2', self._dom_class(class_name))
retval = self._second_decamelize_re.sub(r'\1_\2', s1)
# Fix some exceptions.
retval = retval.replace('Web_Kit', 'WebKit')
retval = retval.replace('X_Path', 'XPath')
retval = retval.replace('HTMLI_Frame', 'HTML_IFrame')
retval = retval.replace('HTMLBR', 'HTML_BR')
retval = retval.replace('HTMLHR', 'HTML_HR')
retval = retval.replace('HTMLLI', 'HTML_LI')
retval = retval.replace('HTMLD', 'HTML_D')
retval = retval.replace('HTMLO', 'HTML_O')
retval = retval.replace('HTMLU', 'HTML_U')
return retval
def _deleted_class(self, function):
for deleted_class in self.DELETED_CLASSES:
decamelized = 'webkit_dom_%s' % self._dom_class_decamelize(deleted_class).lower()
if function.startswith(decamelized):
return deleted_class
return None
def _find_deprecated_symbols(self, symbol_file):
retval = {}
f = open(symbol_file, 'r')
for line in f.readlines():
match = self._function_re.match(line)
if not match:
continue
function = match.group(1)
args = match.group(2).split(', ')
class_name = args[0].strip('*')
retval.setdefault(class_name, []).append(function)
f.close()
return retval
def _symbol_list(self, symbol_file):
retval = []
f = open(symbol_file, 'r')
for line in f.readlines():
match = self._constant_re.match(line)
if match:
retval.append(line.strip('\n'))
continue
match = self._function_re.match(line)
if not match or match.group(1).endswith('get_type'):
continue
retval.append(match.group(1))
return retval
def write_section(self, symbol_file):
class_name = os.path.basename(symbol_file).replace(".symbols", "")
is_custom = class_name == 'WebKitDOMCustom'
is_interface = class_name in ['WebKitDOMEventTarget', 'WebKitDOMNodeFilter', 'WebKitDOMXPathNSResolver']
is_object = class_name == 'WebKitDOMObject'
self.write('\n')
self.write('%s\n%s\n' % (class_name, class_name))
if not is_custom:
self.write('%s\n' % class_name)
self.write('\n')
self.write('\n'.join(self._symbol_list(symbol_file)) + '\n')
try:
deprecated_functions = self._deprecated_symbols[class_name]
self.write('\n'.join(deprecated_functions) + '\n')
except KeyError:
pass
if not is_custom:
self.write('\n\n')
if is_interface:
self.write('%sIface\n' % class_name)
else:
self.write('%sClass\n' % class_name)
dom_class = self._dom_class_decamelize(class_name).upper()
self.write('WEBKIT_DOM_TYPE_%s\n' % dom_class)
self.write('WEBKIT_DOM_%s\n' % dom_class)
self.write('WEBKIT_DOM_IS_%s\n' % dom_class)
self.write('WEBKIT_DOM_%s_CLASS\n' % dom_class)
if is_interface:
self.write('WEBKIT_DOM_%s_GET_IFACE\n' % dom_class)
else:
self.write('WEBKIT_DOM_IS_%s_CLASS\n' % dom_class)
self.write('WEBKIT_DOM_%s_GET_CLASS\n' % dom_class)
self.write('\n\n')
if is_object:
self.write('%sPrivate\n' % class_name)
self.write('webkit_dom_%s_get_type\n' % dom_class.lower())
self.write('\n\n')
def write_deleted_classes(self):
for class_name in self.DELETED_CLASSES:
self.write('\n')
self.write('%s\n%s\n' % (class_name, class_name))
try:
self.write('\n'.join([name for name in self._deprecated_symbols[class_name] if not name.endswith('get_type')]) + '\n')
except KeyError:
# A deleted class with no public methods doesn't have deprecated symbols.
pass
self.write('\n\n')
dom_class = self._dom_class_decamelize(class_name).upper()
self.write('WEBKIT_DOM_TYPE_%s\n' % dom_class)
self.write('WEBKIT_DOM_%s\n' % dom_class)
self.write('WEBKIT_DOM_IS_%s\n' % dom_class)
self.write('WEBKIT_DOM_%s_CLASS\n' % dom_class)
self.write('WEBKIT_DOM_IS_%s_CLASS\n' % dom_class)
self.write('WEBKIT_DOM_%s_GET_CLASS\n' % dom_class)
self.write('\n\n')
self.write('webkit_dom_%s_get_type\n' % self._dom_class_decamelize(class_name).lower())
self.write('\n\n')
def write_footer(self):
self.write('\n')
self.write('webkitdomdefines\nWebKitDOMDefines\n')
self.write('\n')
self.write('WEBKIT_API\nWEBKIT_DEPRECATED\nWEBKIT_DEPRECATED_FOR\n')
self.write('\n\n')
def write_doc_files(module_name):
doc_dir = common.build_path('DerivedSources', 'webkitdom', 'docs')
try:
os.mkdir(doc_dir)
except OSError, e:
if e.errno != errno.EEXIST or not os.path.isdir(doc_dir):
sys.stderr.write("Could not create doc dir at %s: %s\n" % (doc_dir, str(e)))
sys.exit(1)
with open(os.path.join(doc_dir, '%s-sections.txt' % module_name), 'w') as sections_file:
generator = WebKitDOMDocGeneratorSections(get_all_webkitdom_symbol_files(), sections_file)
generator.generate()
with open(os.path.join(doc_dir, 'webkitdomgtk-docs.sgml'), 'w') as sgml_file:
generator = WebKitDOMDocGeneratorSGML(get_all_webkitdom_symbol_files(), sgml_file)
generator.generate()
def header_name_list_from_gtkdoc_config_file():
config_file = common.build_path('gtkdoc-webkitdom.cfg')
if not os.path.isfile(config_file):
sys.stderr.write("Could not find config file at %s\n" % config_file)
return sys.exit(1)
config = SafeConfigParser()
config.read(config_file)
module_name = config.sections()[0]
return [os.path.basename(f) for f in str(config.get(module_name, 'headers')).replace(';', ' ').split()]
def get_all_webkitdom_symbol_files():
static_symbol_files_path = common.top_level_path('Source', 'WebCore', 'bindings', 'gobject')
generated_symbol_files_path = common.build_path('DerivedSources', 'webkitdom')
symbol_files = []
for header_name in header_name_list_from_gtkdoc_config_file():
# webkitdomdefines.h doesn't have a corresponding symbols file and webkitdom.symbols is a
# file containing the expected symbols results.
if header_name in ("webkitdom.h", "webkitdomdefines.h"):
continue
symbol_file = header_name.replace(".h", ".symbols")
path = os.path.join(static_symbol_files_path, symbol_file)
if os.path.exists(path):
symbol_files.append(path)
continue
path = os.path.join(generated_symbol_files_path, symbol_file)
if os.path.exists(path):
symbol_files.append(path)
continue
return symbol_files