forked from mirrors/linphone-iphone
1092 lines
44 KiB
Python
1092 lines
44 KiB
Python
# Copyright (C) 2014 Belledonne Communications SARL
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program 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 General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
from sets import Set
|
|
import sys
|
|
|
|
|
|
def strip_leading_linphone(s):
|
|
if s.lower().startswith('linphone'):
|
|
return s[8:]
|
|
else:
|
|
return s
|
|
|
|
def compute_event_name(s):
|
|
s = strip_leading_linphone(s)
|
|
s = s[4:-2] # Remove leading 'Core' and tailing 'Cb'
|
|
event_name = ''
|
|
first = True
|
|
for l in s:
|
|
if l.isupper() and not first:
|
|
event_name += '_'
|
|
event_name += l.lower()
|
|
first = False
|
|
return event_name
|
|
|
|
|
|
class ArgumentType:
|
|
def __init__(self, basic_type, complete_type, contained_type, linphone_module):
|
|
self.basic_type = basic_type
|
|
self.complete_type = complete_type
|
|
self.contained_type = contained_type
|
|
self.linphone_module = linphone_module
|
|
self.type_str = None
|
|
self.check_func = None
|
|
self.convert_func = None
|
|
self.convert_from_func = None
|
|
self.fmt_str = 'O'
|
|
self.cfmt_str = '%p'
|
|
self.cnativefmt_str = '%p'
|
|
self.use_native_pointer = False
|
|
self.cast_convert_func_result = True
|
|
self.__compute()
|
|
if self.basic_type == 'MSList' and self.contained_type is not None:
|
|
self.linphone_module.mslist_types.add(self.contained_type)
|
|
|
|
def __compute(self):
|
|
splitted_type = self.complete_type.split(' ')
|
|
if self.basic_type == 'char':
|
|
if '*' in splitted_type:
|
|
self.type_str = 'string'
|
|
self.check_func = 'PyString_Check'
|
|
self.convert_func = 'PyString_AsString'
|
|
self.fmt_str = 'z'
|
|
self.cfmt_str = '\\"%s\\"'
|
|
else:
|
|
self.type_str = 'int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AsLong'
|
|
self.fmt_str = 'b'
|
|
self.cfmt_str = '%08x'
|
|
elif self.basic_type == 'int':
|
|
if 'unsigned' in splitted_type:
|
|
self.type_str = 'unsigned int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AsUnsignedLongMask'
|
|
self.fmt_str = 'I'
|
|
self.cfmt_str = '%u'
|
|
else:
|
|
self.type_str = 'int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AS_LONG'
|
|
self.fmt_str = 'i'
|
|
self.cfmt_str = '%d'
|
|
elif self.basic_type in ['int8_t', 'int16_t' 'int32_t']:
|
|
self.type_str = 'int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AS_LONG'
|
|
if self.basic_type == 'int8_t':
|
|
self.fmt_str = 'c'
|
|
elif self.basic_type == 'int16_t':
|
|
self.fmt_str = 'h'
|
|
elif self.basic_type == 'int32_t':
|
|
self.fmt_str = 'l'
|
|
self.cfmt_str = '%d'
|
|
elif self.basic_type in ['uint8_t', 'uint16_t', 'uint32_t']:
|
|
self.type_str = 'unsigned int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AsUnsignedLongMask'
|
|
if self.basic_type == 'uint8_t':
|
|
self.fmt_str = 'b'
|
|
elif self.basic_type == 'uint16_t':
|
|
self.fmt_str = 'H'
|
|
elif self.basic_type == 'uint32_t':
|
|
self.fmt_str = 'k'
|
|
self.cfmt_str = '%u'
|
|
elif self.basic_type == 'int64_t':
|
|
self.type_str = '64bits int'
|
|
self.check_func = 'PyLong_Check'
|
|
self.convert_func = 'PyLong_AsLongLong'
|
|
self.fmt_str = 'L'
|
|
self.cfmt_str = '%ld'
|
|
elif self.basic_type == 'uint64_t':
|
|
self.type_str = '64bits unsigned int'
|
|
self.check_func = 'PyLong_Check'
|
|
self.convert_func = 'PyLong_AsUnsignedLongLong'
|
|
self.fmt_str = 'K'
|
|
self.cfmt_str = '%lu'
|
|
elif self.basic_type == 'size_t':
|
|
self.type_str = 'size_t'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AsSsize_t'
|
|
self.fmt_str = 'n'
|
|
self.cfmt_str = '%lu'
|
|
elif self.basic_type in ['float', 'double']:
|
|
self.type_str = 'float'
|
|
self.check_func = 'PyFloat_Check'
|
|
self.convert_func = 'PyFloat_AsDouble'
|
|
if self.basic_type == 'float':
|
|
self.fmt_str = 'f'
|
|
elif self.basic_type == 'double':
|
|
self.fmt_str = 'd'
|
|
self.cfmt_str = '%f'
|
|
elif self.basic_type == 'bool_t':
|
|
self.type_str = 'bool'
|
|
self.check_func = 'PyBool_Check'
|
|
self.convert_func = 'PyInt_AsLong'
|
|
self.fmt_str = 'b'
|
|
self.cfmt_str = '%u'
|
|
elif self.basic_type == 'time_t':
|
|
self.type_str = 'DateTime'
|
|
self.check_func = 'PyDateTime_Check'
|
|
self.convert_func = 'PyDateTime_As_time_t'
|
|
self.convert_from_func = 'PyDateTime_From_time_t'
|
|
self.fmt_str = 'O'
|
|
self.cfmt_str = '%p'
|
|
self.cnativefmt_str = "%ld"
|
|
elif self.basic_type == 'MSList':
|
|
self.type_str = 'list of linphone.' + self.contained_type
|
|
self.check_func = 'PyList_Check'
|
|
self.convert_func = 'PyList_AsMSListOf' + self.contained_type
|
|
self.convert_from_func = 'PyList_FromMSListOf' + self.contained_type
|
|
self.fmt_str = 'O'
|
|
self.cfmt_str = '%p'
|
|
elif self.basic_type == 'MSVideoSize':
|
|
self.type_str = 'linphone.VideoSize'
|
|
self.check_func = 'PyLinphoneVideoSize_Check'
|
|
self.convert_func = 'PyLinphoneVideoSize_AsMSVideoSize'
|
|
self.convert_from_func = 'PyLinphoneVideoSize_FromMSVideoSize'
|
|
self.fmt_str = 'O'
|
|
self.cfmt_str = '%p'
|
|
self.cast_convert_func_result = False
|
|
else:
|
|
if strip_leading_linphone(self.basic_type) in self.linphone_module.enum_names:
|
|
self.type_str = 'int'
|
|
self.check_func = 'PyInt_Check'
|
|
self.convert_func = 'PyInt_AsLong'
|
|
self.fmt_str = 'i'
|
|
self.cfmt_str = '%d'
|
|
elif '*' in splitted_type:
|
|
self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type)
|
|
self.use_native_pointer = True
|
|
else:
|
|
self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type)
|
|
|
|
|
|
class MethodDefinition:
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
self.body = ''
|
|
self.arg_names = []
|
|
self.parse_tuple_format = ''
|
|
self.build_value_format = ''
|
|
self.return_type = 'void'
|
|
self.return_complete_type = 'void'
|
|
self.return_contained_type = None
|
|
self.method_node = method_node
|
|
self.class_ = class_
|
|
self.linphone_module = linphone_module
|
|
self.self_arg = None
|
|
self.xml_method_return = None
|
|
self.xml_method_args = []
|
|
self.method_type = 'instancemethod'
|
|
|
|
def format_local_variables_definition(self):
|
|
body = ''
|
|
if self.xml_method_return is not None:
|
|
self.return_type = self.xml_method_return.get('type')
|
|
self.return_complete_type = self.xml_method_return.get('completetype')
|
|
self.return_contained_type = self.xml_method_return.get('containedtype')
|
|
if self.return_complete_type != 'void':
|
|
body += "\t" + self.return_complete_type + " cresult;\n"
|
|
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
|
|
self.build_value_format = argument_type.fmt_str
|
|
if self.build_value_format == 'O':
|
|
body += "\tPyObject * pyresult;\n"
|
|
body += "\tPyObject * pyret;\n"
|
|
if self.self_arg is not None:
|
|
body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n"
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
self.parse_tuple_format += argument_type.fmt_str
|
|
if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
|
|
body += "\tPyObject * " + arg_name + ";\n"
|
|
body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr = NULL;\n"
|
|
elif argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
|
|
body += "\tPyObject * " + arg_name + ";\n"
|
|
body += "\t" + arg_complete_type + " " + arg_name + "_native_obj;\n"
|
|
elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names:
|
|
body += "\tint " + arg_name + ";\n"
|
|
else:
|
|
body += "\t" + arg_complete_type + " " + arg_name + ";\n"
|
|
self.arg_names.append(arg_name)
|
|
return body
|
|
|
|
def format_arguments_parsing(self):
|
|
class_native_ptr_check_code = ''
|
|
if self.self_arg is not None:
|
|
class_native_ptr_check_code = self.format_class_native_pointer_check(False)
|
|
parse_tuple_code = ''
|
|
if len(self.arg_names) > 0:
|
|
parse_tuple_code = \
|
|
"""if (!PyArg_ParseTuple(args, "{fmt}", {args})) {{
|
|
return NULL;
|
|
}}
|
|
""".format(fmt=self.parse_tuple_format, args=', '.join(map(lambda a: '&' + a, self.arg_names)))
|
|
args_conversion_code = ''
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
if argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
|
|
args_conversion_code += \
|
|
""" {arg_name}_native_obj = {convert_func}({arg_name});
|
|
""".format(arg_name=arg_name, convert_func=argument_type.convert_func)
|
|
return \
|
|
""" {class_native_ptr_check_code}
|
|
{parse_tuple_code}
|
|
{args_type_check_code}
|
|
{args_native_ptr_check_code}
|
|
{args_conversion_code}
|
|
""".format(class_native_ptr_check_code=class_native_ptr_check_code,
|
|
parse_tuple_code=parse_tuple_code,
|
|
args_type_check_code=self.format_args_type_check(),
|
|
args_native_ptr_check_code=self.format_args_native_pointer_check(),
|
|
args_conversion_code=args_conversion_code)
|
|
|
|
def format_enter_trace(self):
|
|
fmt = ''
|
|
args = []
|
|
if self.self_arg is not None:
|
|
fmt += "%p [%p]"
|
|
args += ["self", "native_ptr"]
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
if fmt != '':
|
|
fmt += ', '
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
fmt += argument_type.cfmt_str
|
|
args.append(arg_name)
|
|
if argument_type.fmt_str == 'O':
|
|
fmt += ' [' + argument_type.cnativefmt_str + ']'
|
|
if argument_type.use_native_pointer:
|
|
args.append(arg_name + '_native_ptr')
|
|
else:
|
|
args.append(arg_name + '_native_obj')
|
|
args = ', '.join(args)
|
|
if args != '':
|
|
args = ', ' + args
|
|
return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s({fmt})\", __FUNCTION__{args});\n".format(fmt=fmt, args=args)
|
|
|
|
def format_c_function_call(self):
|
|
arg_names = []
|
|
c_function_call_code = ''
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
|
|
arg_names.append(arg_name + "_native_ptr")
|
|
elif argument_type.fmt_str == 'O' and argument_type.convert_func is not None:
|
|
arg_names.append(arg_name + "_native_obj")
|
|
else:
|
|
arg_names.append(arg_name)
|
|
if self.return_type != 'void':
|
|
c_function_call_code += "cresult = "
|
|
c_function_call_code += self.method_node.get('name') + "("
|
|
if self.self_arg is not None:
|
|
c_function_call_code += "native_ptr"
|
|
if len(arg_names) > 0:
|
|
c_function_call_code += ', '
|
|
c_function_call_code += ', '.join(arg_names) + ");"
|
|
return_from_user_data_code = ''
|
|
new_from_native_pointer_code = ''
|
|
ref_native_pointer_code = ''
|
|
convert_from_code = ''
|
|
build_value_code = ''
|
|
result_variable = ''
|
|
if self.return_complete_type != 'void':
|
|
if self.build_value_format == 'O':
|
|
stripped_return_type = strip_leading_linphone(self.return_type)
|
|
return_type_class = self.find_class_definition(self.return_type)
|
|
if return_type_class is not None:
|
|
if return_type_class['class_has_user_data']:
|
|
get_user_data_function = return_type_class['class_c_function_prefix'] + "get_user_data"
|
|
return_from_user_data_code = \
|
|
"""if ((cresult != NULL) && ({func}(cresult) != NULL)) {{
|
|
return (PyObject *){func}(cresult);
|
|
}}
|
|
""".format(func=get_user_data_function)
|
|
new_from_native_pointer_code = "pyresult = pylinphone_{return_type}_new_from_native_ptr(&pylinphone_{return_type}Type, cresult);\n".format(return_type=stripped_return_type)
|
|
if self.self_arg is not None and return_type_class['class_refcountable']:
|
|
ref_function = return_type_class['class_c_function_prefix'] + "ref"
|
|
ref_native_pointer_code = \
|
|
"""if (cresult != NULL) {{
|
|
{func}(({cast_type})cresult);
|
|
}}
|
|
""".format(func=ref_function, cast_type=self.remove_const_from_complete_type(self.return_complete_type))
|
|
else:
|
|
return_argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
|
|
if return_argument_type.convert_from_func is not None:
|
|
convert_from_code = \
|
|
"""pyresult = {convert_func}(cresult);
|
|
""".format(convert_func=return_argument_type.convert_from_func)
|
|
result_variable = 'pyresult'
|
|
else:
|
|
result_variable = 'cresult'
|
|
if result_variable != '':
|
|
build_value_code = "pyret = Py_BuildValue(\"{fmt}\", {result_variable});\n".format(fmt=self.build_value_format.replace('O', 'N'), result_variable=result_variable)
|
|
body = \
|
|
""" {c_function_call_code}
|
|
pylinphone_dispatch_messages();
|
|
{return_from_user_data_code}
|
|
{new_from_native_pointer_code}
|
|
{ref_native_pointer_code}
|
|
{convert_from_code}
|
|
{build_value_code}
|
|
""".format(c_function_call_code=c_function_call_code,
|
|
return_from_user_data_code=return_from_user_data_code,
|
|
new_from_native_pointer_code=new_from_native_pointer_code,
|
|
ref_native_pointer_code=ref_native_pointer_code,
|
|
convert_from_code=convert_from_code,
|
|
build_value_code=build_value_code)
|
|
return body
|
|
|
|
def format_return_trace(self):
|
|
if self.return_complete_type != 'void':
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, pyret);\n"
|
|
else:
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> None\", __FUNCTION__);\n"
|
|
|
|
def format_return_result(self):
|
|
if self.return_complete_type != 'void':
|
|
return "\treturn pyret;"
|
|
return "\tPy_RETURN_NONE;"
|
|
|
|
def format_return_none_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> None\", __FUNCTION__);\n"
|
|
|
|
def format_class_native_pointer_check(self, return_int):
|
|
return_value = "NULL"
|
|
if return_int:
|
|
return_value = "-1"
|
|
return \
|
|
"""native_ptr = pylinphone_{class_name}_get_native_ptr(self);
|
|
if (native_ptr == NULL) {{
|
|
PyErr_SetString(PyExc_TypeError, "Invalid linphone.{class_name} instance");
|
|
return {return_value};
|
|
}}
|
|
""".format(class_name=self.class_['class_name'], return_value=return_value)
|
|
|
|
def format_args_type_check(self):
|
|
body = ''
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
if argument_type.fmt_str == 'O':
|
|
if argument_type.use_native_pointer:
|
|
body += \
|
|
""" if (({arg_name} != Py_None) && !PyObject_IsInstance({arg_name}, (PyObject *)&pylinphone_{arg_type}Type)) {{
|
|
PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance.");
|
|
return NULL;
|
|
}}
|
|
""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type), type_str=argument_type.type_str)
|
|
else:
|
|
body += \
|
|
""" if (!{check_func}({arg_name})) {{
|
|
PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance.");
|
|
return NULL;
|
|
}}
|
|
""".format(arg_name=arg_name, check_func=argument_type.check_func, type_str=argument_type.type_str)
|
|
if body != '':
|
|
body = body[1:] # Remove leading '\t'
|
|
return body
|
|
|
|
def format_args_native_pointer_check(self):
|
|
body = ''
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = "_" + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
|
|
body += \
|
|
""" if (({arg_name} != NULL) && ({arg_name} != Py_None)) {{
|
|
if (({arg_name}_native_ptr = pylinphone_{arg_type}_get_native_ptr({arg_name})) == NULL) {{
|
|
return NULL;
|
|
}}
|
|
}}
|
|
""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type))
|
|
if body != '':
|
|
body = body[1:] # Remove leading '\t'
|
|
return body
|
|
|
|
def parse_method_node(self):
|
|
if self.method_node is not None:
|
|
self.xml_method_return = self.method_node.find('./return')
|
|
self.xml_method_args = self.method_node.findall('./arguments/argument')
|
|
self.method_type = self.method_node.tag
|
|
if self.method_type != 'classmethod' and len(self.xml_method_args) > 0:
|
|
self.self_arg = self.xml_method_args[0]
|
|
self.xml_method_args = self.xml_method_args[1:]
|
|
|
|
def remove_const_from_complete_type(self, complete_type):
|
|
splitted_type = complete_type.split(' ')
|
|
while 'const' in splitted_type:
|
|
splitted_type.remove('const')
|
|
return ' '.join(splitted_type)
|
|
|
|
def find_class_definition(self, basic_type):
|
|
basic_type = strip_leading_linphone(basic_type)
|
|
for c in self.linphone_module.classes:
|
|
if c['class_name'] == basic_type:
|
|
return c
|
|
return None
|
|
|
|
def format(self):
|
|
self.parse_method_node()
|
|
body = self.format_local_variables_definition()
|
|
body += self.format_arguments_parsing()
|
|
body += self.format_enter_trace()
|
|
body += self.format_c_function_call()
|
|
body += self.format_return_trace()
|
|
body += self.format_return_result()
|
|
return body
|
|
|
|
class NewMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
MethodDefinition.__init__(self, linphone_module, class_, method_node)
|
|
|
|
def format_local_variables_definition(self):
|
|
return "\tpylinphone_{class_name}Object *self = (pylinphone_{class_name}Object *)type->tp_alloc(type, 0);\n".format(class_name=self.class_['class_name'])
|
|
|
|
def format_arguments_parsing(self):
|
|
return ''
|
|
|
|
def format_enter_trace(self):
|
|
return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s()\", __FUNCTION__);\n"
|
|
|
|
def format_c_function_call(self):
|
|
return "\tself->native_ptr = NULL;\n"
|
|
|
|
def format_return_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n"
|
|
|
|
def format_return_result(self):
|
|
return "\treturn (PyObject *)self;"
|
|
|
|
class NewFromNativePointerMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_):
|
|
MethodDefinition.__init__(self, linphone_module, class_, None)
|
|
|
|
def format_local_variables_definition(self):
|
|
return "\tpylinphone_{class_name}Object *self;\n".format(class_name=self.class_['class_name'])
|
|
|
|
def format_arguments_parsing(self):
|
|
return ''
|
|
|
|
def format_enter_trace(self):
|
|
return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s(%p)\", __FUNCTION__, native_ptr);\n"
|
|
|
|
def format_c_function_call(self):
|
|
set_user_data_func_call = ''
|
|
if self.class_['class_has_user_data']:
|
|
set_user_data_func_call = "\t{function_prefix}set_user_data(self->native_ptr, self);\n".format(function_prefix=self.class_['class_c_function_prefix'])
|
|
return \
|
|
""" if (native_ptr == NULL) {{
|
|
{none_trace}
|
|
Py_RETURN_NONE;
|
|
}}
|
|
self = (pylinphone_{class_name}Object *)PyObject_New(pylinphone_{class_name}Object, type);
|
|
if (self == NULL) {{
|
|
{none_trace}
|
|
Py_RETURN_NONE;
|
|
}}
|
|
self->native_ptr = ({class_cname} *)native_ptr;
|
|
{set_user_data_func_call}
|
|
""".format(class_name=self.class_['class_name'], class_cname=self.class_['class_cname'],
|
|
none_trace=self.format_return_none_trace(), set_user_data_func_call=set_user_data_func_call)
|
|
|
|
def format_return_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n"
|
|
|
|
def format_return_result(self):
|
|
return "\treturn (PyObject *)self;"
|
|
|
|
class DeallocMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
MethodDefinition.__init__(self, linphone_module, class_, method_node)
|
|
|
|
def format_local_variables_definition(self):
|
|
func = "pylinphone_{class_name}_get_native_ptr".format(class_name=self.class_['class_name'])
|
|
return \
|
|
""" {arg_type} * native_ptr = {func}(self);
|
|
""".format(arg_type=self.class_['class_cname'], func=func)
|
|
|
|
def format_arguments_parsing(self):
|
|
return ''
|
|
|
|
def format_enter_trace(self):
|
|
return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s(%p [%p])\", __FUNCTION__, self, native_ptr);\n"
|
|
|
|
def format_c_function_call(self):
|
|
reset_user_data_code = ''
|
|
if self.class_['class_name'] != 'Core' and self.class_['class_has_user_data']:
|
|
reset_user_data_code += \
|
|
"""if (native_ptr != NULL) {{
|
|
{function_prefix}set_user_data(native_ptr, NULL);
|
|
}}
|
|
""".format(function_prefix=self.class_['class_c_function_prefix'])
|
|
# Increment the refcount on self to prevent reentrancy in the dealloc method.
|
|
native_ptr_dealloc_code = "Py_INCREF(self);\n"
|
|
if self.class_['class_refcountable']:
|
|
native_ptr_dealloc_code += \
|
|
""" if (native_ptr != NULL) {{
|
|
{function_prefix}unref(native_ptr);
|
|
}}
|
|
""".format(function_prefix=self.class_['class_c_function_prefix'])
|
|
elif self.class_['class_destroyable']:
|
|
native_ptr_dealloc_code += \
|
|
""" if (native_ptr != NULL) {{
|
|
{function_prefix}destroy(native_ptr);
|
|
}}
|
|
""".format(function_prefix=self.class_['class_c_function_prefix'])
|
|
return \
|
|
""" {reset_user_data_code}
|
|
{native_ptr_dealloc_code}
|
|
pylinphone_dispatch_messages();
|
|
self->ob_type->tp_free(self);
|
|
""".format(reset_user_data_code=reset_user_data_code, native_ptr_dealloc_code=native_ptr_dealloc_code)
|
|
|
|
def format_return_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);"
|
|
|
|
def format_return_result(self):
|
|
return ''
|
|
|
|
class GetterMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
MethodDefinition.__init__(self, linphone_module, class_, method_node)
|
|
|
|
class SetterMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
MethodDefinition.__init__(self, linphone_module, class_, method_node)
|
|
|
|
def format_arguments_parsing(self):
|
|
if self.first_argument_type.check_func is None:
|
|
attribute_type_check_code = \
|
|
"""if ((value != Py_None) && !PyObject_IsInstance(value, (PyObject *)&pylinphone_{class_name}Type)) {{
|
|
PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a linphone.{class_name} instance.");
|
|
return -1;
|
|
}}
|
|
""".format(class_name=self.first_arg_class, attribute_name=self.attribute_name)
|
|
else:
|
|
checknotnone = ''
|
|
if self.first_argument_type.type_str == 'string':
|
|
checknotnone = "(value != Py_None) && "
|
|
attribute_type_check_code = \
|
|
"""if ({checknotnone}!{checkfunc}(value)) {{
|
|
PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a {type_str}.");
|
|
return -1;
|
|
}}
|
|
""".format(checknotnone=checknotnone, checkfunc=self.first_argument_type.check_func, attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str)
|
|
attribute_conversion_code = ''
|
|
if (self.first_argument_type.convert_func is None) or \
|
|
(self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None):
|
|
attribute_conversion_code += "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name)
|
|
if self.first_argument_type.convert_func is not None:
|
|
cast_code = ''
|
|
suffix = ''
|
|
if self.first_argument_type.cast_convert_func_result:
|
|
cast_code = "({arg_type})".format(arg_type=self.first_arg_complete_type)
|
|
if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None:
|
|
suffix = '_native_obj'
|
|
attribute_conversion_code += "\t{arg_name}{suffix} = {cast_code}{convertfunc}(value);\n".format(
|
|
arg_name="_" + self.first_arg_name, suffix=suffix, cast_code=cast_code, convertfunc=self.first_argument_type.convert_func)
|
|
attribute_native_ptr_check_code = ''
|
|
if self.first_argument_type.use_native_pointer:
|
|
attribute_native_ptr_check_code = \
|
|
"""if ({arg_name} != Py_None) {{
|
|
if (({arg_name}_native_ptr = pylinphone_{arg_class}_get_native_ptr({arg_name})) == NULL) {{
|
|
PyErr_SetString(PyExc_TypeError, "Invalid linphone.{arg_class} instance.");
|
|
return -1;
|
|
}}
|
|
}}
|
|
""".format(arg_name="_" + self.first_arg_name, arg_class=self.first_arg_class)
|
|
return \
|
|
""" {native_ptr_check_code}
|
|
if (value == NULL) {{
|
|
PyErr_SetString(PyExc_TypeError, "Cannot delete the '{attribute_name}' attribute.");
|
|
return -1;
|
|
}}
|
|
{attribute_type_check_code}
|
|
{attribute_conversion_code}
|
|
{attribute_native_ptr_check_code}
|
|
""".format(attribute_name=self.attribute_name,
|
|
native_ptr_check_code=self.format_class_native_pointer_check(True),
|
|
attribute_type_check_code=attribute_type_check_code,
|
|
attribute_conversion_code=attribute_conversion_code,
|
|
attribute_native_ptr_check_code=attribute_native_ptr_check_code)
|
|
|
|
def format_c_function_call(self):
|
|
suffix = ''
|
|
if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.use_native_pointer:
|
|
suffix = '_native_ptr'
|
|
elif self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_func is not None:
|
|
suffix = '_native_obj'
|
|
return \
|
|
""" {method_name}(native_ptr, {arg_name}{suffix});
|
|
pylinphone_dispatch_messages();
|
|
""".format(arg_name="_" + self.first_arg_name, method_name=self.method_node.get('name'), suffix=suffix)
|
|
|
|
def format_return_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> 0\", __FUNCTION__);\n"
|
|
|
|
def format_return_result(self):
|
|
return "\treturn 0;"
|
|
|
|
def parse_method_node(self):
|
|
MethodDefinition.parse_method_node(self)
|
|
# Force return value type of setter function to prevent declaring useless local variables
|
|
# TODO: Investigate. Maybe we should decide that setters must always return an int value.
|
|
self.xml_method_return = None
|
|
self.attribute_name = self.method_node.get('property_name')
|
|
self.first_arg_type = self.xml_method_args[0].get('type')
|
|
self.first_arg_complete_type = self.xml_method_args[0].get('completetype')
|
|
self.first_arg_contained_type = self.xml_method_args[0].get('containedtype')
|
|
self.first_arg_name = self.xml_method_args[0].get('name')
|
|
self.first_argument_type = ArgumentType(self.first_arg_type, self.first_arg_complete_type, self.first_arg_contained_type, self.linphone_module)
|
|
self.first_arg_class = strip_leading_linphone(self.first_arg_type)
|
|
|
|
class EventCallbackMethodDefinition(MethodDefinition):
|
|
def __init__(self, linphone_module, class_, method_node = None):
|
|
MethodDefinition.__init__(self, linphone_module, class_, method_node)
|
|
|
|
def format_local_variables_definition(self):
|
|
common = \
|
|
""" pylinphone_CoreObject *pylc = (pylinphone_CoreObject *)linphone_core_get_user_data(lc);
|
|
PyObject *func = PyDict_GetItemString(pylc->vtable_dict, "{name}");
|
|
PyGILState_STATE pygil_state;""".format(name=self.class_['event_name'])
|
|
specific = ''
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = 'py' + xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
if argument_type.fmt_str == 'O':
|
|
specific += "\tPyObject * " + arg_name + " = NULL;\n"
|
|
return "{common}\n{specific}".format(common=common, specific=specific)
|
|
|
|
def format_arguments_parsing(self):
|
|
return "\tpygil_state = PyGILState_Ensure();\n"
|
|
|
|
def format_enter_trace(self):
|
|
fmt = '%p'
|
|
args = ['lc']
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
if fmt != '':
|
|
fmt += ', '
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
fmt += argument_type.cfmt_str
|
|
args.append(arg_name)
|
|
args=', '.join(args)
|
|
if args != '':
|
|
args = ', ' + args
|
|
return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s({fmt})\", __FUNCTION__{args});\n".format(fmt=fmt, args=args)
|
|
|
|
def format_c_function_call(self):
|
|
create_python_objects_code = ''
|
|
fmt = 'O'
|
|
args = ['pylc']
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
|
|
fmt += argument_type.fmt_str
|
|
if argument_type.fmt_str == 'O':
|
|
args.append('py' + arg_name)
|
|
else:
|
|
args.append(arg_name)
|
|
if argument_type.fmt_str == 'O':
|
|
type_class = self.find_class_definition(arg_type)
|
|
get_user_data_code = ''
|
|
new_from_native_pointer_code = "py{name} = pylinphone_{arg_type}_new_from_native_ptr(&pylinphone_{arg_type}Type, {name});".format(name=arg_name, arg_type=strip_leading_linphone(arg_type))
|
|
if type_class is not None and type_class['class_has_user_data']:
|
|
get_user_data_function = type_class['class_c_function_prefix'] + "get_user_data"
|
|
get_user_data_code = "py{name} = {get_user_data_function}({name});".format(name=arg_name, get_user_data_function=get_user_data_function)
|
|
create_python_objects_code += \
|
|
""" {get_user_data_code}
|
|
if (py{name} == NULL) {{
|
|
{new_from_native_pointer_code}
|
|
}}
|
|
""".format(name=arg_name, get_user_data_code=get_user_data_code, new_from_native_pointer_code=new_from_native_pointer_code)
|
|
args=', '.join(args)
|
|
return \
|
|
""" if ((func != NULL) && PyCallable_Check(func)) {{
|
|
{create_python_objects_code}
|
|
if (PyEval_CallObject(func, Py_BuildValue("{fmt}", {args})) == NULL) {{
|
|
PyErr_Print();
|
|
}}
|
|
}}
|
|
""".format(fmt=fmt.replace('O', 'N'), args=args, create_python_objects_code=create_python_objects_code)
|
|
|
|
def format_return_trace(self):
|
|
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);\n"
|
|
|
|
def format_return_result(self):
|
|
return '\tPyGILState_Release(pygil_state);'
|
|
|
|
def format(self):
|
|
body = MethodDefinition.format(self)
|
|
arguments = ['LinphoneCore * lc']
|
|
for xml_method_arg in self.xml_method_args:
|
|
arg_name = xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arguments.append(arg_complete_type + ' ' + arg_name)
|
|
definition = \
|
|
"""static void pylinphone_Core_callback_{event_name}({arguments}) {{
|
|
{body}
|
|
}}
|
|
""".format(event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
|
|
return definition
|
|
|
|
|
|
class LinphoneModule(object):
|
|
def __init__(self, tree, blacklisted_classes, blacklisted_events, blacklisted_functions, hand_written_functions):
|
|
self.internal_instance_method_names = ['destroy', 'ref', 'unref']
|
|
self.internal_property_names = ['user_data']
|
|
self.mslist_types = Set([])
|
|
self.enums = []
|
|
self.enum_names = []
|
|
xml_enums = tree.findall("./enums/enum")
|
|
for xml_enum in xml_enums:
|
|
if xml_enum.get('deprecated') == 'true':
|
|
continue
|
|
e = {}
|
|
e['enum_name'] = strip_leading_linphone(xml_enum.get('name'))
|
|
e['enum_doc'] = self.__format_doc_content(xml_enum.find('briefdescription'), xml_enum.find('detaileddescription'))
|
|
e['enum_doc'] += "\n\nValues:\n"
|
|
e['enum_values'] = []
|
|
xml_enum_values = xml_enum.findall("./values/value")
|
|
for xml_enum_value in xml_enum_values:
|
|
if xml_enum_value.get('deprecated') == 'true':
|
|
continue
|
|
v = {}
|
|
v['enum_value_cname'] = xml_enum_value.get('name')
|
|
v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname'])
|
|
v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription'))
|
|
e['enum_doc'] += '\t' + v['enum_value_name'] + ': ' + v['enum_value_doc'] + '\n'
|
|
e['enum_values'].append(v)
|
|
e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc'])
|
|
self.enums.append(e)
|
|
self.enum_names.append(e['enum_name'])
|
|
self.events = []
|
|
self.classes = []
|
|
xml_classes = tree.findall("./classes/class")
|
|
for xml_class in xml_classes:
|
|
if xml_class.get('deprecated') == 'true':
|
|
continue
|
|
if xml_class.get('name') in blacklisted_classes:
|
|
continue
|
|
c = {}
|
|
c['class_xml_node'] = xml_class
|
|
c['class_cname'] = xml_class.get('name')
|
|
c['class_name'] = strip_leading_linphone(c['class_cname'])
|
|
c['class_c_function_prefix'] = xml_class.get('cfunctionprefix')
|
|
c['class_doc'] = self.__format_doc(xml_class.find('briefdescription'), xml_class.find('detaileddescription'))
|
|
c['class_refcountable'] = (xml_class.get('refcountable') == 'true')
|
|
c['class_destroyable'] = (xml_class.get('destroyable') == 'true')
|
|
c['class_has_user_data'] = False
|
|
c['class_type_methods'] = []
|
|
c['class_type_hand_written_methods'] = []
|
|
c['class_instance_hand_written_methods'] = []
|
|
c['class_hand_written_properties'] = []
|
|
c['class_object_members'] = ''
|
|
if c['class_name'] == 'Core':
|
|
c['class_object_members'] = "\tPyObject *vtable_dict;"
|
|
xml_events = xml_class.findall("./events/event")
|
|
for xml_event in xml_events:
|
|
if xml_event.get('deprecated') == 'true':
|
|
continue
|
|
if xml_event.get('name') in blacklisted_events:
|
|
continue
|
|
ev = {}
|
|
ev['event_xml_node'] = xml_event
|
|
ev['event_cname'] = xml_event.get('name')
|
|
ev['event_name'] = compute_event_name(ev['event_cname'])
|
|
ev['event_doc'] = self.__format_doc(xml_event.find('briefdescription'), xml_event.find('detaileddescription'))
|
|
self.events.append(ev)
|
|
xml_type_methods = xml_class.findall("./classmethods/classmethod")
|
|
for xml_type_method in xml_type_methods:
|
|
if xml_type_method.get('deprecated') == 'true':
|
|
continue
|
|
method_name = xml_type_method.get('name')
|
|
if method_name in blacklisted_functions:
|
|
continue
|
|
m = {}
|
|
m['method_name'] = method_name.replace(c['class_c_function_prefix'], '')
|
|
if method_name in hand_written_functions:
|
|
c['class_type_hand_written_methods'].append(m)
|
|
else:
|
|
m['method_xml_node'] = xml_type_method
|
|
c['class_type_methods'].append(m)
|
|
c['class_instance_methods'] = []
|
|
xml_instance_methods = xml_class.findall("./instancemethods/instancemethod")
|
|
for xml_instance_method in xml_instance_methods:
|
|
if xml_instance_method.get('deprecated') == 'true':
|
|
continue
|
|
method_name = xml_instance_method.get('name')
|
|
if method_name in blacklisted_functions:
|
|
continue
|
|
if method_name.replace(c['class_c_function_prefix'], '') in self.internal_instance_method_names:
|
|
continue
|
|
m = {}
|
|
m['method_name'] = method_name.replace(c['class_c_function_prefix'], '')
|
|
if method_name in hand_written_functions:
|
|
c['class_instance_hand_written_methods'].append(m)
|
|
else:
|
|
m['method_xml_node'] = xml_instance_method
|
|
c['class_instance_methods'].append(m)
|
|
c['class_properties'] = []
|
|
xml_properties = xml_class.findall("./properties/property")
|
|
for xml_property in xml_properties:
|
|
property_name = xml_property.get('name')
|
|
if property_name == 'user_data':
|
|
c['class_has_user_data'] = True
|
|
if property_name in self.internal_property_names:
|
|
continue
|
|
p = {}
|
|
p['property_name'] = property_name
|
|
xml_property_getter = xml_property.find("./getter")
|
|
xml_property_setter = xml_property.find("./setter")
|
|
handwritten_property = False
|
|
if xml_property_getter is not None:
|
|
if xml_property_getter.get('name') in blacklisted_functions or xml_property_getter.get('deprecated') == 'true':
|
|
continue
|
|
elif xml_property_getter.get('name') in hand_written_functions:
|
|
handwritten_property = True
|
|
if xml_property_setter is not None:
|
|
if xml_property_setter.get('name') in blacklisted_functions or xml_property_setter.get('deprecated') == 'true':
|
|
continue
|
|
elif xml_property_setter.get('name') in hand_written_functions:
|
|
handwritten_property = True
|
|
if handwritten_property:
|
|
p['getter_reference'] = 'NULL'
|
|
p['setter_reference'] = 'NULL'
|
|
if xml_property_getter is not None:
|
|
p['getter_reference'] = '(getter)pylinphone_' + c['class_name'] + '_get_' + p['property_name']
|
|
if xml_property_setter is not None:
|
|
p['setter_reference'] = '(setter)pylinphone_' + c['class_name'] + '_set_' + p['property_name']
|
|
c['class_hand_written_properties'].append(p)
|
|
else:
|
|
if xml_property_getter is not None:
|
|
xml_property_getter.set('property_name', property_name)
|
|
p['getter_name'] = xml_property_getter.get('name').replace(c['class_c_function_prefix'], '')
|
|
p['getter_xml_node'] = xml_property_getter
|
|
p['getter_reference'] = "(getter)pylinphone_" + c['class_name'] + "_" + p['getter_name']
|
|
p['getter_definition_begin'] = "static PyObject * pylinphone_" + c['class_name'] + "_" + p['getter_name'] + "(PyObject *self, void *closure) {"
|
|
p['getter_definition_end'] = "}"
|
|
else:
|
|
p['getter_reference'] = "NULL"
|
|
if xml_property_setter is not None:
|
|
xml_property_setter.set('property_name', property_name)
|
|
p['setter_name'] = xml_property_setter.get('name').replace(c['class_c_function_prefix'], '')
|
|
p['setter_xml_node'] = xml_property_setter
|
|
p['setter_reference'] = "(setter)pylinphone_" + c['class_name'] + "_" + p['setter_name']
|
|
p['setter_definition_begin'] = "static int pylinphone_" + c['class_name'] + "_" + p['setter_name'] + "(PyObject *self, PyObject *value, void *closure) {"
|
|
p['setter_definition_end'] = "}"
|
|
else:
|
|
p['setter_reference'] = "NULL"
|
|
c['class_properties'].append(p)
|
|
self.classes.append(c)
|
|
# Format events definitions
|
|
for ev in self.events:
|
|
ev['event_callback_definition'] = EventCallbackMethodDefinition(self, ev, ev['event_xml_node']).format()
|
|
ev['event_vtable_reference'] = "_vtable.{name} = pylinphone_Core_callback_{name};".format(name=ev['event_name'])
|
|
# Format methods' bodies
|
|
for c in self.classes:
|
|
xml_new_method = c['class_xml_node'].find("./classmethods/classmethod[@name='" + c['class_c_function_prefix'] + "new']")
|
|
try:
|
|
c['new_body'] = NewMethodDefinition(self, c, xml_new_method).format()
|
|
except Exception, e:
|
|
e.args += (c['class_name'], 'new_body')
|
|
raise
|
|
try:
|
|
c['new_from_native_pointer_body'] = NewFromNativePointerMethodDefinition(self, c).format()
|
|
except Exception, e:
|
|
e.args += (c['class_name'], 'new_from_native_pointer_body')
|
|
raise
|
|
try:
|
|
for m in c['class_type_methods']:
|
|
m['method_body'] = MethodDefinition(self, c, m['method_xml_node']).format()
|
|
m['method_doc'] = self.__format_method_doc(m['method_xml_node'])
|
|
for m in c['class_instance_methods']:
|
|
m['method_body'] = MethodDefinition(self, c, m['method_xml_node']).format()
|
|
m['method_doc'] = self.__format_method_doc(m['method_xml_node'])
|
|
except Exception, e:
|
|
e.args += (c['class_name'], m['method_name'])
|
|
raise
|
|
try:
|
|
for p in c['class_properties']:
|
|
p['property_doc'] = ''
|
|
if p.has_key('setter_xml_node'):
|
|
p['setter_body'] = SetterMethodDefinition(self, c, p['setter_xml_node']).format()
|
|
p['property_doc'] = self.__format_setter_doc(p['setter_xml_node'])
|
|
if p.has_key('getter_xml_node'):
|
|
p['getter_body'] = GetterMethodDefinition(self, c, p['getter_xml_node']).format()
|
|
if p['property_doc'] == '':
|
|
p['property_doc'] = self.__format_getter_doc(p['getter_xml_node'])
|
|
except Exception, e:
|
|
e.args += (c['class_name'], p['property_name'])
|
|
raise
|
|
try:
|
|
if c['class_refcountable']:
|
|
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "unref']")
|
|
c['dealloc_body'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
|
|
elif c['class_destroyable']:
|
|
xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "destroy']")
|
|
c['dealloc_body'] = DeallocMethodDefinition(self, c, xml_instance_method).format()
|
|
else:
|
|
c['dealloc_body'] = DeallocMethodDefinition(self, c).format()
|
|
except Exception, e:
|
|
e.args += (c['class_name'], 'dealloc_body')
|
|
raise
|
|
# Convert mslist_types to a list of dictionaries for the template
|
|
d = []
|
|
for mslist_type in self.mslist_types:
|
|
t = {}
|
|
t['c_contained_type'] = mslist_type
|
|
t['python_contained_type'] = strip_leading_linphone(mslist_type)
|
|
d.append(t)
|
|
self.mslist_types = d
|
|
|
|
def __format_doc_node(self, node):
|
|
desc = ''
|
|
if node.tag == 'para':
|
|
if node.text is not None:
|
|
desc += node.text.strip()
|
|
for n in list(node):
|
|
desc += self.__format_doc_node(n)
|
|
elif node.tag == 'note':
|
|
if node.text is not None:
|
|
desc += node.text.strip()
|
|
for n in list(node):
|
|
desc += self.__format_doc_node(n)
|
|
elif node.tag == 'ref':
|
|
if node.text is not None:
|
|
desc += ' ' + node.text.strip() + ' '
|
|
tail = node.tail.strip()
|
|
if tail != '':
|
|
if node.tag != 'ref':
|
|
desc += '\n'
|
|
desc += tail
|
|
if node.tag == 'para':
|
|
desc += '\n'
|
|
return desc
|
|
|
|
def __format_doc_content(self, brief_description, detailed_description):
|
|
doc = ''
|
|
if brief_description is None:
|
|
brief_description = ''
|
|
if detailed_description is None:
|
|
detailed_description = ''
|
|
else:
|
|
desc = ''
|
|
for node in list(detailed_description):
|
|
desc += self.__format_doc_node(node) + '\n'
|
|
detailed_description = desc.strip()
|
|
brief_description = brief_description.strip()
|
|
doc += brief_description
|
|
if detailed_description != '':
|
|
if doc != '':
|
|
doc += '\n\n'
|
|
doc += detailed_description
|
|
return doc
|
|
|
|
def __replace_doc_special_chars(self, doc):
|
|
return doc.replace('"', '').encode('string-escape')
|
|
|
|
def __format_doc(self, brief_description, detailed_description):
|
|
doc = self.__format_doc_content(brief_description, detailed_description)
|
|
doc = self.__replace_doc_special_chars(doc)
|
|
return doc
|
|
|
|
def __format_method_doc(self, xml_node):
|
|
doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription'))
|
|
xml_method_return = xml_node.find('./return')
|
|
xml_method_args = xml_node.findall('./arguments/argument')
|
|
method_type = xml_node.tag
|
|
if method_type != 'classmethod' and len(xml_method_args) > 0:
|
|
xml_method_args = xml_method_args[1:]
|
|
doc += '\n'
|
|
if len(xml_method_args) > 0:
|
|
for xml_method_arg in xml_method_args:
|
|
arg_name = xml_method_arg.get('name')
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self)
|
|
arg_doc = self.__format_doc_content(None, xml_method_arg.find('description'))
|
|
doc += '\n:param ' + arg_name + ':'
|
|
if arg_doc != '':
|
|
doc += ' ' + arg_doc
|
|
doc += '\n:type ' + arg_name + ': ' + argument_type.type_str
|
|
if xml_method_return is not None:
|
|
return_type = xml_method_return.get('type')
|
|
return_complete_type = xml_method_return.get('completetype')
|
|
return_contained_type = xml_method_return.get('containedtype')
|
|
if return_complete_type != 'void':
|
|
return_doc = self.__format_doc_content(None, xml_method_return.find('description'))
|
|
return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self)
|
|
doc += '\n:returns: ' + return_doc
|
|
doc += '\n:rtype: ' + return_argument_type.type_str
|
|
doc = self.__replace_doc_special_chars(doc)
|
|
return doc
|
|
|
|
def __format_setter_doc(self, xml_node):
|
|
xml_method_arg = xml_node.findall('./arguments/argument')[1]
|
|
arg_type = xml_method_arg.get('type')
|
|
arg_complete_type = xml_method_arg.get('completetype')
|
|
arg_contained_type = xml_method_arg.get('containedtype')
|
|
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self)
|
|
doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription'))
|
|
doc = '[' + argument_type.type_str + '] ' + doc
|
|
doc = self.__replace_doc_special_chars(doc)
|
|
return doc
|
|
|
|
def __format_getter_doc(self, xml_node):
|
|
xml_method_return = xml_node.find('./return')
|
|
return_type = xml_method_return.get('type')
|
|
return_complete_type = xml_method_return.get('completetype')
|
|
return_contained_type = xml_method_return.get('containedtype')
|
|
return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self)
|
|
doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription'))
|
|
doc = '[' + return_argument_type.type_str + '] ' + doc
|
|
doc = self.__replace_doc_special_chars(doc)
|
|
return doc
|