diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index 1e3b44492..2581ac342 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -37,6 +37,110 @@ def compute_event_name(s): return event_name +class ArgumentType: + def __init__(self, basic_type, complete_type, linphone_module): + self.basic_type = basic_type + self.complete_type = complete_type + self.linphone_module = linphone_module + self.type_str = None + self.check_func = None + self.convert_func = None + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.__compute() + + 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 = 'PyLong_Check' + self.convert_func = 'PyLong_AsUnsignedLong' + self.fmt_str = 'I' + self.cfmt_str = '%u' + else: + self.type_str = 'int' + self.check_func = 'PyLong_Check' + self.convert_func = 'PyLong_AsLong' + 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 = 'PyLong_Check' + self.convert_func = 'PyLong_AsLong' + 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 = 'PyLong_Check' + self.convert_func = 'PyLong_AsUnsignedLong' + 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 = 'PyLong_Check' + self.convert_func = 'PyLong_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 = 'i' + self.cfmt_str = '%d' + 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' + + class MethodDefinition: def __init__(self, linphone_module, class_, method_node = None): self.body = '' @@ -60,7 +164,8 @@ class MethodDefinition: self.return_complete_type = self.xml_method_return.get('completetype') if self.return_complete_type != 'void': body += "\t" + self.return_complete_type + " cresult;\n" - self.build_value_format = self.ctype_to_python_format(self.return_type, self.return_complete_type) + argument_type = ArgumentType(self.return_type, self.return_complete_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" @@ -70,9 +175,9 @@ class MethodDefinition: arg_name = "_" + xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - fmt = self.ctype_to_python_format(arg_type, arg_complete_type) - self.parse_tuple_format += fmt - if fmt == 'O': + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + self.parse_tuple_format += argument_type.fmt_str + if argument_type.fmt_str == 'O': body += "\tPyObject * " + arg_name + ";\n" body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr;\n" elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names: @@ -113,9 +218,12 @@ class MethodDefinition: arg_complete_type = xml_method_arg.get('completetype') if fmt != '': fmt += ', ' - f, a = self.ctype_to_str_format(arg_name, arg_type, arg_complete_type) - fmt += f - args += a + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + fmt += argument_type.cfmt_str + args.append(arg_name) + if argument_type.fmt_str == 'O': + fmt += ' [' + argument_type.cfmt_str + ']' + args.append(arg_name) args=', '.join(args) if args != '': args = ', ' + args @@ -128,8 +236,8 @@ class MethodDefinition: arg_name = "_" + xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - type_str, checkfunc, convertfunc = self.ctype_to_python_type(arg_type, arg_complete_type) - if convertfunc is None: + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + if argument_type.convert_func is None: arg_names.append(arg_name + "_native_ptr") else: arg_names.append(arg_name) @@ -221,8 +329,8 @@ class MethodDefinition: arg_name = "_" + xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - fmt = self.ctype_to_python_format(arg_type, arg_complete_type) - if fmt == 'O': + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + if argument_type.fmt_str == 'O': body += \ """ if (({arg_name}_native_ptr = pylinphone_{arg_type}_get_native_ptr({arg_name})) == NULL) {{ return NULL; @@ -287,78 +395,6 @@ class MethodDefinition: else: return ('%p', [name]) - def ctype_to_python_format(self, basic_type, complete_type): - splitted_type = complete_type.split(' ') - if basic_type == 'char': - if '*' in splitted_type: - return 'z' - elif 'unsigned' in splitted_type: - return 'b' - elif basic_type == 'int': - # TODO: - return 'i' - elif basic_type == 'int8_t': - return 'c' - elif basic_type == 'uint8_t': - return 'b' - elif basic_type == 'int16_t': - return 'h' - elif basic_type == 'uint16_t': - return 'H' - elif basic_type == 'int32_t': - return 'l' - elif basic_type == 'uint32_t': - return 'k' - elif basic_type == 'int64_t': - return 'L' - elif basic_type == 'uint64_t': - return 'K' - elif basic_type == 'size_t': - return 'n' - elif basic_type == 'float': - return 'f' - elif basic_type == 'double': - return 'd' - elif basic_type == 'bool_t': - return 'i' - else: - if strip_leading_linphone(basic_type) in self.linphone_module.enum_names: - return 'i' - else: - return 'O' - - def ctype_to_python_type(self, basic_type, complete_type): - splitted_type = complete_type.split(' ') - if basic_type == 'char': - if '*' in splitted_type: - return ('string', 'PyString_Check', 'PyString_AsString') - else: - return ('int', 'PyInt_Check', 'PyInt_AsLong') - elif basic_type == 'int': - if 'unsigned' in splitted_type: - return ('unsigned int', 'PyLong_Check', 'PyLong_AsUnsignedLong') - else: - return ('int', 'PyLong_Check', 'PyLong_AsLong') - elif basic_type in ['int8_t', 'int16_t' 'int32_t']: - return ('int', 'PyLong_Check', 'PyLong_AsLong') - elif basic_type in ['uint8_t', 'uin16_t', 'uint32_t']: - return ('unsigned int', 'PyLong_Check', 'PyLong_AsUnsignedLong') - elif basic_type == 'int64_t': - return ('64bits int', 'PyLong_Check', 'PyLong_AsLongLong') - elif basic_type == 'uint64_t': - return ('64bits unsigned int', 'PyLong_Check', 'PyLong_AsUnsignedLongLong') - elif basic_type == 'size_t': - return ('size_t', 'PyLong_Check', 'PyLong_AsSsize_t') - elif basic_type in ['float', 'double']: - return ('float', 'PyFloat_Check', 'PyFloat_AsDouble') - elif basic_type == 'bool_t': - return ('bool', 'PyBool_Check', 'PyInt_AsLong') - else: - if strip_leading_linphone(basic_type) in self.linphone_module.enum_names: - return ('int', 'PyInt_Check', 'PyInt_AsLong') - else: - return (None, None, None) - def find_class_definition(self, basic_type): basic_type = strip_leading_linphone(basic_type) for c in self.linphone_module.classes: @@ -488,7 +524,7 @@ class SetterMethodDefinition(MethodDefinition): MethodDefinition.__init__(self, linphone_module, class_, method_node) def format_arguments_parsing(self): - if self.checkfunc is None: + if self.first_argument_type.check_func is None: attribute_type_check_code = \ """if (!PyObject_IsInstance(value, (PyObject *)&pylinphone_{class_name}Type)) {{ PyErr_SetString(PyExc_TypeError, "The {attribute_name} attribute value must be a linphone.{class_name} instance"); @@ -497,21 +533,21 @@ class SetterMethodDefinition(MethodDefinition): """.format(class_name=self.first_arg_class, attribute_name=self.attribute_name) else: checknotnone = '' - if self.type_str == 'string': + 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.checkfunc, attribute_name=self.attribute_name, type_str=self.type_str) - if self.convertfunc is None: +""".format(checknotnone=checknotnone, checkfunc=self.first_argument_type.check_func, attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str) + if self.first_argument_type.convert_func is None: attribute_conversion_code = "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name) else: attribute_conversion_code = "{arg_name} = ({arg_type}){convertfunc}(value);\n".format( - arg_name="_" + self.first_arg_name, arg_type=self.first_arg_complete_type, convertfunc=self.convertfunc) + arg_name="_" + self.first_arg_name, arg_type=self.first_arg_complete_type, convertfunc=self.first_argument_type.convert_func) attribute_native_ptr_check_code = '' - if self.python_fmt == 'O': + if self.first_argument_type.fmt_str == 'O': attribute_native_ptr_check_code = \ """{arg_name}_native_ptr = pylinphone_{arg_class}_get_native_ptr({arg_name}); if ({arg_name}_native_ptr == NULL) {{ @@ -536,7 +572,7 @@ class SetterMethodDefinition(MethodDefinition): def format_c_function_call(self): use_native_ptr = '' - if self.python_fmt == 'O': + if self.first_argument_type.fmt_str == 'O': use_native_ptr = '_native_ptr' return \ """ {method_name}(native_ptr, {arg_name}{use_native_ptr}); @@ -558,9 +594,8 @@ class SetterMethodDefinition(MethodDefinition): 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_name = self.xml_method_args[0].get('name') - self.type_str, self.checkfunc, self.convertfunc = self.ctype_to_python_type(self.first_arg_type, self.first_arg_complete_type) + self.first_argument_type = ArgumentType(self.first_arg_type, self.first_arg_complete_type, self.linphone_module) self.first_arg_class = strip_leading_linphone(self.first_arg_type) - self.python_fmt = self.ctype_to_python_format(self.first_arg_type, self.first_arg_complete_type) class EventCallbackMethodDefinition(MethodDefinition): def __init__(self, linphone_module, class_, method_node = None): @@ -576,8 +611,8 @@ class EventCallbackMethodDefinition(MethodDefinition): arg_name = 'py' + xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - fmt = self.ctype_to_python_format(arg_type, arg_complete_type) - if fmt == 'O': + argument_type = ArgumentType(arg_type, arg_complete_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) @@ -587,8 +622,8 @@ class EventCallbackMethodDefinition(MethodDefinition): arg_name = xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - fmt = self.ctype_to_python_format(arg_type, arg_complete_type) - if fmt == 'O': + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + 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)) @@ -612,9 +647,9 @@ class EventCallbackMethodDefinition(MethodDefinition): arg_complete_type = xml_method_arg.get('completetype') if fmt != '': fmt += ', ' - f, a = self.ctype_to_str_format(arg_name, arg_type, arg_complete_type, with_native_ptr=False) - fmt += f - args += a + argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) + fmt += argument_type.cfmt_str + args.append(arg_name) args=', '.join(args) if args != '': args = ', ' + args @@ -627,9 +662,9 @@ class EventCallbackMethodDefinition(MethodDefinition): arg_name = xml_method_arg.get('name') arg_type = xml_method_arg.get('type') arg_complete_type = xml_method_arg.get('completetype') - f = self.ctype_to_python_format(arg_type, arg_complete_type) - fmt += f - if f == 'O': + argument_type = ArgumentType(arg_type, arg_complete_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)