linphone.py 58.7 KB
Newer Older
Ghislain MARY's avatar
Ghislain MARY committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Ghislain MARY's avatar
Ghislain MARY committed
16

17

18
import re
19
from sets import Set
20 21 22
import sys


23 24 25 26 27 28
def strip_leading_linphone(s):
	if s.lower().startswith('linphone'):
		return s[8:]
	else:
		return s

29 30 31 32 33 34 35 36 37 38 39 40
def remove_useless_enum_prefix(senum, svalue):
	lenum = re.findall('[A-Z][^A-Z]*', senum)
	lvalue = re.findall('[A-Z][^A-Z]*', svalue)
	if len(lenum) == 0 or len(lvalue) == 0:
		return svalue
	if lenum[0] == lvalue[0]:
		i = 0
		while i < len(lenum) and lenum[i] == lvalue[i]:
			i += 1
		return ''.join(lvalue[i:])
	return svalue

41 42 43 44
def is_callback(s):
	return s.startswith('Linphone') and s.endswith('Cb')

def compute_event_name(s, className):
45
	s = strip_leading_linphone(s)
46
	s = s[len(className):-2] # Remove leading class name and tailing 'Cb'
47 48 49 50 51 52 53 54 55
	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

56

57
class HandWrittenCode:
58
	def __init__(self, _class, name, func_list, doc = ''):
59 60 61
		self._class = _class
		self.name = name
		self.func_list = func_list
62
		self.doc = doc
63 64

class HandWrittenInstanceMethod(HandWrittenCode):
65 66
	def __init__(self, _class, name, cfunction, doc = ''):
		HandWrittenCode.__init__(self, _class, name, [cfunction], doc)
67 68

class HandWrittenClassMethod(HandWrittenCode):
69 70
	def __init__(self, _class, name, cfunction, doc = ''):
		HandWrittenCode.__init__(self, _class, name, [cfunction], doc)
71

72 73 74 75
class HandWrittenDeallocMethod(HandWrittenCode):
	def __init__(self, _class, cfunction):
		HandWrittenCode.__init__(self, _class, 'dealloc', [cfunction], '')

76
class HandWrittenProperty(HandWrittenCode):
77
	def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None, doc = ''):
78 79 80 81 82
		func_list = []
		if getter_cfunction is not None:
			func_list.append(getter_cfunction)
		if setter_cfunction is not None:
			func_list.append(setter_cfunction)
83
		HandWrittenCode.__init__(self, _class, name, func_list, doc)
84 85 86 87
		self.getter_cfunction = getter_cfunction
		self.setter_cfunction = setter_cfunction


88
class ArgumentType:
89
	def __init__(self, basic_type, complete_type, contained_type, linphone_module):
90 91
		self.basic_type = basic_type
		self.complete_type = complete_type
92
		self.contained_type = contained_type
93 94
		self.linphone_module = linphone_module
		self.type_str = None
95 96
		self.check_condition = None
		self.convert_code = None
97
		self.convert_from_func = None
98 99
		self.fmt_str = 'O'
		self.cfmt_str = '%p'
100
		self.cnativefmt_str = '%p'
101 102
		self.use_native_pointer = False
		self.cast_convert_func_result = True
103
		self.__compute()
104
		if (self.basic_type == 'MSList' or self.basic_type == 'bctbx_list_t') and self.contained_type is not None and self.contained_type != 'const char *':
105
			self.linphone_module.mslist_types.add(self.contained_type)
106 107 108 109 110 111

	def __compute(self):
		splitted_type = self.complete_type.split(' ')
		if self.basic_type == 'char':
			if '*' in splitted_type:
				self.type_str = 'string'
112 113
				self.check_condition = "!PyString_Check({arg_name})"
				self.convert_code = "{result_name}{result_suffix} = {cast}PyString_AsString({arg_name});\n"
114 115 116 117
				self.fmt_str = 'z'
				self.cfmt_str = '\\"%s\\"'
			else:
				self.type_str = 'int'
118 119
				self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
				self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n"
120 121 122 123 124
				self.fmt_str = 'b'
				self.cfmt_str = '%08x'
		elif self.basic_type == 'int':
			if 'unsigned' in splitted_type:
				self.type_str = 'unsigned int'
125 126
				self.check_condition = "!PyInt_Check({arg_name})"
				self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n"
127 128 129 130
				self.fmt_str = 'I'
				self.cfmt_str = '%u'
			else:
				self.type_str = 'int'
131 132
				self.check_condition = "!PyInt_Check({arg_name})"
				self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n"
133 134 135 136
				self.fmt_str = 'i'
				self.cfmt_str = '%d'
		elif self.basic_type in ['int8_t', 'int16_t' 'int32_t']:
			self.type_str = 'int'
137 138
			self.check_condition = "!PyInt_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n"
139 140 141 142 143 144 145 146 147
			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'
148 149
			self.check_condition = "!PyInt_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n"
150 151 152 153 154 155 156 157 158
			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'
159 160 161 162 163
			self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
			self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(PY_LONG_LONG)PyInt_AsLong({arg_name});
	else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}PyLong_AsLongLong({arg_name});
"""
164 165 166 167
			self.fmt_str = 'L'
			self.cfmt_str = '%ld'
		elif self.basic_type == 'uint64_t':
			self.type_str = '64bits unsigned int'
168 169
			self.check_condition = "!PyLong_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyLong_AsUnsignedLongLong({arg_name});\n"
170 171 172
			self.fmt_str = 'K'
			self.cfmt_str = '%lu'
		elif self.basic_type == 'size_t':
173 174 175 176 177 178
			self.type_str = 'int'
			self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})"
			self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyInt_AsSsize_t({arg_name});
	else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyLong_AsSsize_t({arg_name});
"""
179
			self.fmt_str = 'n'
180
			self.cfmt_str = '%lu'
181 182 183 184 185 186 187 188 189 190 191
		elif self.basic_type == 'float':
			self.type_str = 'float'
			self.check_condition = "!PyFloat_Check({arg_name})"
			self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyInt_AsLong({arg_name});
	else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyLong_AsLong({arg_name});
	else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyFloat_AsDouble({arg_name});
"""
			self.fmt_str = 'f'
			self.cfmt_str = '%f'
		elif self.basic_type == 'double':
192
			self.type_str = 'float'
193 194 195 196 197 198 199
			self.check_condition = "!PyFloat_Check({arg_name})"
			self.convert_code = \
"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyInt_AsLong({arg_name});
	else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyLong_AsLong({arg_name});
	else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyFloat_AsDouble({arg_name});
"""
			self.fmt_str = 'd'
200 201 202
			self.cfmt_str = '%f'
		elif self.basic_type == 'bool_t':
			self.type_str = 'bool'
203 204
			self.check_condition = "!PyBool_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyObject_IsTrue({arg_name});\n"
205 206 207 208
			self.convert_from_func = 'PyBool_FromLong'
			self.fmt_str = 'O'
			self.cfmt_str = '%p'
			self.cnativefmt_str = '%u'
209 210
		elif self.basic_type == 'time_t':
			self.type_str = 'DateTime'
211 212
			self.check_condition = "!PyDateTime_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyDateTime_As_time_t({arg_name});\n"
213 214 215
			self.convert_from_func = 'PyDateTime_From_time_t'
			self.fmt_str = 'O'
			self.cfmt_str = '%p'
216
			self.cnativefmt_str = '%ld'
217
		elif self.basic_type == 'MSList' or self.basic_type == 'bctbx_list_t':
218 219 220 221 222 223 224 225
			if self.contained_type == 'const char *':
				self.type_str = 'list of string'
				self.convert_code = "{result_name}{result_suffix} = {cast}PyList_AsMSListOfString({arg_name});\n"
				self.convert_from_func = 'PyList_FromMSListOfString'
			else:
				self.type_str = 'list of linphone.' + self.contained_type
				self.convert_code = "{result_name}{result_suffix} = {cast}PyList_AsMSListOf" + self.contained_type + "({arg_name});\n"
				self.convert_from_func = 'PyList_FromMSListOf' + self.contained_type
226
			self.check_condition = "!PyList_Check({arg_name})"
227 228
			self.fmt_str = 'O'
			self.cfmt_str = '%p'
229 230
		elif self.basic_type == 'MSVideoSize':
			self.type_str = 'linphone.VideoSize'
231 232
			self.check_condition = "!PyLinphoneVideoSize_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneVideoSize_AsMSVideoSize({arg_name});\n"
233 234 235 236
			self.convert_from_func = 'PyLinphoneVideoSize_FromMSVideoSize'
			self.fmt_str = 'O'
			self.cfmt_str = '%p'
			self.cast_convert_func_result = False
237 238
		elif self.basic_type == 'LCSipTransports':
			self.type_str = 'linphone.SipTransports'
239 240
			self.check_condition = "!PyLinphoneSipTransports_Check({arg_name})"
			self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneSipTransports_AsLCSipTransports({arg_name});\n"
241 242 243 244
			self.convert_from_func = 'PyLinphoneSipTransports_FromLCSipTransports'
			self.fmt_str = 'O'
			self.cfmt_str = '%p'
			self.cast_convert_func_result = False
245 246 247
		else:
			if strip_leading_linphone(self.basic_type) in self.linphone_module.enum_names:
				self.type_str = 'int'
248 249
				self.check_condition = "!PyInt_Check({arg_name})"
				self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n"
250 251
				self.fmt_str = 'i'
				self.cfmt_str = '%d'
252 253
			elif is_callback(self.complete_type):
				self.type_str = 'callable'
254
				self.check_condition = "!PyCallable_Check({arg_name})"
255
				self.cnativefmt_str = None
256
			elif '*' in splitted_type:
257
				self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type)
258
				self.use_native_pointer = True
259 260
			else:
				self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type)
261 262


Ghislain MARY's avatar
Ghislain MARY committed
263
class MethodDefinition:
264
	def __init__(self, linphone_module, class_, method_name = "", method_node = None):
Ghislain MARY's avatar
Ghislain MARY committed
265 266 267 268 269
		self.body = ''
		self.arg_names = []
		self.parse_tuple_format = ''
		self.build_value_format = ''
		self.return_type = 'void'
270
		self.return_complete_type = 'void'
271
		self.return_contained_type = None
272
		self.method_name = method_name
Ghislain MARY's avatar
Ghislain MARY committed
273 274
		self.method_node = method_node
		self.class_ = class_
275
		self.linphone_module = linphone_module
276
		self.self_arg = None
277 278 279
		self.xml_method_return = None
		self.xml_method_args = []
		self.method_type = 'instancemethod'
Ghislain MARY's avatar
Ghislain MARY committed
280 281

	def format_local_variables_definition(self):
282
		body = self.format_local_return_variables_definition()
283
		if self.self_arg is not None:
284
			body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n"
Ghislain MARY's avatar
Ghislain MARY committed
285
		for xml_method_arg in self.xml_method_args:
286
			arg_name = "_" + xml_method_arg.get('name')
287 288
			arg_type = xml_method_arg.get('type')
			arg_complete_type = xml_method_arg.get('completetype')
289 290
			arg_contained_type = xml_method_arg.get('containedtype')
			argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
291
			self.parse_tuple_format += argument_type.fmt_str
292 293 294
			if is_callback(arg_complete_type):
				body += "\tPyObject * {arg_name};\n".format(arg_name=arg_name)
			elif argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
295
				body += "\tPyObject * " + arg_name + ";\n"
296
				body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr = NULL;\n"
297
			elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
298 299
				body += "\tPyObject * " + arg_name + ";\n"
				body += "\t" + arg_complete_type + " " + arg_name + "_native_obj;\n"
300
			elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names:
301
				body += "\tint " + arg_name + ";\n"
302
			else:
303
				body += "\t" + arg_complete_type + " " + arg_name + ";\n"
304
			self.arg_names.append(arg_name)
305
		return body
306

307 308 309 310 311 312
	def format_deprecation_warning(self):
		if self.method_node is not None and self.method_node.get('deprecated') == 'true':
			print(self.class_['class_name'] + "." + self.method_name + " is deprecated")
			return "\tPyErr_WarnEx(PyExc_DeprecationWarning, \"{msg}\", 1);\n".format(msg="{class_name}.{method_name} is deprecated".format(class_name=self.class_['class_name'], method_name=self.method_name))
		return ""

Ghislain MARY's avatar
Ghislain MARY committed
313
	def format_arguments_parsing(self):
314
		class_native_ptr_check_code = ''
315
		if self.self_arg is not None:
316 317
			class_native_ptr_check_code = self.format_class_native_pointer_check(False)
		parse_tuple_code = ''
Ghislain MARY's avatar
Ghislain MARY committed
318
		if len(self.arg_names) > 0:
319
			parse_tuple_code = \
320
"""if (!PyArg_ParseTuple(args, "{fmt}", {args})) {{
321 322 323
		return NULL;
	}}
""".format(fmt=self.parse_tuple_format, args=', '.join(map(lambda a: '&' + a, self.arg_names)))
324 325 326 327 328 329 330
		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)
331 332
			if argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
				args_conversion_code += argument_type.convert_code.format(result_name=arg_name, result_suffix='_native_obj', cast='', arg_name=arg_name)
333 334 335
		return \
"""	{class_native_ptr_check_code}
	{parse_tuple_code}
336
	{args_type_check_code}
337
	{args_native_ptr_check_code}
338
	{args_conversion_code}
339 340
""".format(class_native_ptr_check_code=class_native_ptr_check_code,
		parse_tuple_code=parse_tuple_code,
341
		args_type_check_code=self.format_args_type_check(),
342 343
		args_native_ptr_check_code=self.format_args_native_pointer_check(),
		args_conversion_code=args_conversion_code)
344 345

	def format_enter_trace(self):
346 347 348 349 350 351
		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:
352
			arg_name = "_" + xml_method_arg.get('name')
353 354
			arg_type = xml_method_arg.get('type')
			arg_complete_type = xml_method_arg.get('completetype')
355
			arg_contained_type = xml_method_arg.get('containedtype')
356 357
			if fmt != '':
				fmt += ', '
358
			argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
359 360
			fmt += argument_type.cfmt_str
			args.append(arg_name)
361
			if argument_type.fmt_str == 'O' and argument_type.cnativefmt_str is not None:
362 363 364 365 366
				fmt += ' [' + argument_type.cnativefmt_str + ']'
				if argument_type.use_native_pointer:
					args.append(arg_name + '_native_ptr')
				else:
					args.append(arg_name + '_native_obj')
367
		args = ', '.join(args)
368 369
		if args != '':
			args = ', ' + args
370
		return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s({fmt})\", __FUNCTION__{args});\n".format(fmt=fmt, args=args)
Ghislain MARY's avatar
Ghislain MARY committed
371 372

	def format_c_function_call(self):
373
		arg_names = []
374
		c_function_call_code = ''
375
		for xml_method_arg in self.xml_method_args:
376
			arg_name = "_" + xml_method_arg.get('name')
377 378
			arg_type = xml_method_arg.get('type')
			arg_complete_type = xml_method_arg.get('completetype')
379 380
			arg_contained_type = xml_method_arg.get('containedtype')
			argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
381
			if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
382
				arg_names.append(arg_name + "_native_ptr")
383
			elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None:
384
				arg_names.append(arg_name + "_native_obj")
385 386
			else:
				arg_names.append(arg_name)
387 388 389 390 391 392 393 394 395 396 397
		if is_callback(self.return_complete_type):
			c_function_call_code = "pyresult = ((pylinphone_{class_name}Object *)self)->{callback_name};".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.return_complete_type, self.class_['class_name']))
		else:
			if self.return_complete_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) + ");"
398
		from_native_pointer_code = ''
399
		convert_from_code = ''
400
		build_value_code = ''
401
		cfree_code = ''
402
		result_variable = ''
403
		if self.return_complete_type != 'void':
Ghislain MARY's avatar
Ghislain MARY committed
404
			if self.build_value_format == 'O':
405
				stripped_return_type = strip_leading_linphone(self.return_type)
406
				return_type_class = self.find_class_definition(self.return_type)
407
				if return_type_class is not None:
408
					from_native_pointer_code = "pyresult = pylinphone_{return_type}_from_native_ptr(&pylinphone_{return_type}Type, cresult);\n".format(return_type=stripped_return_type)
409
				else:
410
					return_argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
411 412 413 414
					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)
415 416 417 418
				result_variable = 'pyresult'
			else:
				result_variable = 'cresult'
		if result_variable != '':
419
			build_value_code = "pyret = Py_BuildValue(\"{fmt}\", {result_variable});".format(fmt=self.build_value_format, result_variable=result_variable)
420 421
		if self.return_complete_type == 'char *':
			cfree_code = 'ms_free(cresult);';
422 423 424
		body = \
"""	{c_function_call_code}
	pylinphone_dispatch_messages();
425
	{from_native_pointer_code}
426
	{convert_from_code}
427
	{build_value_code}
428
	{cfree_code}
429
""".format(c_function_call_code=c_function_call_code,
430
		from_native_pointer_code=from_native_pointer_code,
431
		convert_from_code=convert_from_code,
432 433
		build_value_code=build_value_code,
		cfree_code=cfree_code)
434 435 436 437 438 439 440 441 442 443
		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':
444
			return "\treturn pyret;"
445
		return "\tPy_RETURN_NONE;"
446

447 448 449 450 451 452 453 454
	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 \
455
"""native_ptr = pylinphone_{class_name}_get_native_ptr(self);
456 457 458
	if (native_ptr == NULL) {{
		PyErr_SetString(PyExc_TypeError, "Invalid linphone.{class_name} instance");
		return {return_value};
459
	}}
460 461
""".format(class_name=self.class_['class_name'], return_value=return_value)

462
	def format_args_type_check(self):
463 464
		body = ''
		for xml_method_arg in self.xml_method_args:
465
			arg_name = "_" + xml_method_arg.get('name')
466 467
			arg_type = xml_method_arg.get('type')
			arg_complete_type = xml_method_arg.get('completetype')
468 469
			arg_contained_type = xml_method_arg.get('containedtype')
			argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
470
			if argument_type.fmt_str == 'O':
471 472
				if argument_type.use_native_pointer:
					body += \
473
"""	if (({arg_name} != Py_None) && !PyObject_IsInstance({arg_name}, (PyObject *)&pylinphone_{arg_type}Type)) {{
474
		PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance.");
475
		return NULL;
476
	}}
477
""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type), type_str=argument_type.type_str)
478 479
				else:
					body += \
480
"""	if ({check_condition}) {{
481 482 483
		PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance.");
		return NULL;
	}}
484
""".format(arg_name=arg_name, check_condition=argument_type.check_condition.format(arg_name=arg_name), type_str=argument_type.type_str)
485 486
		if body != '':
			body = body[1:] # Remove leading '\t'
487 488 489 490 491 492 493 494
		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')
495 496
			arg_contained_type = xml_method_arg.get('containedtype')
			argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
497
			if argument_type.fmt_str == 'O' and argument_type.use_native_pointer:
498 499 500 501 502 503
				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;
		}}
	}}
504
""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type))
505 506
		if body != '':
			body = body[1:] # Remove leading '\t'
507 508
		return body

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
	def format_local_return_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 is_callback(self.return_complete_type):
			body += "\tPyObject * pyresult;\n"
			body += "\tPyObject * pyret;\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
		elif 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"
		return body

529 530 531 532 533 534 535 536
	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:]
537

538
	def remove_const_from_complete_type(self, complete_type):
539 540 541 542 543
		splitted_type = complete_type.split(' ')
		while 'const' in splitted_type:
			splitted_type.remove('const')
		return ' '.join(splitted_type)

544
	def find_class_definition(self, basic_type):
545 546 547 548 549 550
		basic_type = strip_leading_linphone(basic_type)
		for c in self.linphone_module.classes:
			if c['class_name'] == basic_type:
				return c
		return None

551 552 553
	def format(self):
		self.parse_method_node()
		body = self.format_local_variables_definition()
554
		body += self.format_deprecation_warning()
555 556 557 558 559 560 561 562 563
		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):
564
		MethodDefinition.__init__(self, linphone_module, class_, "new", method_node)
565 566 567 568 569 570 571 572 573 574 575

	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):
576
		return ''
577 578 579 580 581 582 583

	def format_return_trace(self):
		return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n"

	def format_return_result(self):
		return "\treturn (PyObject *)self;"

584 585
class InitMethodDefinition(MethodDefinition):
	def __init__(self, linphone_module, class_, method_node = None):
586
		MethodDefinition.__init__(self, linphone_module, class_, "init", method_node)
587 588

	def format_local_variables_definition(self):
589
		return "\tpylinphone_{class_name}Object *self_obj = (pylinphone_{class_name}Object *)self;\n".format(class_name=self.class_['class_name'])
590 591 592 593 594 595 596 597

	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):
598 599 600 601 602 603 604 605
		specific_member_initialization_code = ''
		for member in self.class_['class_object_members']:
			specific_member_initialization_code += "\tself_obj->{member} = NULL;\n".format(member=member)
		return \
"""	self_obj->native_ptr = NULL;
	self_obj->user_data = NULL;
{specific_member_initialization_code}
""".format(specific_member_initialization_code=specific_member_initialization_code)
606 607 608 609 610 611 612

	def format_return_trace(self):
		return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n"

	def format_return_result(self):
		return "\treturn 0;"

613
class FromNativePointerMethodDefinition(MethodDefinition):
614
	def __init__(self, linphone_module, class_):
615
		MethodDefinition.__init__(self, linphone_module, class_, "from_native_pointer", None)
616 617

	def format_local_variables_definition(self):
618
		return "\tpylinphone_{class_name}Object *self = NULL;\n".format(class_name=self.class_['class_name'])
619 620 621 622 623 624 625 626

	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):
627
		get_user_data_func_call = ''
628 629
		set_user_data_func_call = ''
		if self.class_['class_has_user_data']:
630
			get_user_data_func_call = "self = (pylinphone_{class_name}Object *){function_prefix}get_user_data(native_ptr);".format(class_name=self.class_['class_name'], function_prefix=self.class_['class_c_function_prefix'])
631 632 633 634
			set_user_data_func_call = "{function_prefix}set_user_data(self->native_ptr, self);".format(function_prefix=self.class_['class_c_function_prefix'])
		ref_native_pointer_code = ''
		if self.class_['class_refcountable']:
			ref_native_pointer_code = "{func}(self->native_ptr);".format(func=self.class_['class_c_function_prefix'] + "ref")
635
		return \
636
"""	if (native_ptr == NULL) {{
637 638 639
	{none_trace}
		Py_RETURN_NONE;
	}}
640
	{get_user_data_func_call}
641
	if (self == NULL) {{
642 643 644 645 646 647 648 649
		self = (pylinphone_{class_name}Object *)PyObject_CallObject((PyObject *)&pylinphone_{class_name}Type, NULL);
		if (self == NULL) {{
		{none_trace}
			Py_RETURN_NONE;
		}}
		self->native_ptr = ({class_cname} *)native_ptr;
		{set_user_data_func_call}
		{ref_native_pointer_code}
650 651
	}}
""".format(class_name=self.class_['class_name'], class_cname=self.class_['class_cname'],
652 653
		none_trace=self.format_return_none_trace(),
		get_user_data_func_call=get_user_data_func_call, set_user_data_func_call=set_user_data_func_call,
654
		ref_native_pointer_code=ref_native_pointer_code)
655 656 657 658 659 660 661 662 663

	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):
664
		MethodDefinition.__init__(self, linphone_module, class_, "dealloc", method_node)
665 666 667 668 669 670 671 672

	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):
673 674
		# Check that the dealloc is not called a second time because of reentrancy
		return "\tif (Py_REFCNT(self) < 0) return;\n"
675 676 677 678 679

	def format_enter_trace(self):
		return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s(%p [%p])\", __FUNCTION__, self, native_ptr);\n"

	def format_c_function_call(self):
680 681 682 683 684 685 686
		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'])
687 688
		native_ptr_dealloc_code = ''
		specific_member_decref_code = ''
689
		if self.class_['class_refcountable']:
690
			native_ptr_dealloc_code += \
691 692 693 694 695
"""	if (native_ptr != NULL) {{
		{function_prefix}unref(native_ptr);
	}}
""".format(function_prefix=self.class_['class_c_function_prefix'])
		elif self.class_['class_destroyable']:
696
			native_ptr_dealloc_code += \
697 698 699 700
"""	if (native_ptr != NULL) {{
		{function_prefix}destroy(native_ptr);
	}}
""".format(function_prefix=self.class_['class_c_function_prefix'])
701 702
		for member in self.class_['class_object_members']:
			specific_member_decref_code += "\tPy_XDECREF(((pylinphone_{class_name}Object *)self)->{member});\n".format(class_name=self.class_['class_name'], member=member)
703
		return \
704 705
"""	{reset_user_data_code}
	{native_ptr_dealloc_code}
706
	pylinphone_dispatch_messages();
707 708
	Py_XDECREF(((pylinphone_{class_name}Object *)self)->user_data);
{specific_member_decref_code}
709
	self->ob_type->tp_free(self);
710
""".format(class_name=self.class_['class_name'], reset_user_data_code=reset_user_data_code, native_ptr_dealloc_code=native_ptr_dealloc_code, specific_member_decref_code=specific_member_decref_code)
711 712 713 714 715 716 717

	def format_return_trace(self):
		return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);"

	def format_return_result(self):
		return ''

718 719 720 721 722 723
	def format(self):
		return \
"""static void pylinphone_{class_name}_dealloc(PyObject *self) {{
{method_body}
}}""".format(class_name=self.class_['class_name'], method_body=MethodDefinition.format(self))

724
class GetterMethodDefinition(MethodDefinition):
725 726
	def __init__(self, linphone_module, class_, method_name = "", method_node = None):
		MethodDefinition.__init__(self, linphone_module, class_, method_name, method_node)
727 728

class SetterMethodDefinition(MethodDefinition):
729 730
	def __init__(self, linphone_module, class_, method_name = "", method_node = None):
		MethodDefinition.__init__(self, linphone_module, class_, method_name, method_node)
731 732

	def format_arguments_parsing(self):
733
		if self.first_argument_type.check_condition is None:
734
			attribute_type_check_code = \
735 736
"""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.");
737 738 739 740
		return -1;
	}}
""".format(class_name=self.first_arg_class, attribute_name=self.attribute_name)
		else:
741
			checknotnone = ''
742
			if self.first_argument_type.type_str == 'string':
743
				checknotnone = "(value != Py_None) && "
744
			attribute_type_check_code = \
745
"""if ({checknotnone}{check_condition}) {{
746
		PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a {type_str}.");
747 748
		return -1;
	}}
749
""".format(checknotnone=checknotnone, check_condition=self.first_argument_type.check_condition.format(arg_name='value'), attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str)
750
		attribute_conversion_code = ''
751 752 753 754
		callback_setting_code = ''
		if is_callback(self.first_argument_type.complete_type):
			callback_setting_code = \
"""Py_XDECREF(((pylinphone_{class_name}Object *)self)->{callback_name});
755 756
	Py_INCREF(value);
	((pylinphone_{class_name}Object *)self)->{callback_name} = value;
757
""".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_arg_complete_type, self.class_['class_name']))
758 759
		if (self.first_argument_type.convert_code is None) or \
			(self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None):
760
			attribute_conversion_code += "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name)
761
		if self.first_argument_type.convert_code is not None:
762
			cast_code = ''
763
			suffix = ''
764 765
			if self.first_argument_type.cast_convert_func_result:
				cast_code = "({arg_type})".format(arg_type=self.first_arg_complete_type)
766
			if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None:
767
				suffix = '_native_obj'
768
			attribute_conversion_code += self.first_argument_type.convert_code.format(result_name="_" + self.first_arg_name, result_suffix=suffix, cast=cast_code, arg_name='value')
769
		attribute_native_ptr_check_code = ''
770
		if self.first_argument_type.use_native_pointer:
771
			attribute_native_ptr_check_code = \
772 773 774 775 776
"""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;
		}}
777
	}}
778
""".format(arg_name="_" + self.first_arg_name, arg_class=self.first_arg_class)
779 780 781
		return \
"""	{native_ptr_check_code}
	if (value == NULL) {{
782
		PyErr_SetString(PyExc_TypeError, "Cannot delete the '{attribute_name}' attribute.");
783 784 785 786
		return -1;
	}}
	{attribute_type_check_code}
	{attribute_conversion_code}
787
	{callback_setting_code}
788 789 790 791 792
	{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,
793
		callback_setting_code=callback_setting_code,
794 795 796
		attribute_native_ptr_check_code=attribute_native_ptr_check_code)

	def format_c_function_call(self):
797 798 799 800 801
		if is_callback(self.first_argument_type.complete_type):
			return \
"""	{method_name}(native_ptr, pylinphone_{class_name}_callback_{callback_name});
	pylinphone_dispatch_messages();
""".format(method_name=self.method_node.get('name'), class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_argument_type.complete_type, self.class_['class_name']))
802 803 804
		suffix = ''
		if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.use_native_pointer:
			suffix = '_native_ptr'
805
		elif self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None:
806
			suffix = '_native_obj'
807
		return \
808
"""	{method_name}(native_ptr, {arg_name}{suffix});
809
	pylinphone_dispatch_messages();
810
""".format(arg_name="_" + self.first_arg_name, method_name=self.method_node.get('name'), suffix=suffix)
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825

	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')
826
		self.first_arg_contained_type = self.xml_method_args[0].get('containedtype')
827
		self.first_arg_name = self.xml_method_args[0].get('name')
828
		self.first_argument_type = ArgumentType(self.first_arg_type, self.first_arg_complete_type, self.first_arg_contained_type, self.linphone_module)
829 830
		self.first_arg_class = strip_leading_linphone(self.first_arg_type)

831
class EventCallbackMethodDefinition(MethodDefinition):
832 833
	def __init__(self, linphone_module, class_, method_name = "", method_node = None):
		MethodDefinition.__init__(self, linphone_module, class_, method_name, method_node)