1/*
2 * This module exports a function to load variables in a bundle
3 *
4 * NOTE: The interface is specified with NSBundles, but we have to
5 * use CFBundles in the implementation. This is not portable to GNUstep :-(
6 */
7#include "pyobjc.h"
8
9#include <CoreFoundation/CoreFoundation.h>
10#import <Foundation/NSBundle.h>
11#import <Foundation/NSURL.h>
12
13#include <dlfcn.h>
14
15static CFBundleRef
16NSBundle2CFBundle(NSBundle* bundle)
17{
18	CFURLRef bundleURL;
19
20	bundleURL = (CFURLRef)[NSURL fileURLWithPath:[bundle bundlePath]];
21	return CFBundleCreate(
22			kCFAllocatorDefault,
23			bundleURL);
24}
25
26PyObject* PyObjC_loadSpecialVar(
27		PyObject* self __attribute__((__unused__)),
28		PyObject* args, PyObject* kwds)
29{
30static char* keywords[] = { "bundle", "module_globals", "typeid", "name", "skip_undefined", NULL };
31
32	NSBundle*	bundle;
33	NSString*       name;
34	PyObject*	module_globals;
35	Py_ssize_t	typeid;
36	Py_ssize_t	skip_undefined = 1;
37	CFBundleRef	cfBundle;
38	void*           value;
39
40	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&OiO&|i",
41			keywords, PyObjCObject_Convert, &bundle,
42			&module_globals, &typeid,
43			PyObjCObject_Convert, &name, &skip_undefined)) {
44		return NULL;
45	}
46
47
48	PyObjC_DURING
49		cfBundle = NSBundle2CFBundle(bundle);
50
51	PyObjC_HANDLER
52		PyObjCErr_FromObjC(localException);
53		cfBundle = NULL;
54
55	PyObjC_ENDHANDLER
56
57	if (cfBundle == NULL) {
58		if (PyErr_Occurred()) {
59			return NULL;
60		}
61		PyErr_Format(PyObjCExc_Error,
62			"Cannot convert NSBundle to CFBundle");
63		return NULL;
64	}
65
66	if (![name isKindOfClass:[NSString class]]) {
67		PyErr_SetString(PyExc_TypeError,
68				"variable name not a string");
69		return NULL;
70	}
71
72	value = CFBundleGetDataPointerForName(cfBundle, (CFStringRef)name);
73	if (value == NULL) {
74		if (!skip_undefined) {
75			PyErr_SetString(PyObjCExc_Error,
76				"cannot find a variable");
77			return NULL;
78		}
79
80	} else {
81		PyObject* pyVal = PyObjCCF_NewSpecial2(typeid, value);
82		if (pyVal == NULL) {
83			return NULL;
84		}
85
86		if (PyDict_SetItemString(module_globals,
87				[name UTF8String], pyVal) == -1) {
88			Py_DECREF(pyVal);
89			return NULL;
90		}
91		Py_DECREF(pyVal);
92	}
93	Py_INCREF(Py_None);
94	return Py_None;
95}
96
97PyObject* PyObjC_loadBundleVariables(PyObject* self __attribute__((__unused__)),
98		PyObject* args, PyObject* kwds)
99{
100static char* keywords[] = { "bundle", "module_globals", "variableInfo", "skip_undefined", NULL };
101	NSBundle*	bundle;
102	PyObject*	module_globals;
103	PyObject*	variableInfo;
104	Py_ssize_t	skip_undefined = 1;
105	CFBundleRef	cfBundle;
106	PyObject*       seq;
107	Py_ssize_t	i, len;
108
109	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&OO|i",
110			keywords, PyObjCObject_Convert, &bundle,
111			&module_globals, &variableInfo, &skip_undefined)) {
112		return NULL;
113	}
114
115
116	PyObjC_DURING
117		cfBundle = NSBundle2CFBundle(bundle);
118
119	PyObjC_HANDLER
120		PyObjCErr_FromObjC(localException);
121		cfBundle = NULL;
122
123	PyObjC_ENDHANDLER
124
125	if (cfBundle == NULL) {
126		if (PyErr_Occurred()) {
127			return NULL;
128		}
129		PyErr_Format(PyObjCExc_Error,
130			"Cannot convert NSBundle to CFBundle");
131		return NULL;
132	}
133
134	seq = PySequence_Fast(variableInfo, "variableInfo not a sequence");
135	if (seq == NULL) {
136		return NULL;
137	}
138
139	len = PySequence_Fast_GET_SIZE(seq);
140	for (i = 0; i < len; i++) {
141		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
142		void*		value;
143		char*		signature;
144		PyObject* 	py_name;
145		NSString*	name;
146
147		if (!PyTuple_Check(item)) {
148			PyErr_Format(PyExc_TypeError,
149				"item %" PY_FORMAT_SIZE_T
150				"d has type %s not tuple",
151				i, Py_TYPE(item)->tp_name);
152			Py_DECREF(seq);
153			return NULL;
154		}
155
156		if (!PyArg_ParseTuple(item,
157				"O!"Py_ARG_BYTES":variableInfo",
158#if PY_MAJOR_VERSION == 2
159				&PyBaseString_Type,
160#else
161				&PyUnicode_Type,
162#endif
163				&py_name, &signature)) {
164			Py_DECREF(seq);
165			return NULL;
166		}
167
168		name = PyObjC_PythonToId(py_name);
169		if (name == NULL && PyErr_Occurred()) {
170			return NULL;
171		}
172
173		value = CFBundleGetDataPointerForName(cfBundle,
174				(CFStringRef)name);
175		if (value == NULL) {
176			if (!skip_undefined) {
177				PyErr_SetString(PyObjCExc_Error,
178					"cannot find a variable");
179				Py_DECREF(seq);
180				return NULL;
181			}
182
183		} else {
184			PyObject* pyVal = pythonify_c_value(signature, value);
185			if (pyVal == NULL) {
186				Py_DECREF(seq);
187				return NULL;
188			}
189
190			if (PyDict_SetItemString(module_globals,
191					[name UTF8String], pyVal) == -1) {
192				Py_DECREF(seq);
193				Py_DECREF(pyVal);
194				return NULL;
195			}
196			Py_DECREF(pyVal);
197		}
198	}
199	Py_DECREF(seq);
200	Py_INCREF(Py_None);
201	return Py_None;
202}
203
204PyObject* PyObjC_loadBundleFunctions(PyObject* self __attribute__((__unused__)),
205		PyObject* args, PyObject* kwds)
206{
207static char* keywords[] = { "bundle", "module_globals", "functionInfo", "skip_undefined", NULL };
208	NSBundle*	bundle;
209	PyObject*	module_globals;
210	PyObject*	functionInfo;
211	int		skip_undefined = 1;
212	CFBundleRef	cfBundle;
213	PyObject*       seq;
214	Py_ssize_t	i, len;
215
216	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&OO|i",
217			keywords, PyObjCObject_Convert, &bundle,
218			&module_globals, &functionInfo, &skip_undefined)) {
219		return NULL;
220	}
221
222
223	PyObjC_DURING
224		cfBundle = NSBundle2CFBundle(bundle);
225
226	PyObjC_HANDLER
227		PyObjCErr_FromObjC(localException);
228		cfBundle = NULL;
229
230	PyObjC_ENDHANDLER
231
232	if  (cfBundle == NULL && PyErr_Occurred()) {
233		return NULL;
234	}
235
236	if (cfBundle == NULL) {
237		PyErr_Format(PyObjCExc_Error,
238			"Cannot convert NSBundle to CFBundle");
239		return NULL;
240	}
241
242	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
243	if (seq == NULL) {
244		return NULL;
245	}
246
247	len = PySequence_Fast_GET_SIZE(seq);
248	for (i = 0; i < len; i++) {
249		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
250		void*		value;
251		char*		signature;
252		NSString*	name;
253		PyObject*	doc;
254		PyObject*       meta = NULL;
255
256		if (!PyTuple_Check(item)) {
257			PyErr_Format(PyExc_TypeError,
258				"item %" PY_FORMAT_SIZE_T
259				"d has type %s not tuple",
260				i, Py_TYPE(item)->tp_name);
261			Py_DECREF(seq);
262			return NULL;
263		}
264
265		doc = NULL;
266		if (!PyArg_ParseTuple(item,
267#if PY_MAJOR_VERSION == 2
268				"O&s|SO;functionInfo",
269#else
270				"O&y|UO;functionInfo",
271#endif
272				PyObjCObject_Convert, &name, &signature, &doc, &meta)){
273			Py_DECREF(seq);
274			return NULL;
275		}
276
277		if (![name isKindOfClass:[NSString class]]) {
278			PyErr_SetString(PyExc_TypeError,
279					"functionInfo name not a string");
280			Py_DECREF(seq);
281			return NULL;
282		}
283
284		value = CFBundleGetFunctionPointerForName(cfBundle,
285				(CFStringRef)name);
286		if (value == NULL) {
287			if (!skip_undefined) {
288				PyErr_SetString(PyObjCExc_Error,
289					"cannot find a function");
290				Py_DECREF(seq);
291				return NULL;
292			}
293		} else {
294			PyObject* py_name = PyObjC_IdToPython(name);
295			PyObject* pyVal = PyObjCFunc_New(
296					py_name,
297					value,
298					signature,
299					doc,
300					meta);
301			if (pyVal == NULL) {
302				Py_DECREF(seq);
303				Py_DECREF(py_name);
304				return NULL;
305			}
306
307			if (PyDict_SetItem(module_globals,
308					py_name, pyVal) == -1) {
309				Py_DECREF(seq);
310				Py_DECREF(py_name);
311				Py_DECREF(pyVal);
312				return NULL;
313			}
314			Py_DECREF(py_name);
315			Py_DECREF(pyVal);
316		}
317	}
318	Py_DECREF(seq);
319	Py_INCREF(Py_None);
320	return Py_None;
321}
322
323typedef void(*function)(void);
324struct functionlist {
325	char*	 name;
326	function func;
327};
328
329static function find_function(struct functionlist* functions, PyObject* name)
330{
331	while (functions->name != NULL) {
332		if (PyObjC_is_ascii_string(name, functions->name)) {
333			return functions->func;
334		}
335		functions++;
336	}
337	return NULL;
338}
339
340PyObject* PyObjC_loadFunctionList(PyObject* self __attribute__((__unused__)),
341		PyObject* args, PyObject* kwds)
342{
343static char* keywords[] = { "function_list", "module_globals", "functionInfo", "skip_undefined", NULL };
344	PyObject* 	pyFunctionsList;
345	PyObject*	module_globals;
346	PyObject*	functionInfo;
347	int		skip_undefined = 1;
348	PyObject*       seq;
349	Py_ssize_t	i, len;
350	struct functionlist* function_list;
351
352
353	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|i",
354			keywords, &pyFunctionsList,
355			&module_globals, &functionInfo, &skip_undefined)) {
356		return NULL;
357	}
358
359	if (!PyCapsule_CheckExact(pyFunctionsList)) {
360		PyErr_SetString(PyExc_TypeError, "function_list not a PyCapsule");
361		return NULL;
362	}
363	function_list = PyCapsule_GetPointer(pyFunctionsList, "objc.__functionlist__");
364	if (function_list == NULL) {
365		PyErr_SetString(PyExc_ValueError, "no function list\n");
366		return NULL;
367	}
368
369	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
370	if (seq == NULL) {
371		return NULL;
372	}
373
374	len = PySequence_Fast_GET_SIZE(seq);
375	for (i = 0; i < len; i++) {
376		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
377		void*		value;
378		char*		signature;
379		PyObject*	name;
380		PyObject*	doc;
381		PyObject*       meta = NULL;
382
383		if (!PyTuple_Check(item)) {
384			PyErr_Format(PyExc_TypeError,
385				"item %" PY_FORMAT_SIZE_T
386				"d has type %s not tuple",
387				i, Py_TYPE(item)->tp_name);
388			Py_DECREF(seq);
389			return NULL;
390		}
391
392		doc = NULL;
393		if (!PyArg_ParseTuple(item,
394#if PY_MAJOR_VERSION == 2
395					"O!s|SO:functionInfo tuple", &PyBaseString_Type,
396
397#else
398					"Uy|UO:functionInfo tuple",
399#endif
400				&name, &signature, &doc, &meta)){
401			Py_DECREF(seq);
402			return NULL;
403		}
404
405		value = find_function(function_list, name);
406		if (value == NULL) {
407			if (!skip_undefined) {
408				PyErr_Format(PyObjCExc_Error,
409					"cannot find function %s", name);
410				Py_DECREF(seq);
411				return NULL;
412			}
413		} else {
414			PyObject* pyVal = PyObjCFunc_New(
415					name,
416					value,
417					signature,
418					doc,
419					meta);
420			if (pyVal == NULL) {
421				Py_DECREF(seq);
422				return NULL;
423			}
424
425			if (PyDict_SetItem(module_globals,
426					name, pyVal) == -1) {
427				Py_DECREF(seq);
428				Py_DECREF(pyVal);
429				return NULL;
430			}
431			Py_DECREF(pyVal);
432		}
433	}
434	Py_DECREF(seq);
435	Py_INCREF(Py_None);
436	return Py_None;
437}
438