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	if (bundle == NULL) {
224		cfBundle = NULL;
225	} else {
226		PyObjC_DURING
227			cfBundle = NSBundle2CFBundle(bundle);
228
229		PyObjC_HANDLER
230			PyObjCErr_FromObjC(localException);
231			cfBundle = NULL;
232
233		PyObjC_ENDHANDLER
234
235		if  (cfBundle == NULL && PyErr_Occurred()) {
236			return NULL;
237		}
238
239		if (cfBundle == NULL) {
240			PyErr_Format(PyObjCExc_Error,
241				"Cannot convert NSBundle to CFBundle");
242			return NULL;
243		}
244	}
245
246	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
247	if (seq == NULL) {
248		return NULL;
249	}
250
251	len = PySequence_Fast_GET_SIZE(seq);
252	for (i = 0; i < len; i++) {
253		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
254		void*		value;
255		char*		signature;
256		NSString*	name;
257		char*           c_name;
258		PyObject*	doc;
259		PyObject*       meta = NULL;
260
261		if (!PyTuple_Check(item)) {
262			PyErr_Format(PyExc_TypeError,
263				"item %" PY_FORMAT_SIZE_T
264				"d has type %s not tuple",
265				i, Py_TYPE(item)->tp_name);
266			Py_DECREF(seq);
267			return NULL;
268		}
269
270		doc = NULL;
271		if (cfBundle != NULL) {
272			if (!PyArg_ParseTuple(item,
273#if PY_MAJOR_VERSION == 2
274				"O&s|SO;functionInfo",
275#else
276				"O&y|UO;functionInfo",
277#endif
278				PyObjCObject_Convert, &name, &signature, &doc, &meta)){
279				Py_DECREF(seq);
280				return NULL;
281			}
282			if (![name isKindOfClass:[NSString class]]) {
283				PyErr_SetString(PyExc_TypeError,
284					"functionInfo name not a string");
285				Py_DECREF(seq);
286				return NULL;
287			}
288
289			value = CFBundleGetFunctionPointerForName(cfBundle,
290					(CFStringRef)name);
291		} else {
292			if (!PyArg_ParseTuple(item,
293#if PY_MAJOR_VERSION == 2
294				"ss|SO;functionInfo",
295#else
296				"sy|UO;functionInfo",
297#endif
298				&c_name, &signature, &doc, &meta)){
299				Py_DECREF(seq);
300				return NULL;
301			}
302
303			value = dlsym(RTLD_DEFAULT, c_name);
304		}
305		if (value == NULL) {
306			if (!skip_undefined) {
307				PyErr_SetString(PyObjCExc_Error,
308					"cannot find a function");
309				Py_DECREF(seq);
310				return NULL;
311			}
312		} else {
313			PyObject* py_name;
314			if (cfBundle == NULL) {
315				py_name = PyText_FromString(c_name);
316			} else {
317				py_name = PyObjC_IdToPython(name);
318			}
319			PyObject* pyVal = PyObjCFunc_New(
320					py_name,
321					value,
322					signature,
323					doc,
324					meta);
325			if (pyVal == NULL) {
326				Py_DECREF(seq);
327				Py_DECREF(py_name);
328				return NULL;
329			}
330
331			if (PyDict_SetItem(module_globals,
332					py_name, pyVal) == -1) {
333				Py_DECREF(seq);
334				Py_DECREF(py_name);
335				Py_DECREF(pyVal);
336				return NULL;
337			}
338			Py_DECREF(py_name);
339			Py_DECREF(pyVal);
340		}
341	}
342	Py_DECREF(seq);
343	Py_INCREF(Py_None);
344	return Py_None;
345}
346
347typedef void(*function)(void);
348struct functionlist {
349	char*	 name;
350	function func;
351};
352
353static function find_function(struct functionlist* functions, PyObject* name)
354{
355	while (functions->name != NULL) {
356		if (PyObjC_is_ascii_string(name, functions->name)) {
357			return functions->func;
358		}
359		functions++;
360	}
361	return NULL;
362}
363
364PyObject* PyObjC_loadFunctionList(PyObject* self __attribute__((__unused__)),
365		PyObject* args, PyObject* kwds)
366{
367static char* keywords[] = { "function_list", "module_globals", "functionInfo", "skip_undefined", NULL };
368	PyObject* 	pyFunctionsList;
369	PyObject*	module_globals;
370	PyObject*	functionInfo;
371	int		skip_undefined = 1;
372	PyObject*       seq;
373	Py_ssize_t	i, len;
374	struct functionlist* function_list;
375
376
377	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|i",
378			keywords, &pyFunctionsList,
379			&module_globals, &functionInfo, &skip_undefined)) {
380		return NULL;
381	}
382
383	if (!PyCapsule_CheckExact(pyFunctionsList)) {
384		PyErr_SetString(PyExc_TypeError, "function_list not a PyCapsule");
385		return NULL;
386	}
387	function_list = PyCapsule_GetPointer(pyFunctionsList, "objc.__inline__");
388	if (function_list == NULL) {
389		PyErr_SetString(PyExc_ValueError, "no function list");
390		return NULL;
391	}
392
393	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
394	if (seq == NULL) {
395		return NULL;
396	}
397
398	len = PySequence_Fast_GET_SIZE(seq);
399	for (i = 0; i < len; i++) {
400		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
401		void*		value;
402		char*		signature;
403		PyObject*	name;
404		PyObject*	doc;
405		PyObject*       meta = NULL;
406
407		if (!PyTuple_Check(item)) {
408			PyErr_Format(PyExc_TypeError,
409				"item %" PY_FORMAT_SIZE_T
410				"d has type %s not tuple",
411				i, Py_TYPE(item)->tp_name);
412			Py_DECREF(seq);
413			return NULL;
414		}
415
416		doc = NULL;
417		if (!PyArg_ParseTuple(item,
418#if PY_MAJOR_VERSION == 2
419					"O!s|O!O:functionInfo tuple", &PyBaseString_Type,
420
421#else
422					"Uy|O!O:functionInfo tuple",
423#endif
424				&name, &signature,
425#if PY_MAJOR_VERSION == 2
426				&PyBaseString_Type,
427#else
428				&PyUnicode_Type,
429#endif
430
431				&doc, &meta)){
432			Py_DECREF(seq);
433			return NULL;
434		}
435
436
437		value = find_function(function_list, name);
438		if (value == NULL) {
439			if (!skip_undefined) {
440				PyErr_Format(PyObjCExc_Error,
441					"cannot find function %s", name);
442				Py_DECREF(seq);
443				return NULL;
444			}
445		} else {
446			PyObject* pyVal = PyObjCFunc_New(
447					name,
448					value,
449					signature,
450					doc,
451					meta);
452			if (pyVal == NULL) {
453				Py_DECREF(seq);
454				return NULL;
455			}
456
457			if (PyDict_SetItem(module_globals,
458					name, pyVal) == -1) {
459				Py_DECREF(seq);
460				Py_DECREF(pyVal);
461				return NULL;
462			}
463			Py_DECREF(pyVal);
464		}
465	}
466	Py_DECREF(seq);
467	Py_INCREF(Py_None);
468	return Py_None;
469}
470