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
112static PyObject*
113func_call(PyObject* s, PyObject* args, PyObject* kwds)
114{
115	func_object* self = (func_object*)s;
116	Py_ssize_t byref_in_count;
117	Py_ssize_t byref_out_count;
118	Py_ssize_t plain_count;
119	Py_ssize_t argbuf_len;
120	int r;
121	int cif_arg_count;
122	BOOL variadicAllArgs = NO;
123
124	unsigned char* argbuf = NULL;
125	ffi_type* arglist[64];
126	void*     values[64];
127	void**	  byref = NULL;
128	struct byref_attr* byref_attr = NULL;
129	ffi_cif cif;
130	ffi_cif* volatile cifptr;
131
132	PyObject* retval;
133
134	if (self->methinfo->suggestion != NULL) {
135		PyErr_SetObject(PyExc_TypeError, self->methinfo->suggestion);
136		return NULL;
137	}
138
139
140	if (Py_SIZE(self->methinfo) >= 63) {
141		PyErr_Format(PyObjCExc_Error,
142			"wrapping a function with %"PY_FORMAT_SIZE_T"d arguments, at most 64 "
143			"are supported", Py_SIZE(self->methinfo));
144		return NULL;
145	}
146
147	if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {
148		PyErr_SetString(PyExc_TypeError,
149			"keyword arguments not supported");
150		return NULL;
151	}
152
153	argbuf_len = PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type);
154	argbuf_len = align(argbuf_len, sizeof(void*));
155	r = PyObjCFFI_CountArguments(
156		self->methinfo, 0,
157		&byref_in_count, &byref_out_count, &plain_count,
158		&argbuf_len, &variadicAllArgs);
159	if (r == -1) {
160		return NULL;
161	}
162
163	variadicAllArgs |= self->methinfo->variadic && (self->methinfo->null_terminated_array || self->methinfo->arrayArg != -1);
164
165	if (variadicAllArgs) {
166		if (byref_in_count != 0 || byref_out_count != 0) {
167			PyErr_Format(PyExc_TypeError, "Sorry, printf format with by-ref args not supported");
168			return NULL;
169		}
170		if (PyTuple_Size(args) < Py_SIZE(self->methinfo)) {
171			PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d",
172			Py_SIZE(self->methinfo) - 2, PyTuple_Size(args));
173			return NULL;
174		}
175	} else if (PyTuple_Size(args) != Py_SIZE(self->methinfo)) {
176		PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d",
177			Py_SIZE(self->methinfo), PyTuple_Size(args));
178		return NULL;
179	}
180
181
182	argbuf = PyMem_Malloc(argbuf_len);
183	if (argbuf == NULL) {
184		PyErr_NoMemory();
185		return NULL;
186	}
187
188	if (variadicAllArgs) {
189		if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), &byref, &byref_attr) < 0) {
190			goto error;
191		}
192	} else {
193		if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo), &byref, &byref_attr) < 0) {
194			goto error;
195		}
196	}
197
198	cif_arg_count = PyObjCFFI_ParseArguments(
199		self->methinfo, 0, args,
200		align(PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type), sizeof(void*)),
201		argbuf, argbuf_len, byref, byref_attr, arglist, values);
202	if (cif_arg_count == -1) {
203		goto error;
204	}
205
206	if (variadicAllArgs) {
207		r = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, cif_arg_count,
208			signature_to_ffi_return_type(self->methinfo->rettype.type), arglist);
209		if (r != FFI_OK) {
210			PyErr_Format(PyExc_RuntimeError,
211				"Cannot setup FFI CIF [%d]", r);
212				goto error;
213		}
214		cifptr = &cif;
215
216	} else {
217		cifptr = self->cif;
218	}
219
220	PyObjC_DURING
221		ffi_call(cifptr, FFI_FN(self->function), argbuf, values);
222	PyObjC_HANDLER
223		PyObjCErr_FromObjC(localException);
224	PyObjC_ENDHANDLER
225
226	if (PyErr_Occurred()) {
227		goto error;
228	}
229
230	retval = PyObjCFFI_BuildResult(self->methinfo, 0, argbuf, byref,
231			byref_attr, byref_out_count, NULL, 0, values);
232
233	if (variadicAllArgs) {
234		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), byref, byref_attr) < 0) {
235			byref = NULL; byref_attr = NULL;
236			goto error;
237		}
238	} else {
239		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) {
240			byref = NULL; byref_attr = NULL;
241			goto error;
242		}
243	}
244	PyMem_Free(argbuf); argbuf = NULL;
245	return retval;
246
247error:
248	if (variadicAllArgs) {
249		if (PyObjCFFI_FreeByRef(PyTuple_Size(args), byref, byref_attr) < 0) {
250			byref = NULL; byref_attr = NULL;
251			goto error;
252		}
253	} else {
254		if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) {
255			byref = NULL; byref_attr = NULL;
256			goto error;
257		}
258	}
259	if (argbuf) {
260		PyMem_Free(argbuf);
261	}
262	return NULL;
263}
264
265static void
266func_dealloc(PyObject* s)
267{
268	func_object* self = (func_object*)s;
269
270	Py_XDECREF(self->doc); self->doc = NULL;
271	Py_XDECREF(self->name); self->name = NULL;
272	Py_XDECREF(self->module); self->module = NULL;
273	if (self->cif != NULL) {
274		PyObjCFFI_FreeCIF(self->cif);
275	}
276	Py_XDECREF(self->methinfo);
277	PyObject_Free(s);
278}
279
280PyTypeObject PyObjCFunc_Type =
281{
282	PyVarObject_HEAD_INIT(&PyType_Type, 0)
283	"objc.function",			/* tp_name */
284	sizeof (func_object),			/* tp_basicsize */
285	0,					/* tp_itemsize */
286
287	/* methods */
288	func_dealloc,				/* tp_dealloc */
289	0,					/* tp_print */
290	0,					/* tp_getattr */
291	0,					/* tp_setattr */
292	0,					/* tp_compare */
293	func_repr,				/* tp_repr */
294	0,					/* tp_as_number */
295	0,					/* tp_as_sequence */
296	0,					/* tp_as_mapping */
297	0,					/* tp_hash */
298	func_call,				/* tp_call */
299	0,					/* tp_str */
300	PyObject_GenericGetAttr,		/* tp_getattro */
301	0,					/* tp_setattro */
302	0,					/* tp_as_buffer */
303	Py_TPFLAGS_DEFAULT,			/* tp_flags */
304	"Wrapper around a Objective-C function",/* tp_doc */
305	0,					/* tp_traverse */
306	0,					/* tp_clear */
307	0,					/* tp_richcompare */
308	0,					/* tp_weaklistoffset */
309	0,					/* tp_iter */
310	0,					/* tp_iternext */
311	func_methods,				/* tp_methods */
312	func_members,				/* tp_members */
313	0,					/* tp_getset */
314	0,					/* tp_base */
315	0,					/* tp_dict */
316	0,					/* tp_descr_get */
317	0,					/* tp_descr_set */
318	0,					/* tp_dictoffset */
319	0,					/* tp_init */
320	0,					/* tp_alloc */
321	0,					/* tp_new */
322	0,					/* tp_free */
323	0,					/* tp_is_gc */
324	0,					/* tp_bases */
325	0,					/* tp_mro */
326	0,					/* tp_cache */
327	0,					/* tp_subclasses */
328	0,					/* tp_weaklist */
329	0					/* tp_del */
330#if PY_VERSION_HEX >= 0x02060000
331	, 0                                     /* tp_version_tag */
332#endif
333
334};
335
336PyObject*
337PyObjCFunc_WithMethodSignature(PyObject* name, void* func, PyObjCMethodSignature* methinfo)
338{
339	func_object* result;
340
341	result = PyObject_NEW(func_object, &PyObjCFunc_Type);
342	if (result == NULL) return NULL;
343
344	result->function = func;
345	result->doc = NULL;
346	result->name = name;
347	Py_XINCREF(name);
348	result->module = NULL;
349	result->methinfo = methinfo;
350	Py_XINCREF(methinfo);
351
352	result->cif = PyObjCFFI_CIFForSignature(result->methinfo);
353	if (result->cif == NULL) {
354		Py_DECREF(result);
355		return NULL;
356	}
357
358	return (PyObject*)result;
359}
360
361
362PyObject*
363PyObjCFunc_New(PyObject* name, void* func, const char* signature, PyObject* doc, PyObject* meta)
364{
365	func_object* result;
366
367
368	result = PyObject_NEW(func_object, &PyObjCFunc_Type);
369	if (result == NULL) return NULL;
370
371	result->function = NULL;
372	result->doc = NULL;
373	result->name = NULL;
374	result->module = NULL;
375	result->cif = NULL;
376
377	result->methinfo= PyObjCMethodSignature_WithMetaData(signature, meta, NO);
378	if (result->methinfo == NULL) {
379		Py_DECREF(result);
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