1/*
2 * Wrapper for simple global functions. Simple functions are those without
3 * arguments that require additional effort.
4 */
5#include "pyobjc.h"
6
7/* XXX: move this to a header file */
8static inline Py_ssize_t align(Py_ssize_t offset, Py_ssize_t alignment)
9{
10	Py_ssize_t rest = offset % alignment;
11	if (rest == 0) return offset;
12	return offset + (alignment - rest);
13}
14
15
16typedef struct {
17	PyObject_HEAD
18	ffi_cif*  cif;
19	PyObjCMethodSignature* methinfo;
20	void*     function;
21	PyObject* doc;
22	PyObject* name;
23	PyObject* module;
24} func_object;
25
26
27
28PyDoc_STRVAR(func_metadata_doc, "Return a dict that describes the metadata for this function.");
29static PyObject* func_metadata(PyObject* self)
30{
31	return PyObjCMethodSignature_AsDict(((func_object*)self)->methinfo);
32}
33
34static PyMethodDef func_methods[] = {
35	{
36		  "__metadata__",
37	    	  (PyCFunction)func_metadata,
38	          METH_NOARGS,
39		  func_metadata_doc
40	},
41	{ 0, 0, 0, 0 }
42};
43
44
45
46static PyMemberDef func_members[] = {
47	{
48		"__doc__",
49		T_OBJECT,
50		offsetof(func_object, doc),
51		READONLY,
52		NULL
53	},
54	{
55		"__name__",
56		T_OBJECT,
57		offsetof(func_object, name),
58		READONLY,
59		NULL
60	},
61	{
62		"__module__",
63		T_OBJECT,
64		offsetof(func_object, module),
65		0,
66		NULL
67	},
68	{
69		NULL,
70		0,
71		0,
72		0,
73		NULL
74	}
75};
76
77static PyObject* func_repr(PyObject* _self)
78{
79	func_object* self = (func_object*)_self;
80
81	if (self->name == NULL) {
82		return PyText_FromFormat("<objc.function object at %p>", self);
83#if PY_MAJOR_VERSION == 2
84	} else if (PyString_Check(self->name)) {
85		return PyString_FromFormat("<objc.function '%s' at %p>", PyString_AsString(self->name), self);
86#else
87	} else if (PyUnicode_Check(self->name)) {
88		return PyUnicode_FromFormat("<objc.function %R at %p>", self->name, self);
89#endif
90	} else {
91#if PY_MAJOR_VERSION == 2
92		PyObject* result;
93		PyObject* name_repr = PyObject_Repr(self->name);
94		if (name_repr == NULL) {
95			return NULL;
96		}
97		if (!PyString_Check(name_repr)) {
98			result = PyString_FromFormat("<objc.function object at %p>", self);
99		} else {
100			result = PyString_FromFormat("<objc.function '%s' at %p>",
101					PyString_AsString(name_repr), self);
102		}
103		Py_DECREF(name_repr);
104		return result;
105#else
106		return PyUnicode_FromFormat("<objc.function %R at %p>", self->name, self);
107#endif
108	}
109}
110
111
112
113static PyObject*
114func_call(PyObject* s, PyObject* args, PyObject* kwds)
115{
116	func_object* self = (func_object*)s;
117	Py_ssize_t byref_in_count;
118	Py_ssize_t byref_out_count;
119	Py_ssize_t plain_count;
120	Py_ssize_t argbuf_len;
121	int r;
122	int cif_arg_count;
123	BOOL variadicAllArgs = NO;
124
125	unsigned char* argbuf = NULL;
126	ffi_type* arglist[64];
127	void*     values[64];
128	void**	  byref = NULL;
129	struct byref_attr* byref_attr = NULL;
130	ffi_cif cif;
131	ffi_cif* volatile cifptr;
132
133	PyObject* retval;
134
135	if (self->methinfo->suggestion != NULL) {
136		PyErr_SetObject(PyExc_TypeError, self->methinfo->suggestion);
137		return NULL;
138	}
139
140
141	if (Py_SIZE(self->methinfo) >= 63) {
142		PyErr_Format(PyObjCExc_Error,
143			"wrapping a function with %"PY_FORMAT_SIZE_T"d arguments, at most 64 "
144			"are supported", Py_SIZE(self->methinfo));
145		return NULL;
146	}
147
148	if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {
149		PyErr_SetString(PyExc_TypeError,
150			"keyword arguments not supported");
151		return NULL;
152	}
153
154	argbuf_len = PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type);
155	argbuf_len = align(argbuf_len, sizeof(void*));
156	r = PyObjCFFI_CountArguments(
157		self->methinfo, 0,
158		&byref_in_count, &byref_out_count, &plain_count,
159		&argbuf_len, &variadicAllArgs);
160	if (r == -1) {
161		return NULL;
162	}
163
164	variadicAllArgs |= self->methinfo->variadic && (self->methinfo->null_terminated_array || self->methinfo->arrayArg != -1);
165
166	if (variadicAllArgs) {
167		if (byref_in_count != 0 || byref_out_count != 0) {
168			PyErr_Format(PyExc_TypeError, "Sorry, printf format with by-ref args not supported");
169			return NULL;
170		}
171		if (PyTuple_Size(args) < Py_SIZE(self->methinfo)) {
172			PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d",
173			Py_SIZE(self->methinfo) - 2, PyTuple_Size(args));
174			return NULL;
175		}
176	} else if (PyTuple_Size(args) != Py_SIZE(self->methinfo)) {
177		PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d",
178			Py_SIZE(self->methinfo), PyTuple_Size(args));
179		return NULL;
180	}
181
182
183	argbuf = PyMem_Malloc(argbuf_len);
184	if (argbuf == NULL) {
185		PyErr_NoMemory();
186		return NULL;
187	}
188
189	if (variadicAllArgs) {
190		if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), &byref, &byref_attr) < 0) {
191			goto error;
192		}
193	} else {
194		if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo), &byref, &byref_attr) < 0) {
195			goto error;
196		}
197	}
198
199	cif_arg_count = PyObjCFFI_ParseArguments(
200		self->methinfo, 0, args,
201		align(PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type), sizeof(void*)),
202		argbuf, argbuf_len, byref, byref_attr, arglist, values);
203	if (cif_arg_count == -1) {
204		goto error;
205	}
206
207	if (variadicAllArgs) {
208		r = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, cif_arg_count,
209			signature_to_ffi_return_type(self->methinfo->rettype.type), arglist);
210		if (r != FFI_OK) {
211			PyErr_Format(PyExc_RuntimeError,
212				"Cannot setup FFI CIF [%d]", r);
213				goto error;
214		}
215		cifptr = &cif;
216
217	} else {
218		cifptr = self->cif;
219	}
220
221	PyObjC_DURING
222		ffi_call(cifptr, FFI_FN(self->function), argbuf, values);
223	PyObjC_HANDLER
224		PyObjCErr_FromObjC(localException);
225	PyObjC_ENDHANDLER
226
227	if (PyErr_Occurred()) {
228		goto error;
229	}
230
231	retval = PyObjCFFI_BuildResult(self->methinfo, 0, argbuf, byref,
232			byref_attr, byref_out_count, NULL, 0, values);
233
234	if (variadicAllArgs) {
235		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), byref, byref_attr) < 0) {
236			byref = NULL; byref_attr = NULL;
237			goto error;
238		}
239	} else {
240		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) {
241			byref = NULL; byref_attr = NULL;
242			goto error;
243		}
244	}
245	PyMem_Free(argbuf); argbuf = NULL;
246	return retval;
247
248error:
249	if (variadicAllArgs) {
250		if (PyObjCFFI_FreeByRef(PyTuple_Size(args), byref, byref_attr) < 0) {
251			byref = NULL; byref_attr = NULL;
252			goto error;
253		}
254	} else {
255		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) {
256			byref = NULL; byref_attr = NULL;
257			goto error;
258		}
259	}
260	if (argbuf) {
261		PyMem_Free(argbuf);
262	}
263	return NULL;
264}
265
266static void
267func_dealloc(PyObject* s)
268{
269	func_object* self = (func_object*)s;
270
271	Py_XDECREF(self->doc); self->doc = NULL;
272	Py_XDECREF(self->name); self->name = NULL;
273	Py_XDECREF(self->module); self->module = NULL;
274	if (self->cif != NULL) {
275		PyObjCFFI_FreeCIF(self->cif);
276	}
277	Py_XDECREF(self->methinfo);
278	PyObject_Free(s);
279}
280
281PyTypeObject PyObjCFunc_Type =
282{
283	PyVarObject_HEAD_INIT(&PyType_Type, 0)
284	"objc.function",			/* tp_name */
285	sizeof (func_object),			/* tp_basicsize */
286	0,					/* tp_itemsize */
287
288	/* methods */
289	func_dealloc,				/* tp_dealloc */
290	0,					/* tp_print */
291	0,					/* tp_getattr */
292	0,					/* tp_setattr */
293	0,					/* tp_compare */
294	func_repr,				/* tp_repr */
295	0,					/* tp_as_number */
296	0,					/* tp_as_sequence */
297	0,					/* tp_as_mapping */
298	0,					/* tp_hash */
299	func_call,				/* tp_call */
300	0,					/* tp_str */
301	PyObject_GenericGetAttr,		/* tp_getattro */
302	0,					/* tp_setattro */
303	0,					/* tp_as_buffer */
304	Py_TPFLAGS_DEFAULT,			/* tp_flags */
305	"Wrapper around a Objective-C function",/* tp_doc */
306	0,					/* tp_traverse */
307	0,					/* tp_clear */
308	0,					/* tp_richcompare */
309	0,					/* tp_weaklistoffset */
310	0,					/* tp_iter */
311	0,					/* tp_iternext */
312	func_methods,				/* tp_methods */
313	func_members,				/* tp_members */
314	0,					/* tp_getset */
315	0,					/* tp_base */
316	0,					/* tp_dict */
317	0,					/* tp_descr_get */
318	0,					/* tp_descr_set */
319	0,					/* tp_dictoffset */
320	0,					/* tp_init */
321	0,					/* tp_alloc */
322	0,					/* tp_new */
323	0,					/* tp_free */
324	0,					/* tp_is_gc */
325	0,					/* tp_bases */
326	0,					/* tp_mro */
327	0,					/* tp_cache */
328	0,					/* tp_subclasses */
329	0,					/* tp_weaklist */
330	0					/* tp_del */
331#if PY_VERSION_HEX >= 0x02060000
332	, 0                                     /* tp_version_tag */
333#endif
334
335};
336
337PyObject*
338PyObjCFunc_WithMethodSignature(PyObject* name, void* func, PyObjCMethodSignature* methinfo)
339{
340	func_object* result;
341
342	result = PyObject_NEW(func_object, &PyObjCFunc_Type);
343	if (result == NULL) return NULL;
344
345	result->function = func;
346	result->doc = NULL;
347	result->name = name;
348	Py_XINCREF(name);
349	result->module = NULL;
350	result->methinfo = methinfo;
351	Py_XINCREF(methinfo);
352
353	result->cif = PyObjCFFI_CIFForSignature(result->methinfo);
354	if (result->cif == NULL) {
355		Py_DECREF(result);
356		return NULL;
357	}
358
359	return (PyObject*)result;
360}
361
362
363PyObject*
364PyObjCFunc_New(PyObject* name, void* func, const char* signature, PyObject* doc, PyObject* meta)
365{
366	func_object* result;
367
368
369	result = PyObject_NEW(func_object, &PyObjCFunc_Type);
370	if (result == NULL) return NULL;
371
372	result->function = NULL;
373	result->doc = NULL;
374	result->name = NULL;
375	result->module = NULL;
376
377	result->methinfo= PyObjCMethodSignature_WithMetaData(signature, meta, NO);
378	if (result->methinfo == NULL) {
379		Py_DECREF(result->methinfo);
380		return NULL;
381	}
382
383	result->function = func;
384
385	result->doc = doc;
386	Py_XINCREF(doc);
387
388	result->name = name;
389	Py_XINCREF(name);
390	result->cif = PyObjCFFI_CIFForSignature(result->methinfo);
391	if (result->cif == NULL) {
392		Py_DECREF(result);
393		return NULL;
394	}
395
396	return (PyObject*)result;
397}
398
399PyObjCMethodSignature* PyObjCFunc_GetMethodSignature(PyObject* func)
400{
401	return ((func_object*)func)->methinfo;
402}
403