| # Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights |
| # reserved. Use of this source code is governed by a BSD-style license that |
| # can be found in the LICENSE file. |
| |
| from __future__ import absolute_import |
| from date_util import * |
| from file_util import * |
| import os |
| import re |
| import shutil |
| import string |
| import sys |
| import textwrap |
| import time |
| |
| |
| def notify(msg): |
| """ Display a message. """ |
| sys.stdout.write(' NOTE: ' + msg + '\n') |
| |
| |
| def wrap_text(text, indent='', maxchars=80): |
| """ Wrap the text to the specified number of characters. If |
| necessary a line will be broken and wrapped after a word. |
| """ |
| result = '' |
| lines = textwrap.wrap(text, maxchars - len(indent)) |
| for line in lines: |
| result += indent + line + '\n' |
| return result |
| |
| |
| def is_base_class(clsname): |
| """ Returns true if |clsname| is a known base (root) class in the object |
| hierarchy. |
| """ |
| return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped' |
| |
| |
| def get_capi_file_name(cppname): |
| """ Convert a C++ header file name to a C API header file name. """ |
| return cppname[:-2] + '_capi.h' |
| |
| |
| def get_capi_name(cppname, isclassname, prefix=None): |
| """ Convert a C++ CamelCaps name to a C API underscore name. """ |
| result = '' |
| lastchr = '' |
| for chr in cppname: |
| # add an underscore if the current character is an upper case letter |
| # and the last character was a lower case letter |
| if len(result) > 0 and not chr.isdigit() \ |
| and chr.upper() == chr \ |
| and not lastchr.upper() == lastchr: |
| result += '_' |
| result += chr.lower() |
| lastchr = chr |
| |
| if isclassname: |
| result += '_t' |
| |
| if not prefix is None: |
| if prefix[0:3] == 'cef': |
| # if the prefix name is duplicated in the function name |
| # remove that portion of the function name |
| subprefix = prefix[3:] |
| pos = result.find(subprefix) |
| if pos >= 0: |
| result = result[0:pos] + result[pos + len(subprefix):] |
| result = prefix + '_' + result |
| |
| return result |
| |
| |
| def get_wrapper_type_enum(cppname): |
| """ Returns the wrapper type enumeration value for the specified C++ class |
| name. """ |
| return 'WT_' + get_capi_name(cppname, False)[4:].upper() |
| |
| |
| def get_prev_line(body, pos): |
| """ Retrieve the start and end positions and value for the line immediately |
| before the line containing the specified position. |
| """ |
| end = body.rfind('\n', 0, pos) |
| start = body.rfind('\n', 0, end) + 1 |
| line = body[start:end] |
| return {'start': start, 'end': end, 'line': line} |
| |
| |
| def get_comment(body, name): |
| """ Retrieve the comment for a class or function. """ |
| result = [] |
| |
| pos = body.find(name) |
| in_block_comment = False |
| while pos > 0: |
| data = get_prev_line(body, pos) |
| line = data['line'].strip() |
| pos = data['start'] |
| if len(line) == 0: |
| # check if the next previous line is a comment |
| prevdata = get_prev_line(body, pos) |
| prevline = prevdata['line'].strip() |
| if prevline[0:2] == '//' and prevline[0:3] != '///': |
| result.append(None) |
| else: |
| break |
| # single line /*--cef()--*/ |
| elif line[0:2] == '/*' and line[-2:] == '*/': |
| continue |
| # start of multi line /*--cef()--*/ |
| elif in_block_comment and line[0:2] == '/*': |
| in_block_comment = False |
| continue |
| # end of multi line /*--cef()--*/ |
| elif not in_block_comment and line[-2:] == '*/': |
| in_block_comment = True |
| continue |
| elif in_block_comment: |
| continue |
| elif line[0:2] == '//': |
| # keep the comment line including any leading spaces |
| result.append(line[2:]) |
| else: |
| break |
| |
| result.reverse() |
| return result |
| |
| |
| def validate_comment(file, name, comment): |
| """ Validate the comment array returned by get_comment(). """ |
| # Verify that the comment contains beginning and ending '///' as required by |
| # CppDoc (the leading '//' from each line will already have been removed by |
| # the get_comment() logic). There may be additional comments proceeding the |
| # CppDoc block so we look at the quantity of lines equaling '/' and expect |
| # the last line to be '/'. |
| docct = 0 |
| for line in comment: |
| if not line is None and len(line) > 0 and line == '/': |
| docct = docct + 1 |
| if docct != 2 or len(comment) < 3 or comment[len(comment) - 1] != '/': |
| raise Exception('Missing or incorrect comment in %s for: %s' % \ |
| (file, name)) |
| |
| |
| def format_comment(comment, indent, translate_map=None, maxchars=80): |
| """ Return the comments array as a formatted string. """ |
| if not translate_map is None: |
| # Replace longest keys first in translation. |
| translate_keys = sorted( |
| translate_map.keys(), key=lambda item: (-len(item), item)) |
| |
| result = '' |
| wrapme = '' |
| hasemptyline = False |
| for line in comment: |
| # if the line starts with a leading space, remove that space |
| if not line is None and len(line) > 0 and line[0:1] == ' ': |
| line = line[1:] |
| didremovespace = True |
| else: |
| didremovespace = False |
| |
| if line is None or len(line) == 0 or line[0:1] == ' ' \ |
| or line[0:1] == '/': |
| # the previous paragraph, if any, has ended |
| if len(wrapme) > 0: |
| if not translate_map is None: |
| # apply the translation |
| for key in translate_keys: |
| wrapme = wrapme.replace(key, translate_map[key]) |
| # output the previous paragraph |
| result += wrap_text(wrapme, indent + '// ', maxchars) |
| wrapme = '' |
| |
| if not line is None: |
| if len(line) == 0 or line[0:1] == ' ' or line[0:1] == '/': |
| # blank lines or anything that's further indented should be |
| # output as-is |
| result += indent + '//' |
| if len(line) > 0: |
| if didremovespace: |
| result += ' ' + line |
| else: |
| result += line |
| result += '\n' |
| else: |
| # add to the current paragraph |
| wrapme += line + ' ' |
| else: |
| # output an empty line |
| hasemptyline = True |
| result += '\n' |
| |
| if len(wrapme) > 0: |
| if not translate_map is None: |
| # apply the translation |
| for key in translate_map.keys(): |
| wrapme = wrapme.replace(key, translate_map[key]) |
| # output the previous paragraph |
| result += wrap_text(wrapme, indent + '// ', maxchars) |
| |
| if hasemptyline: |
| # an empty line means a break between comments, so the comment is |
| # probably a section heading and should have an extra line before it |
| result = '\n' + result |
| return result |
| |
| |
| def format_translation_changes(old, new): |
| """ Return a comment stating what is different between the old and new |
| function prototype parts. |
| """ |
| changed = False |
| result = '' |
| |
| # normalize C API attributes |
| oldargs = [x.replace('struct _', '') for x in old['args']] |
| oldretval = old['retval'].replace('struct _', '') |
| newargs = [x.replace('struct _', '') for x in new['args']] |
| newretval = new['retval'].replace('struct _', '') |
| |
| # check if the prototype has changed |
| oldset = set(oldargs) |
| newset = set(newargs) |
| if len(oldset.symmetric_difference(newset)) > 0: |
| changed = True |
| result += '\n // WARNING - CHANGED ATTRIBUTES' |
| |
| # in the implementation set only |
| oldonly = oldset.difference(newset) |
| for arg in oldonly: |
| result += '\n // REMOVED: ' + arg |
| |
| # in the current set only |
| newonly = newset.difference(oldset) |
| for arg in newonly: |
| result += '\n // ADDED: ' + arg |
| |
| # check if the return value has changed |
| if oldretval != newretval: |
| changed = True |
| result += '\n // WARNING - CHANGED RETURN VALUE'+ \ |
| '\n // WAS: '+old['retval']+ \ |
| '\n // NOW: '+new['retval'] |
| |
| if changed: |
| result += '\n #pragma message("Warning: "__FILE__": '+new['name']+ \ |
| ' prototype has changed")\n' |
| |
| return result |
| |
| |
| def format_translation_includes(header, body): |
| """ Return the necessary list of includes based on the contents of the |
| body. |
| """ |
| result = '' |
| |
| # <algorithm> required for VS2013. |
| if body.find('std::min') > 0 or body.find('std::max') > 0: |
| result += '#include <algorithm>\n' |
| |
| if body.find('cef_api_hash(') > 0: |
| result += '#include "include/cef_api_hash.h"\n' |
| |
| # identify what CppToC classes are being used |
| p = re.compile('([A-Za-z0-9_]{1,})CppToC') |
| list = sorted(set(p.findall(body))) |
| for item in list: |
| directory = '' |
| if not is_base_class(item): |
| cls = header.get_class(item) |
| dir = cls.get_file_directory() |
| if not dir is None: |
| directory = dir + '/' |
| result += '#include "libcef_dll/cpptoc/'+directory+ \ |
| get_capi_name(item[3:], False)+'_cpptoc.h"\n' |
| |
| # identify what CToCpp classes are being used |
| p = re.compile('([A-Za-z0-9_]{1,})CToCpp') |
| list = sorted(set(p.findall(body))) |
| for item in list: |
| directory = '' |
| if not is_base_class(item): |
| cls = header.get_class(item) |
| dir = cls.get_file_directory() |
| if not dir is None: |
| directory = dir + '/' |
| result += '#include "libcef_dll/ctocpp/'+directory+ \ |
| get_capi_name(item[3:], False)+'_ctocpp.h"\n' |
| |
| if body.find('shutdown_checker') > 0: |
| result += '#include "libcef_dll/shutdown_checker.h"\n' |
| |
| if body.find('transfer_') > 0: |
| result += '#include "libcef_dll/transfer_util.h"\n' |
| |
| return result |
| |
| |
| def str_to_dict(str): |
| """ Convert a string to a dictionary. If the same key has multiple values |
| the values will be stored in a list. """ |
| dict = {} |
| parts = str.split(',') |
| for part in parts: |
| part = part.strip() |
| if len(part) == 0: |
| continue |
| sparts = part.split('=') |
| if len(sparts) > 2: |
| raise Exception('Invalid dictionary pair format: ' + part) |
| name = sparts[0].strip() |
| if len(sparts) == 2: |
| val = sparts[1].strip() |
| else: |
| val = True |
| if name in dict: |
| # a value with this name already exists |
| curval = dict[name] |
| if not isinstance(curval, list): |
| # convert the string value to a list |
| dict[name] = [curval] |
| dict[name].append(val) |
| else: |
| dict[name] = val |
| return dict |
| |
| |
| def dict_to_str(dict): |
| """ Convert a dictionary to a string. """ |
| str = [] |
| for name in dict.keys(): |
| if not isinstance(dict[name], list): |
| if dict[name] is True: |
| # currently a bool value |
| str.append(name) |
| else: |
| # currently a string value |
| str.append(name + '=' + dict[name]) |
| else: |
| # currently a list value |
| for val in dict[name]: |
| str.append(name + '=' + val) |
| return ','.join(str) |
| |
| |
| # regex for matching comment-formatted attributes |
| _cre_attrib = '/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/' |
| # regex for matching class and function names |
| _cre_cfname = '([A-Za-z0-9_]{1,})' |
| # regex for matching class and function names including path separators |
| _cre_cfnameorpath = '([A-Za-z0-9_\/]{1,})' |
| # regex for matching function return values |
| _cre_retval = '([A-Za-z0-9_<>:,\*\&]{1,})' |
| # regex for matching typedef value and name combination |
| _cre_typedef = '([A-Za-z0-9_<>:,\*\&\s]{1,})' |
| # regex for matching function return value and name combination |
| _cre_func = '([A-Za-z][A-Za-z0-9_<>:,\*\&\s]{1,})' |
| # regex for matching virtual function modifiers + arbitrary whitespace |
| _cre_vfmod = '([\sA-Za-z0-9_]{0,})' |
| # regex for matching arbitrary whitespace |
| _cre_space = '[\s]{1,}' |
| # regex for matching optional virtual keyword |
| _cre_virtual = '(?:[\s]{1,}virtual){0,1}' |
| |
| # Simple translation types. Format is: |
| # 'cpp_type' : ['capi_type', 'capi_default_value'] |
| _simpletypes = { |
| 'void': ['void', ''], |
| 'void*': ['void*', 'NULL'], |
| 'int': ['int', '0'], |
| 'int16': ['int16', '0'], |
| 'uint16': ['uint16', '0'], |
| 'int32': ['int32', '0'], |
| 'uint32': ['uint32', '0'], |
| 'int64': ['int64', '0'], |
| 'uint64': ['uint64', '0'], |
| 'double': ['double', '0'], |
| 'float': ['float', '0'], |
| 'float*': ['float*', 'NULL'], |
| 'long': ['long', '0'], |
| 'unsigned long': ['unsigned long', '0'], |
| 'long long': ['long long', '0'], |
| 'size_t': ['size_t', '0'], |
| 'bool': ['int', '0'], |
| 'char': ['char', '0'], |
| 'char* const': ['char* const', 'NULL'], |
| 'cef_color_t': ['cef_color_t', '0'], |
| 'cef_json_parser_error_t': ['cef_json_parser_error_t', 'JSON_NO_ERROR'], |
| 'cef_plugin_policy_t': ['cef_plugin_policy_t', 'PLUGIN_POLICY_ALLOW'], |
| 'CefCursorHandle': ['cef_cursor_handle_t', 'kNullCursorHandle'], |
| 'CefCompositionUnderline': [ |
| 'cef_composition_underline_t', 'CefCompositionUnderline()' |
| ], |
| 'CefEventHandle': ['cef_event_handle_t', 'kNullEventHandle'], |
| 'CefWindowHandle': ['cef_window_handle_t', 'kNullWindowHandle'], |
| 'CefPoint': ['cef_point_t', 'CefPoint()'], |
| 'CefRect': ['cef_rect_t', 'CefRect()'], |
| 'CefSize': ['cef_size_t', 'CefSize()'], |
| 'CefRange': ['cef_range_t', 'CefRange()'], |
| 'CefDraggableRegion': ['cef_draggable_region_t', 'CefDraggableRegion()'], |
| 'CefThreadId': ['cef_thread_id_t', 'TID_UI'], |
| 'CefTime': ['cef_time_t', 'CefTime()'], |
| 'CefAudioParameters': ['cef_audio_parameters_t', 'CefAudioParameters()'] |
| } |
| |
| |
| def get_function_impls(content, ident, has_impl=True): |
| """ Retrieve the function parts from the specified contents as a set of |
| return value, name, arguments and body. Ident must occur somewhere in |
| the value. |
| """ |
| # extract the functions |
| find_regex = '\n' + _cre_func + '\((.*?)\)([A-Za-z0-9_\s]{0,})' |
| if has_impl: |
| find_regex += '\{(.*?)\n\}' |
| else: |
| find_regex += '(;)' |
| p = re.compile(find_regex, re.MULTILINE | re.DOTALL) |
| list = p.findall(content) |
| |
| # build the function map with the function name as the key |
| result = [] |
| for retval, argval, vfmod, body in list: |
| if retval.find(ident) < 0: |
| # the identifier was not found |
| continue |
| |
| # remove the identifier |
| retval = retval.replace(ident, '') |
| retval = retval.strip() |
| |
| # Normalize the delimiter. |
| retval = retval.replace('\n', ' ') |
| |
| # retrieve the function name |
| parts = retval.split(' ') |
| name = parts[-1] |
| del parts[-1] |
| retval = ' '.join(parts) |
| |
| # parse the arguments |
| args = [] |
| for v in argval.split(','): |
| v = v.strip() |
| if len(v) > 0: |
| args.append(v) |
| |
| result.append({ |
| 'retval': retval.strip(), |
| 'name': name, |
| 'args': args, |
| 'vfmod': vfmod.strip(), |
| 'body': body if has_impl else '', |
| }) |
| |
| return result |
| |
| |
| def get_next_function_impl(existing, name): |
| result = None |
| for item in existing: |
| if item['name'] == name: |
| result = item |
| existing.remove(item) |
| break |
| return result |
| |
| |
| def get_copyright(full=False, translator=True): |
| if full: |
| result = \ |
| """// Copyright (c) $YEAR$ Marshall A. Greenblatt. All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the name Chromium Embedded |
| // Framework nor the names of its contributors may be used to endorse |
| // or promote products derived from this software without specific prior |
| // written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| """ |
| else: |
| result = \ |
| """// Copyright (c) $YEAR$ The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| """ |
| |
| if translator: |
| result += \ |
| """// |
| // --------------------------------------------------------------------------- |
| // |
| // This file was generated by the CEF translator tool. If making changes by |
| // hand only do so within the body of existing method and function |
| // implementations. See the translator.README.txt file in the tools directory |
| // for more information. |
| // |
| // $hash=$$HASH$$$ |
| // |
| |
| """ |
| |
| # add the copyright year |
| return result.replace('$YEAR$', get_year()) |
| |
| |
| class obj_header: |
| """ Class representing a C++ header file. """ |
| |
| def __init__(self): |
| self.filenames = [] |
| self.typedefs = [] |
| self.funcs = [] |
| self.classes = [] |
| self.root_directory = None |
| |
| def set_root_directory(self, root_directory): |
| """ Set the root directory. """ |
| self.root_directory = root_directory |
| |
| def get_root_directory(self): |
| """ Get the root directory. """ |
| return self.root_directory |
| |
| def add_directory(self, directory, excluded_files=[]): |
| """ Add all header files from the specified directory. """ |
| files = get_files(os.path.join(directory, '*.h')) |
| for file in files: |
| if len(excluded_files) == 0 or \ |
| not os.path.split(file)[1] in excluded_files: |
| self.add_file(file) |
| |
| def add_file(self, filepath): |
| """ Add a header file. """ |
| |
| if self.root_directory is None: |
| filename = os.path.split(filepath)[1] |
| else: |
| filename = os.path.relpath(filepath, self.root_directory) |
| filename = filename.replace('\\', '/') |
| |
| # read the input file into memory |
| self.add_data(filename, read_file(filepath)) |
| |
| def add_data(self, filename, data): |
| """ Add header file contents. """ |
| |
| added = False |
| |
| # remove space from between template definition end brackets |
| data = data.replace("> >", ">>") |
| |
| # extract global typedefs |
| p = re.compile('\ntypedef' + _cre_space + _cre_typedef + ';', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(data) |
| if len(list) > 0: |
| # build the global typedef objects |
| for value in list: |
| pos = value.rfind(' ') |
| if pos < 0: |
| raise Exception('Invalid typedef: ' + value) |
| alias = value[pos + 1:].strip() |
| value = value[:pos].strip() |
| self.typedefs.append(obj_typedef(self, filename, value, alias)) |
| |
| # extract global functions |
| p = re.compile('\n' + _cre_attrib + '\n' + _cre_func + '\((.*?)\)', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(data) |
| if len(list) > 0: |
| added = True |
| |
| # build the global function objects |
| for attrib, retval, argval in list: |
| comment = get_comment(data, retval + '(' + argval + ');') |
| validate_comment(filename, retval, comment) |
| self.funcs.append( |
| obj_function(self, filename, attrib, retval, argval, comment)) |
| |
| # extract includes |
| p = re.compile('\n#include \"include/' + _cre_cfnameorpath + '.h') |
| includes = p.findall(data) |
| |
| # extract forward declarations |
| p = re.compile('\nclass' + _cre_space + _cre_cfname + ';') |
| forward_declares = p.findall(data) |
| |
| # extract empty classes |
| p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname + |
| _cre_space + ':' + _cre_space + 'public' + _cre_virtual + |
| _cre_space + _cre_cfname + _cre_space + '{};', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(data) |
| if len(list) > 0: |
| added = True |
| |
| # build the class objects |
| for attrib, name, parent_name in list: |
| # Style may place the ':' on the next line. |
| comment = get_comment(data, name + ' :') |
| if len(comment) == 0: |
| comment = get_comment(data, name + "\n") |
| validate_comment(filename, name, comment) |
| self.classes.append( |
| obj_class(self, filename, attrib, name, parent_name, "", comment, |
| includes, forward_declares)) |
| |
| # Remove empty classes from |data| so we don't mess up the non-empty |
| # class search that follows. |
| data = p.sub('', data) |
| |
| # extract classes |
| p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname + |
| _cre_space + ':' + _cre_space + 'public' + _cre_virtual + |
| _cre_space + _cre_cfname + _cre_space + '{(.*?)\n};', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(data) |
| if len(list) > 0: |
| added = True |
| |
| # build the class objects |
| for attrib, name, parent_name, body in list: |
| # Style may place the ':' on the next line. |
| comment = get_comment(data, name + ' :') |
| if len(comment) == 0: |
| comment = get_comment(data, name + "\n") |
| validate_comment(filename, name, comment) |
| self.classes.append( |
| obj_class(self, filename, attrib, name, parent_name, body, comment, |
| includes, forward_declares)) |
| |
| if added: |
| # a global function or class was read from the header file |
| self.filenames.append(filename) |
| |
| def __repr__(self): |
| result = '' |
| |
| if len(self.typedefs) > 0: |
| strlist = [] |
| for cls in self.typedefs: |
| strlist.append(str(cls)) |
| result += "\n".join(strlist) + "\n\n" |
| |
| if len(self.funcs) > 0: |
| strlist = [] |
| for cls in self.funcs: |
| strlist.append(str(cls)) |
| result += "\n".join(strlist) + "\n\n" |
| |
| if len(self.classes) > 0: |
| strlist = [] |
| for cls in self.classes: |
| strlist.append(str(cls)) |
| result += "\n".join(strlist) |
| |
| return result |
| |
| def get_file_names(self): |
| """ Return the array of header file names. """ |
| return self.filenames |
| |
| def get_typedefs(self): |
| """ Return the array of typedef objects. """ |
| return self.typedefs |
| |
| def get_funcs(self, filename=None): |
| """ Return the array of function objects. """ |
| if filename is None: |
| return self.funcs |
| else: |
| # only return the functions in the specified file |
| res = [] |
| for func in self.funcs: |
| if func.get_file_name() == filename: |
| res.append(func) |
| return res |
| |
| def get_classes(self, filename=None): |
| """ Return the array of class objects. """ |
| if filename is None: |
| return self.classes |
| else: |
| # only return the classes in the specified file |
| res = [] |
| for cls in self.classes: |
| if cls.get_file_name() == filename: |
| res.append(cls) |
| return res |
| |
| def get_class(self, classname, defined_structs=None): |
| """ Return the specified class or None if not found. """ |
| for cls in self.classes: |
| if cls.get_name() == classname: |
| return cls |
| elif not defined_structs is None: |
| defined_structs.append(cls.get_capi_name()) |
| return None |
| |
| def get_class_names(self): |
| """ Returns the names of all classes in this object. """ |
| result = [] |
| for cls in self.classes: |
| result.append(cls.get_name()) |
| return result |
| |
| def get_base_class_name(self, classname): |
| """ Returns the base (root) class name for |classname|. """ |
| cur_cls = self.get_class(classname) |
| while True: |
| parent_name = cur_cls.get_parent_name() |
| if is_base_class(parent_name): |
| return parent_name |
| else: |
| parent_cls = self.get_class(parent_name) |
| if parent_cls is None: |
| break |
| cur_cls = self.get_class(parent_name) |
| return None |
| |
| def get_types(self, list): |
| """ Return a dictionary mapping data types to analyzed values. """ |
| for cls in self.typedefs: |
| cls.get_types(list) |
| |
| for cls in self.classes: |
| cls.get_types(list) |
| |
| def get_alias_translation(self, alias): |
| """ Return a translation of alias to value based on typedef |
| statements. """ |
| for cls in self.typedefs: |
| if cls.alias == alias: |
| return cls.value |
| return None |
| |
| def get_analysis(self, value, named=True): |
| """ Return an analysis of the value based the header file context. """ |
| return obj_analysis([self], value, named) |
| |
| def get_defined_structs(self): |
| """ Return a list of already defined structure names. """ |
| return [ |
| 'cef_print_info_t', 'cef_window_info_t', 'cef_base_ref_counted_t', |
| 'cef_base_scoped_t' |
| ] |
| |
| def get_capi_translations(self): |
| """ Return a dictionary that maps C++ terminology to C API terminology. |
| """ |
| # strings that will be changed in C++ comments |
| map = { |
| 'class': 'structure', |
| 'Class': 'Structure', |
| 'interface': 'structure', |
| 'Interface': 'Structure', |
| 'true': 'true (1)', |
| 'false': 'false (0)', |
| 'empty': 'NULL', |
| 'method': 'function' |
| } |
| |
| # add mappings for all classes and functions |
| funcs = self.get_funcs() |
| for func in funcs: |
| map[func.get_name() + '()'] = func.get_capi_name() + '()' |
| |
| classes = self.get_classes() |
| for cls in classes: |
| map[cls.get_name()] = cls.get_capi_name() |
| |
| funcs = cls.get_virtual_funcs() |
| for func in funcs: |
| map[func.get_name() + '()'] = func.get_capi_name() + '()' |
| |
| funcs = cls.get_static_funcs() |
| for func in funcs: |
| map[func.get_name() + '()'] = func.get_capi_name() + '()' |
| |
| return map |
| |
| |
| class obj_class: |
| """ Class representing a C++ class. """ |
| |
| def __init__(self, parent, filename, attrib, name, parent_name, body, comment, |
| includes, forward_declares): |
| if not isinstance(parent, obj_header): |
| raise Exception('Invalid parent object type') |
| |
| self.parent = parent |
| self.filename = filename |
| self.attribs = str_to_dict(attrib) |
| self.name = name |
| self.parent_name = parent_name |
| self.comment = comment |
| self.includes = includes |
| self.forward_declares = forward_declares |
| |
| # extract typedefs |
| p = re.compile( |
| '\n' + _cre_space + 'typedef' + _cre_space + _cre_typedef + ';', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(body) |
| |
| # build the typedef objects |
| self.typedefs = [] |
| for value in list: |
| pos = value.rfind(' ') |
| if pos < 0: |
| raise Exception('Invalid typedef: ' + value) |
| alias = value[pos + 1:].strip() |
| value = value[:pos].strip() |
| self.typedefs.append(obj_typedef(self, filename, value, alias)) |
| |
| # extract static functions |
| p = re.compile('\n' + _cre_space + _cre_attrib + '\n' + _cre_space + |
| 'static' + _cre_space + _cre_func + '\((.*?)\)', |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(body) |
| |
| # build the static function objects |
| self.staticfuncs = [] |
| for attrib, retval, argval in list: |
| comment = get_comment(body, retval + '(' + argval + ')') |
| validate_comment(filename, retval, comment) |
| self.staticfuncs.append( |
| obj_function_static(self, attrib, retval, argval, comment)) |
| |
| # extract virtual functions |
| p = re.compile( |
| '\n' + _cre_space + _cre_attrib + '\n' + _cre_space + 'virtual' + |
| _cre_space + _cre_func + '\((.*?)\)' + _cre_vfmod, |
| re.MULTILINE | re.DOTALL) |
| list = p.findall(body) |
| |
| # build the virtual function objects |
| self.virtualfuncs = [] |
| for attrib, retval, argval, vfmod in list: |
| comment = get_comment(body, retval + '(' + argval + ')') |
| validate_comment(filename, retval, comment) |
| self.virtualfuncs.append( |
| obj_function_virtual(self, attrib, retval, argval, comment, |
| vfmod.strip())) |
| |
| def __repr__(self): |
| result = '/* ' + dict_to_str( |
| self.attribs) + ' */ class ' + self.name + "\n{" |
| |
| if len(self.typedefs) > 0: |
| result += "\n\t" |
| strlist = [] |
| for cls in self.typedefs: |
| strlist.append(str(cls)) |
| result += "\n\t".join(strlist) |
| |
| if len(self.staticfuncs) > 0: |
| result += "\n\t" |
| strlist = [] |
| for cls in self.staticfuncs: |
| strlist.append(str(cls)) |
| result += "\n\t".join(strlist) |
| |
| if len(self.virtualfuncs) > 0: |
| result += "\n\t" |
| strlist = [] |
| for cls in self.virtualfuncs: |
| strlist.append(str(cls)) |
| result += "\n\t".join(strlist) |
| |
| result += "\n};\n" |
| return result |
| |
| def get_file_name(self): |
| """ Return the C++ header file name. Includes the directory component, |
| if any. """ |
| return self.filename |
| |
| def get_capi_file_name(self): |
| """ Return the CAPI header file name. Includes the directory component, |
| if any. """ |
| return get_capi_file_name(self.filename) |
| |
| def get_file_directory(self): |
| """ Return the file directory component, if any. """ |
| pos = self.filename.rfind('/') |
| if pos >= 0: |
| return self.filename[:pos] |
| return None |
| |
| def get_name(self): |
| """ Return the class name. """ |
| return self.name |
| |
| def get_capi_name(self): |
| """ Return the CAPI structure name for this class. """ |
| return get_capi_name(self.name, True) |
| |
| def get_parent_name(self): |
| """ Return the parent class name. """ |
| return self.parent_name |
| |
| def get_parent_capi_name(self): |
| """ Return the CAPI structure name for the parent class. """ |
| return get_capi_name(self.parent_name, True) |
| |
| def has_parent(self, parent_name): |
| """ Returns true if this class has the specified class anywhere in its |
| inheritance hierarchy. """ |
| # Every class has a known base class as the top-most parent. |
| if is_base_class(parent_name) or parent_name == self.parent_name: |
| return True |
| if is_base_class(self.parent_name): |
| return False |
| |
| cur_cls = self.parent.get_class(self.parent_name) |
| while True: |
| cur_parent_name = cur_cls.get_parent_name() |
| if is_base_class(cur_parent_name): |
| break |
| elif cur_parent_name == parent_name: |
| return True |
| cur_cls = self.parent.get_class(cur_parent_name) |
| |
| return False |
| |
| def get_comment(self): |
| """ Return the class comment as an array of lines. """ |
| return self.comment |
| |
| def get_includes(self): |
| """ Return the list of classes that are included from this class' |
| header file. """ |
| return self.includes |
| |
| def get_forward_declares(self): |
| """ Return the list of classes that are forward declared for this |
| class. """ |
| return self.forward_declares |
| |
| def get_attribs(self): |
| """ Return all attributes as a dictionary. """ |
| return self.attribs |
| |
| def has_attrib(self, name): |
| """ Return true if the specified attribute exists. """ |
| return name in self.attribs |
| |
| def get_attrib(self, name): |
| """ Return the first or only value for specified attribute. """ |
| if name in self.attribs: |
| if isinstance(self.attribs[name], list): |
| # the value is a list |
| return self.attribs[name][0] |
| else: |
| # the value is a string |
| return self.attribs[name] |
| return None |
| |
| def get_attrib_list(self, name): |
| """ Return all values for specified attribute as a list. """ |
| if name in self.attribs: |
| if isinstance(self.attribs[name], list): |
| # the value is already a list |
| return self.attribs[name] |
| else: |
| # convert the value to a list |
| return [self.attribs[name]] |
| return None |
| |
| def get_typedefs(self): |
| """ Return the array of typedef objects. """ |
| return self.typedefs |
| |
| def has_typedef_alias(self, alias): |
| """ Returns true if the specified typedef alias is defined in the scope |
| of this class declaration. """ |
| for typedef in self.typedefs: |
| if typedef.get_alias() == alias: |
| return True |
| return False |
| |
| def get_static_funcs(self): |
| """ Return the array of static function objects. """ |
| return self.staticfuncs |
| |
| def get_virtual_funcs(self): |
| """ Return the array of virtual function objects. """ |
| return self.virtualfuncs |
| |
| def get_types(self, list): |
| """ Return a dictionary mapping data types to analyzed values. """ |
| for cls in self.typedefs: |
| cls.get_types(list) |
| |
| for cls in self.staticfuncs: |
| cls.get_types(list) |
| |
| for cls in self.virtualfuncs: |
| cls.get_types(list) |
| |
| def get_alias_translation(self, alias): |
| for cls in self.typedefs: |
| if cls.alias == alias: |
| return cls.value |
| return None |
| |
| def get_analysis(self, value, named=True): |
| """ Return an analysis of the value based on the class definition |
| context. |
| """ |
| return obj_analysis([self, self.parent], value, named) |
| |
| def is_library_side(self): |
| """ Returns true if the class is implemented by the library. """ |
| return self.attribs['source'] == 'library' |
| |
| def is_client_side(self): |
| """ Returns true if the class is implemented by the client. """ |
| return self.attribs['source'] == 'client' |
| |
| |
| class obj_typedef: |
| """ Class representing a typedef statement. """ |
| |
| def __init__(self, parent, filename, value, alias): |
| if not isinstance(parent, obj_header) \ |
| and not isinstance(parent, obj_class): |
| raise Exception('Invalid parent object type') |
| |
| self.parent = parent |
| self.filename = filename |
| self.alias = alias |
| self.value = self.parent.get_analysis(value, False) |
| |
| def __repr__(self): |
| return 'typedef ' + self.value.get_type() + ' ' + self.alias + ';' |
| |
| def get_file_name(self): |
| """ Return the C++ header file name. """ |
| return self.filename |
| |
| def get_capi_file_name(self): |
| """ Return the CAPI header file name. """ |
| return get_capi_file_name(self.filename) |
| |
| def get_alias(self): |
| """ Return the alias. """ |
| return self.alias |
| |
| def get_value(self): |
| """ Return an analysis of the value based on the class or header file |
| definition context. |
| """ |
| return self.value |
| |
| def get_types(self, list): |
| """ Return a dictionary mapping data types to analyzed values. """ |
| name = self.value.get_type() |
| if not name in list: |
| list[name] = self.value |
| |
| |
| class obj_function: |
| """ Class representing a function. """ |
| |
| def __init__(self, parent, filename, attrib, retval, argval, comment): |
| self.parent = parent |
| self.filename = filename |
| self.attribs = str_to_dict(attrib) |
| self.retval = obj_argument(self, retval) |
| self.name = self.retval.remove_name() |
| self.comment = comment |
| |
| # build the argument objects |
| self.arguments = [] |
| arglist = argval.split(',') |
| argindex = 0 |
| while argindex < len(arglist): |
| arg = arglist[argindex] |
| if arg.find('<') >= 0 and arg.find('>') == -1: |
| # We've split inside of a template type declaration. Join the |
| # next argument with this argument. |
| argindex += 1 |
| arg += ',' + arglist[argindex] |
| |
| arg = arg.strip() |
| if len(arg) > 0: |
| argument = obj_argument(self, arg) |
| if argument.needs_attrib_count_func() and \ |
| argument.get_attrib_count_func() is None: |
| raise Exception("A 'count_func' attribute is required "+ \ |
| "for the '"+argument.get_name()+ \ |
| "' parameter to "+self.get_qualified_name()) |
| self.arguments.append(argument) |
| |
| argindex += 1 |
| |
| if self.retval.needs_attrib_default_retval() and \ |
| self.retval.get_attrib_default_retval() is None: |
| raise Exception("A 'default_retval' attribute is required for "+ \ |
| self.get_qualified_name()) |
| |
| def __repr__(self): |
| return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto() |
| |
| def get_file_name(self): |
| """ Return the C++ header file name. """ |
| return self.filename |
| |
| def get_capi_file_name(self): |
| """ Return the CAPI header file name. """ |
| return get_capi_file_name(self.filename) |
| |
| def get_name(self): |
| """ Return the function name. """ |
| return self.name |
| |
| def get_qualified_name(self): |
| """ Return the fully qualified function name. """ |
| if isinstance(self.parent, obj_header): |
| # global function |
| return self.name |
| else: |
| # member function |
| return self.parent.get_name() + '::' + self.name |
| |
| def get_capi_name(self, prefix=None): |
| """ Return the CAPI function name. """ |
| if 'capi_name' in self.attribs: |
| return self.attribs['capi_name'] |
| return get_capi_name(self.name, False, prefix) |
| |
| def get_comment(self): |
| """ Return the function comment as an array of lines. """ |
| return self.comment |
| |
| def get_attribs(self): |
| """ Return all attributes as a dictionary. """ |
| return self.attribs |
| |
| def has_attrib(self, name): |
| """ Return true if the specified attribute exists. """ |
| return name in self.attribs |
| |
| def get_attrib(self, name): |
| """ Return the first or only value for specified attribute. """ |
| if name in self.attribs: |
| if isinstance(self.attribs[name], list): |
| # the value is a list |
| return self.attribs[name][0] |
| else: |
| # the value is a string |
| return self.attribs[name] |
| return None |
| |
| def get_attrib_list(self, name): |
| """ Return all values for specified attribute as a list. """ |
| if name in self.attribs: |
| if isinstance(self.attribs[name], list): |
| # the value is already a list |
| return self.attribs[name] |
| else: |
| # convert the value to a list |
| return [self.attribs[name]] |
| return None |
| |
| def get_retval(self): |
| """ Return the return value object. """ |
| return self.retval |
| |
| def get_arguments(self): |
| """ Return the argument array. """ |
| return self.arguments |
| |
| def get_types(self, list): |
| """ Return a dictionary mapping data types to analyzed values. """ |
| for cls in self.arguments: |
| cls.get_types(list) |
| |
| def get_capi_parts(self, defined_structs=[], prefix=None): |
| """ Return the parts of the C API function definition. """ |
| retval = '' |
| dict = self.retval.get_type().get_capi(defined_structs) |
| if dict['format'] == 'single': |
| retval = dict['value'] |
| |
| name = self.get_capi_name(prefix) |
| args = [] |
| |
| if isinstance(self, obj_function_virtual): |
| # virtual functions get themselves as the first argument |
| str = 'struct _' + self.parent.get_capi_name() + '* self' |
| if isinstance(self, obj_function_virtual) and self.is_const(): |
| # const virtual functions get const self pointers |
| str = 'const ' + str |
| args.append(str) |
| |
| if len(self.arguments) > 0: |
| for cls in self.arguments: |
| type = cls.get_type() |
| dict = type.get_capi(defined_structs) |
| if dict['format'] == 'single': |
| args.append(dict['value']) |
| elif dict['format'] == 'multi-arg': |
| # add an additional argument for the size of the array |
| type_name = type.get_name() |
| if type.is_const(): |
| # for const arrays pass the size argument by value |
| args.append('size_t ' + type_name + 'Count') |
| else: |
| # for non-const arrays pass the size argument by address |
| args.append('size_t* ' + type_name + 'Count') |
| args.append(dict['value']) |
| |
| return {'retval': retval, 'name': name, 'args': args} |
| |
| def get_capi_proto(self, defined_structs=[], prefix=None): |
| """ Return the prototype of the C API function. """ |
| parts = self.get_capi_parts(defined_structs, prefix) |
| result = parts['retval']+' '+parts['name']+ \ |
| '('+', '.join(parts['args'])+')' |
| return result |
| |
| def get_cpp_parts(self, isimpl=False): |
| """ Return the parts of the C++ function definition. """ |
| retval = str(self.retval) |
| name = self.name |
| |
| args = [] |
| if len(self.arguments) > 0: |
| for cls in self.arguments: |
| args.append(str(cls)) |
| |
| if isimpl and isinstance(self, obj_function_virtual): |
| # enumeration return values must be qualified with the class name |
| # if the type is defined in the class declaration scope. |
| type = self.get_retval().get_type() |
| if type.is_result_struct() and type.is_result_struct_enum() and \ |
| self.parent.has_typedef_alias(retval): |
| retval = self.parent.get_name() + '::' + retval |
| |
| return {'retval': retval, 'name': name, 'args': args} |
| |
| def get_cpp_proto(self, classname=None): |
| """ Return the prototype of the C++ function. """ |
| parts = self.get_cpp_parts() |
| result = parts['retval'] + ' ' |
| if not classname is None: |
| result += classname + '::' |
| result += parts['name'] + '(' + ', '.join(parts['args']) + ')' |
| if isinstance(self, obj_function_virtual) and self.is_const(): |
| result += ' const' |
| return result |
| |
| def is_same_side(self, other_class_name): |
| """ Returns true if this function is on the same side (library or |
| client) and the specified class. """ |
| if isinstance(self.parent, obj_class): |
| # this function is part of a class |
| this_is_library_side = self.parent.is_library_side() |
| header = self.parent.parent |
| else: |
| # this function is global |
| this_is_library_side = True |
| header = self.parent |
| |
| if is_base_class(other_class_name): |
| other_is_library_side = False |
| else: |
| other_class = header.get_class(other_class_name) |
| if other_class is None: |
| raise Exception('Unknown class: ' + other_class_name) |
| other_is_library_side = other_class.is_library_side() |
| |
| return other_is_library_side == this_is_library_side |
| |
| |
| class obj_function_static(obj_function): |
| """ Class representing a static function. """ |
| |
| def __init__(self, parent, attrib, retval, argval, comment): |
| if not isinstance(parent, obj_class): |
| raise Exception('Invalid parent object type') |
| obj_function.__init__(self, parent, parent.filename, attrib, retval, argval, |
| comment) |
| |
| def __repr__(self): |
| return 'static ' + obj_function.__repr__(self) + ';' |
| |
| def get_capi_name(self, prefix=None): |
| """ Return the CAPI function name. """ |
| if prefix is None: |
| # by default static functions are prefixed with the class name |
| prefix = get_capi_name(self.parent.get_name(), False) |
| return obj_function.get_capi_name(self, prefix) |
| |
| |
| class obj_function_virtual(obj_function): |
| """ Class representing a virtual function. """ |
| |
| def __init__(self, parent, attrib, retval, argval, comment, vfmod): |
| if not isinstance(parent, obj_class): |
| raise Exception('Invalid parent object type') |
| obj_function.__init__(self, parent, parent.filename, attrib, retval, argval, |
| comment) |
| if vfmod == 'const': |
| self.isconst = True |
| else: |
| self.isconst = False |
| |
| def __repr__(self): |
| return 'virtual ' + obj_function.__repr__(self) + ';' |
| |
| def is_const(self): |
| """ Returns true if the method declaration is const. """ |
| return self.isconst |
| |
| |
| class obj_argument: |
| """ Class representing a function argument. """ |
| |
| def __init__(self, parent, argval): |
| if not isinstance(parent, obj_function): |
| raise Exception('Invalid parent object type') |
| |
| self.parent = parent |
| self.type = self.parent.parent.get_analysis(argval) |
| |
| def __repr__(self): |
| result = '' |
| if self.type.is_const(): |
| result += 'const ' |
| result += self.type.get_type() |
| if self.type.is_byref(): |
| result += '&' |
| elif self.type.is_byaddr(): |
| result += '*' |
| if self.type.has_name(): |
| result += ' ' + self.type.get_name() |
| return result |
| |
| def get_name(self): |
| """ Return the name for this argument. """ |
| return self.type.get_name() |
| |
| def remove_name(self): |
| """ Remove and return the name value. """ |
| name = self.type.get_name() |
| self.type.name = None |
| return name |
| |
| def get_type(self): |
| """ Return an analysis of the argument type based on the class |
| definition context. |
| """ |
| return self.type |
| |
| def get_types(self, list): |
| """ Return a dictionary mapping data types to analyzed values. """ |
| name = self.type.get_type() |
| if not name in list: |
| list[name] = self.type |
| |
| def needs_attrib_count_func(self): |
| """ Returns true if this argument requires a 'count_func' attribute. """ |
| # A 'count_func' attribute is required for non-const non-string vector |
| # attribute types |
| return self.type.has_name() and \ |
| self.type.is_result_vector() and \ |
| not self.type.is_result_vector_string() and \ |
| not self.type.is_const() |
| |
| def get_attrib_count_func(self): |
| """ Returns the count function for this argument. """ |
| # The 'count_func' attribute value format is name:function |
| if not self.parent.has_attrib('count_func'): |
| return None |
| name = self.type.get_name() |
| vals = self.parent.get_attrib_list('count_func') |
| for val in vals: |
| parts = val.split(':') |
| if len(parts) != 2: |
| raise Exception("Invalid 'count_func' attribute value for "+ \ |
| self.parent.get_qualified_name()+': '+val) |
| if parts[0].strip() == name: |
| return parts[1].strip() |
| return None |
| |
| def needs_attrib_default_retval(self): |
| """ Returns true if this argument requires a 'default_retval' attribute. |
| """ |
| # A 'default_retval' attribute is required for enumeration return value |
| # types. |
| return not self.type.has_name() and \ |
| self.type.is_result_struct() and \ |
| self.type.is_result_struct_enum() |
| |
| def get_attrib_default_retval(self): |
| """ Returns the defualt return value for this argument. """ |
| return self.parent.get_attrib('default_retval') |
| |
| def get_arg_type(self): |
| """ Returns the argument type as defined in translator.README.txt. """ |
| if not self.type.has_name(): |
| raise Exception('Cannot be called for retval types') |
| |
| # simple or enumeration type |
| if (self.type.is_result_simple() and \ |
| self.type.get_type() != 'bool') or \ |
| (self.type.is_result_struct() and \ |
| self.type.is_result_struct_enum()): |
| if self.type.is_byref(): |
| if self.type.is_const(): |
| return 'simple_byref_const' |
| return 'simple_byref' |
| elif self.type.is_byaddr(): |
| return 'simple_byaddr' |
| return 'simple_byval' |
| |
| # boolean type |
| if self.type.get_type() == 'bool': |
| if self.type.is_byref(): |
| return 'bool_byref' |
| elif self.type.is_byaddr(): |
| return 'bool_byaddr' |
| return 'bool_byval' |
| |
| # structure type |
| if self.type.is_result_struct() and self.type.is_byref(): |
| if self.type.is_const(): |
| return 'struct_byref_const' |
| return 'struct_byref' |
| |
| # string type |
| if self.type.is_result_string() and self.type.is_byref(): |
| if self.type.is_const(): |
| return 'string_byref_const' |
| return 'string_byref' |
| |
| # *ptr type |
| if self.type.is_result_ptr(): |
| prefix = self.type.get_result_ptr_type_prefix() |
| same_side = self.parent.is_same_side(self.type.get_ptr_type()) |
| if self.type.is_byref(): |
| if same_side: |
| return prefix + 'ptr_same_byref' |
| return prefix + 'ptr_diff_byref' |
| if same_side: |
| return prefix + 'ptr_same' |
| return prefix + 'ptr_diff' |
| |
| if self.type.is_result_vector(): |
| # all vector types must be passed by reference |
| if not self.type.is_byref(): |
| return 'invalid' |
| |
| if self.type.is_result_vector_string(): |
| # string vector type |
| if self.type.is_const(): |
| return 'string_vec_byref_const' |
| return 'string_vec_byref' |
| |
| if self.type.is_result_vector_simple(): |
| if self.type.get_vector_type() != 'bool': |
| # simple/enumeration vector types |
| if self.type.is_const(): |
| return 'simple_vec_byref_const' |
| return 'simple_vec_byref' |
| |
| # boolean vector types |
| if self.type.is_const(): |
| return 'bool_vec_byref_const' |
| return 'bool_vec_byref' |
| |
| if self.type.is_result_vector_ptr(): |
| # *ptr vector types |
| prefix = self.type.get_result_vector_ptr_type_prefix() |
| same_side = self.parent.is_same_side(self.type.get_ptr_type()) |
| if self.type.is_const(): |
| if same_side: |
| return prefix + 'ptr_vec_same_byref_const' |
| return prefix + 'ptr_vec_diff_byref_const' |
| if same_side: |
| return prefix + 'ptr_vec_same_byref' |
| return prefix + 'ptr_vec_diff_byref' |
| |
| # string single map type |
| if self.type.is_result_map_single(): |
| if not self.type.is_byref(): |
| return 'invalid' |
| if self.type.is_const(): |
| return 'string_map_single_byref_const' |
| return 'string_map_single_byref' |
| |
| # string multi map type |
| if self.type.is_result_map_multi(): |
| if not self.type.is_byref(): |
| return 'invalid' |
| if self.type.is_const(): |
| return 'string_map_multi_byref_const' |
| return 'string_map_multi_byref' |
| |
| return 'invalid' |
| |
| def get_retval_type(self): |
| """ Returns the retval type as defined in translator.README.txt. """ |
| if self.type.has_name(): |
| raise Exception('Cannot be called for argument types') |
| |
| # unsupported modifiers |
| if self.type.is_const() or self.type.is_byref() or \ |
| self.type.is_byaddr(): |
| return 'invalid' |
| |
| # void types don't have a return value |
| if self.type.get_type() == 'void': |
| return 'none' |
| |
| if (self.type.is_result_simple() and \ |
| self.type.get_type() != 'bool') or \ |
| (self.type.is_result_struct() and self.type.is_result_struct_enum()): |
| return 'simple' |
| |
| if self.type.get_type() == 'bool': |
| return 'bool' |
| |
| if self.type.is_result_string(): |
| return 'string' |
| |
| if self.type.is_result_ptr(): |
| prefix = self.type.get_result_ptr_type_prefix() |
| if self.parent.is_same_side(self.type.get_ptr_type()): |
| return prefix + 'ptr_same' |
| else: |
| return prefix + 'ptr_diff' |
| |
| return 'invalid' |
| |
| def get_retval_default(self, for_capi): |
| """ Returns the default return value based on the retval type. """ |
| # start with the default retval attribute, if any. |
| retval = self.get_attrib_default_retval() |
| if not retval is None: |
| if for_capi: |
| # apply any appropriate C API translations. |
| if retval == 'true': |
| return '1' |
| if retval == 'false': |
| return '0' |
| return retval |
| |
| # next look at the retval type value. |
| type = self.get_retval_type() |
| if type == 'simple': |
| return self.get_type().get_result_simple_default() |
| elif type == 'bool': |
| if for_capi: |
| return '0' |
| return 'false' |
| elif type == 'string': |
| if for_capi: |
| return 'NULL' |
| return 'CefString()' |
| elif type == 'refptr_same' or type == 'refptr_diff' or \ |
| type == 'rawptr_same' or type == 'rawptr_diff': |
| if for_capi: |
| return 'NULL' |
| return 'nullptr' |
| elif type == 'ownptr_same' or type == 'ownptr_diff': |
| if for_capi: |
| return 'NULL' |
| return 'CefOwnPtr<' + self.type.get_ptr_type() + '>()' |
| |
| return '' |
| |
| |
| class obj_analysis: |
| """ Class representing an analysis of a data type value. """ |
| |
| def __init__(self, scopelist, value, named): |
| self.value = value |
| self.result_type = 'unknown' |
| self.result_value = None |
| self.result_default = None |
| self.ptr_type = None |
| |
| # parse the argument string |
| partlist = value.strip().split() |
| |
| if named == True: |
| # extract the name value |
| self.name = partlist[-1] |
| del partlist[-1] |
| else: |
| self.name = None |
| |
| if len(partlist) == 0: |
| raise Exception('Invalid argument value: ' + value) |
| |
| # check const status |
| if partlist[0] == 'const': |
| self.isconst = True |
| del partlist[0] |
| else: |
| self.isconst = False |
| |
| if len(partlist) == 0: |
| raise Exception('Invalid argument value: ' + value) |
| |
| # combine the data type |
| self.type = ' '.join(partlist) |
| |
| # extract the last character of the data type |
| endchar = self.type[-1] |
| |
| # check if the value is passed by reference |
| if endchar == '&': |
| self.isbyref = True |
| self.type = self.type[:-1] |
| else: |
| self.isbyref = False |
| |
| # check if the value is passed by address |
| if endchar == '*': |
| self.isbyaddr = True |
| self.type = self.type[:-1] |
| else: |
| self.isbyaddr = False |
| |
| # see if the value is directly identifiable |
| if self._check_advanced(self.type) == True: |
| return |
| |
| # not identifiable, so look it up |
| translation = None |
| for scope in scopelist: |
| if not isinstance(scope, obj_header) \ |
| and not isinstance(scope, obj_class): |
| raise Exception('Invalid scope object type') |
| translation = scope.get_alias_translation(self.type) |
| if not translation is None: |
| break |
| |
| if translation is None: |
| raise Exception('Failed to translate type: ' + self.type) |
| |
| # the translation succeeded so keep the result |
| self.result_type = translation.result_type |
| self.result_value = translation.result_value |
| |
| def _check_advanced(self, value): |
| # check for vectors |
| if value.find('std::vector') == 0: |
| self.result_type = 'vector' |
| val = value[12:-1].strip() |
| self.result_value = [self._get_basic(val)] |
| self.result_value[0]['vector_type'] = val |
| return True |
| |
| # check for maps |
| if value.find('std::map') == 0: |
| self.result_type = 'map' |
| vals = value[9:-1].split(',') |
| if len(vals) == 2: |
| self.result_value = [ |
| self._get_basic(vals[0].strip()), |
| self._get_basic(vals[1].strip()) |
| ] |
| return True |
| |
| # check for multimaps |
| if value.find('std::multimap') == 0: |
| self.result_type = 'multimap' |
| vals = value[14:-1].split(',') |
| if len(vals) == 2: |
| self.result_value = [ |
| self._get_basic(vals[0].strip()), |
| self._get_basic(vals[1].strip()) |
| ] |
| return True |
| |
| # check for basic types |
| basic = self._get_basic(value) |
| if not basic is None: |
| self.result_type = basic['result_type'] |
| self.result_value = basic['result_value'] |
| if 'ptr_type' in basic: |
| self.ptr_type = basic['ptr_type'] |
| if 'result_default' in basic: |
| self.result_default = basic['result_default'] |
| return True |
| |
| return False |
| |
| def _get_basic(self, value): |
| # check for string values |
| if value == "CefString": |
| return {'result_type': 'string', 'result_value': None} |
| |
| # check for simple direct translations |
| if value in _simpletypes.keys(): |
| return { |
| 'result_type': 'simple', |
| 'result_value': _simpletypes[value][0], |
| 'result_default': _simpletypes[value][1], |
| } |
| |
| # check if already a C API structure |
| if value[-2:] == '_t': |
| return {'result_type': 'structure', 'result_value': value} |
| |
| # check for CEF reference pointers |
| p = re.compile('^CefRefPtr<(.*?)>$', re.DOTALL) |
| list = p.findall(value) |
| if len(list) == 1: |
| return { |
| 'result_type': 'refptr', |
| 'result_value': get_capi_name(list[0], True) + '*', |
| 'ptr_type': list[0] |
| } |
| |
| # check for CEF owned pointers |
| p = re.compile('^CefOwnPtr<(.*?)>$', re.DOTALL) |
| list = p.findall(value) |
| if len(list) == 1: |
| return { |
| 'result_type': 'ownptr', |
| 'result_value': get_capi_name(list[0], True) + '*', |
| 'ptr_type': list[0] |
| } |
| |
| # check for CEF raw pointers |
| p = re.compile('^CefRawPtr<(.*?)>$', re.DOTALL) |
| list = p.findall(value) |
| if len(list) == 1: |
| return { |
| 'result_type': 'rawptr', |
| 'result_value': get_capi_name(list[0], True) + '*', |
| 'ptr_type': list[0] |
| } |
| |
| # check for CEF structure types |
| if value[0:3] == 'Cef' and value[-4:] != 'List': |
| return { |
| 'result_type': 'structure', |
| 'result_value': get_capi_name(value, True) |
| } |
| |
| return None |
| |
| def __repr__(self): |
| return '(' + self.result_type + ') ' + str(self.result_value) |
| |
| def has_name(self): |
| """ Returns true if a name value exists. """ |
| return (not self.name is None) |
| |
| def get_name(self): |
| """ Return the name. """ |
| return self.name |
| |
| def get_value(self): |
| """ Return the C++ value (type + name). """ |
| return self.value |
| |
| def get_type(self): |
| """ Return the C++ type. """ |
| return self.type |
| |
| def get_ptr_type(self): |
| """ Return the C++ class type referenced by a CefRefPtr. """ |
| if self.is_result_vector() and self.is_result_vector_ptr(): |
| # return the vector RefPtr type |
| return self.result_value[0]['ptr_type'] |
| # return the basic RefPtr type |
| return self.ptr_type |
| |
| def get_vector_type(self): |
| """ Return the C++ class type referenced by a std::vector. """ |
| if self.is_result_vector(): |
| return self.result_value[0]['vector_type'] |
| return None |
| |
| def is_const(self): |
| """ Returns true if the argument value is constant. """ |
| return self.isconst |
| |
| def is_byref(self): |
| """ Returns true if the argument is passed by reference. """ |
| return self.isbyref |
| |
| def is_byaddr(self): |
| """ Returns true if the argument is passed by address. """ |
| return self.isbyaddr |
| |
| def is_result_simple(self): |
| """ Returns true if this is a simple argument type. """ |
| return (self.result_type == 'simple') |
| |
| def get_result_simple_type_root(self): |
| """ Return the simple structure or basic type name. """ |
| return self.result_value |
| |
| def get_result_simple_type(self): |
| """ Return the simple type. """ |
| result = '' |
| if self.is_const(): |
| result += 'const ' |
| result += self.result_value |
| if self.is_byaddr() or self.is_byref(): |
| result += '*' |
| return result |
| |
| def get_result_simple_default(self): |
| """ Return the default value fo the basic type. """ |
| return self.result_default |
| |
| def is_result_ptr(self): |
| """ Returns true if this is a *Ptr type. """ |
| return self.is_result_refptr() or self.is_result_ownptr() or \ |
| self.is_result_rawptr() |
| |
| def get_result_ptr_type_root(self): |
| """ Return the *Ptr type structure name. """ |
| return self.result_value[:-1] |
| |
| def get_result_ptr_type(self, defined_structs=[]): |
| """ Return the *Ptr type. """ |
| result = '' |
| if not self.result_value[:-1] in defined_structs: |
| result += 'struct _' |
| result += self.result_value |
| if self.is_byref() or self.is_byaddr(): |
| result += '*' |
| return result |
| |
| def get_result_ptr_type_prefix(self): |
| """ Returns the *Ptr type prefix. """ |
| if self.is_result_refptr(): |
| return 'ref' |
| if self.is_result_ownptr(): |
| return 'own' |
| if self.is_result_rawptr(): |
| return 'raw' |
| raise Exception('Not a pointer type') |
| |
| def is_result_refptr(self): |
| """ Returns true if this is a RefPtr type. """ |
| return (self.result_type == 'refptr') |
| |
| def is_result_ownptr(self): |
| """ Returns true if this is a OwnPtr type. """ |
| return (self.result_type == 'ownptr') |
| |
| def is_result_rawptr(self): |
| """ Returns true if this is a RawPtr type. """ |
| return (self.result_type == 'rawptr') |
| |
| def is_result_struct(self): |
| """ Returns true if this is a structure type. """ |
| return (self.result_type == 'structure') |
| |
| def is_result_struct_enum(self): |
| """ Returns true if this struct type is likely an enumeration. """ |
| # structure values that are passed by reference or address must be |
| # structures and not enumerations |
| if not self.is_byref() and not self.is_byaddr(): |
| return True |
| return False |
| |
| def get_result_struct_type(self, defined_structs=[]): |
| """ Return the structure or enumeration type. """ |
| result = '' |
| is_enum = self.is_result_struct_enum() |
| if not is_enum: |
| if self.is_const(): |
| result += 'const ' |
| if not self.result_value in defined_structs: |
| result += 'struct _' |
| result += self.result_value |
| if not is_enum: |
| result += '*' |
| return result |
| |
| def is_result_string(self): |
| """ Returns true if this is a string type. """ |
| return (self.result_type == 'string') |
| |
| def get_result_string_type(self): |
| """ Return the string type. """ |
| if not self.has_name(): |
| # Return values are string structs that the user must free. Use |
| # the name of the structure as a hint. |
| return 'cef_string_userfree_t' |
| elif not self.is_const() and (self.is_byref() or self.is_byaddr()): |
| # Parameters passed by reference or address. Use the normal |
| # non-const string struct. |
| return 'cef_string_t*' |
| # Const parameters use the const string struct. |
| return 'const cef_string_t*' |
| |
| def is_result_vector(self): |
| """ Returns true if this is a vector type. """ |
| return (self.result_type == 'vector') |
| |
| def is_result_vector_string(self): |
| """ Returns true if this is a string vector. """ |
| return self.result_value[0]['result_type'] == 'string' |
| |
| def is_result_vector_simple(self): |
| """ Returns true if this is a string vector. """ |
| return self.result_value[0]['result_type'] == 'simple' |
| |
| def is_result_vector_ptr(self): |
| """ Returns true if this is a *Ptr vector. """ |
| return self.is_result_vector_refptr() or \ |
| self.is_result_vector_ownptr() or \ |
| self.is_result_vector_rawptr() |
| |
| def get_result_vector_ptr_type_prefix(self): |
| """ Returns the *Ptr type prefix. """ |
| if self.is_result_vector_refptr(): |
| return 'ref' |
| if self.is_result_vector_ownptr(): |
| return 'own' |
| if self.is_result_vector_rawptr(): |
| return 'raw' |
| raise Exception('Not a pointer type') |
| |
| def is_result_vector_refptr(self): |
| """ Returns true if this is a RefPtr vector. """ |
| return self.result_value[0]['result_type'] == 'refptr' |
| |
| def is_result_vector_ownptr(self): |
| """ Returns true if this is a OwnPtr vector. """ |
| return self.result_value[0]['result_type'] == 'ownptr' |
| |
| def is_result_vector_rawptr(self): |
| """ Returns true if this is a RawPtr vector. """ |
| return self.result_value[0]['result_type'] == 'rawptr' |
| |
| def get_result_vector_type_root(self): |
| """ Return the vector structure or basic type name. """ |
| return self.result_value[0]['result_value'] |
| |
| def get_result_vector_type(self, defined_structs=[]): |
| """ Return the vector type. """ |
| if not self.has_name(): |
| raise Exception('Cannot use vector as a return type') |
| |
| type = self.result_value[0]['result_type'] |
| value = self.result_value[0]['result_value'] |
| |
| result = {} |
| if type == 'string': |
| result['value'] = 'cef_string_list_t' |
| result['format'] = 'single' |
| return result |
| |
| if type == 'simple': |
| str = value |
| if self.is_const(): |
| str += ' const' |
| str += '*' |
| result['value'] = str |
| elif type == 'refptr' or type == 'ownptr' or type == 'rawptr': |
| str = '' |
| if not value[:-1] in defined_structs: |
| str += 'struct _' |
| str += value |
| if self.is_const(): |
| str += ' const' |
| str += '*' |
| result['value'] = str |
| else: |
| raise Exception('Unsupported vector type: ' + type) |
| |
| # vector values must be passed as a value array parameter |
| # and a size parameter |
| result['format'] = 'multi-arg' |
| return result |
| |
| def is_result_map(self): |
| """ Returns true if this is a map type. """ |
| return (self.result_type == 'map' or self.result_type == 'multimap') |
| |
| def is_result_map_single(self): |
| """ Returns true if this is a single map type. """ |
| return (self.result_type == 'map') |
| |
| def is_result_map_multi(self): |
| """ Returns true if this is a multi map type. """ |
| return (self.result_type == 'multimap') |
| |
| def get_result_map_type(self, defined_structs=[]): |
| """ Return the map type. """ |
| if not self.has_name(): |
| raise Exception('Cannot use map as a return type') |
| if self.result_value[0]['result_type'] == 'string' \ |
| and self.result_value[1]['result_type'] == 'string': |
| if self.result_type == 'map': |
| return {'value': 'cef_string_map_t', 'format': 'single'} |
| elif self.result_type == 'multimap': |
| return {'value': 'cef_string_multimap_t', 'format': 'multi'} |
| raise Exception('Only mappings of strings to strings are supported') |
| |
| def get_capi(self, defined_structs=[]): |
| """ Format the value for the C API. """ |
| result = '' |
| format = 'single' |
| if self.is_result_simple(): |
| result += self.get_result_simple_type() |
| elif self.is_result_ptr(): |
| result += self.get_result_ptr_type(defined_structs) |
| elif self.is_result_struct(): |
| result += self.get_result_struct_type(defined_structs) |
| elif self.is_result_string(): |
| result += self.get_result_string_type() |
| elif self.is_result_map(): |
| resdict = self.get_result_map_type(defined_structs) |
| if resdict['format'] == 'single' or resdict['format'] == 'multi': |
| result += resdict['value'] |
| else: |
| raise Exception('Unsupported map type') |
| elif self.is_result_vector(): |
| resdict = self.get_result_vector_type(defined_structs) |
| if resdict['format'] != 'single': |
| format = resdict['format'] |
| result += resdict['value'] |
| |
| if self.has_name(): |
| result += ' ' + self.get_name() |
| |
| return {'format': format, 'value': result} |
| |
| |
| # test the module |
| if __name__ == "__main__": |
| import pprint |
| import sys |
| |
| # verify that the correct number of command-line arguments are provided |
| if len(sys.argv) != 2: |
| sys.stderr.write('Usage: ' + sys.argv[0] + ' <directory>') |
| sys.exit() |
| |
| pp = pprint.PrettyPrinter(indent=4) |
| |
| # create the header object |
| header = obj_header() |
| header.add_directory(sys.argv[1]) |
| |
| # output the type mapping |
| types = {} |
| header.get_types(types) |
| pp.pprint(types) |
| sys.stdout.write('\n') |
| |
| # output the parsed C++ data |
| sys.stdout.write(str(header)) |
| |
| # output the C API formatted data |
| defined_names = header.get_defined_structs() |
| result = '' |
| |
| # global functions |
| funcs = header.get_funcs() |
| if len(funcs) > 0: |
| for func in funcs: |
| result += func.get_capi_proto(defined_names) + ';\n' |
| result += '\n' |
| |
| classes = header.get_classes() |
| for cls in classes: |
| # virtual functions are inside a structure |
| result += 'struct ' + cls.get_capi_name() + '\n{\n' |
| funcs = cls.get_virtual_funcs() |
| if len(funcs) > 0: |
| for func in funcs: |
| result += '\t' + func.get_capi_proto(defined_names) + ';\n' |
| result += '}\n\n' |
| |
| defined_names.append(cls.get_capi_name()) |
| |
| # static functions become global |
| funcs = cls.get_static_funcs() |
| if len(funcs) > 0: |
| for func in funcs: |
| result += func.get_capi_proto(defined_names) + ';\n' |
| result += '\n' |
| sys.stdout.write(result) |