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		NSString*	name;
145
146		if (!PyTuple_Check(item)) {
147			PyErr_Format(PyExc_TypeError,
148				"item %" PY_FORMAT_SIZE_T
149				"d has type %s not tuple",
150				i, item->ob_type->tp_name);
151			Py_DECREF(seq);
152			return NULL;
153		}
154
155		if (!PyArg_ParseTuple(item, "O&s:variableInfo",
156				PyObjCObject_Convert, &name, &signature)) {
157			Py_DECREF(seq);
158			return NULL;
159		}
160
161		if (![name isKindOfClass:[NSString class]]) {
162			PyErr_SetString(PyExc_TypeError,
163					"variable name not a string");
164			Py_DECREF(seq);
165			return NULL;
166		}
167
168		value = CFBundleGetDataPointerForName(cfBundle,
169				(CFStringRef)name);
170		if (value == NULL) {
171			if (!skip_undefined) {
172				PyErr_SetString(PyObjCExc_Error,
173					"cannot find a variable");
174				Py_DECREF(seq);
175				return NULL;
176			}
177
178		} else {
179			PyObject* pyVal = pythonify_c_value(signature, value);
180			if (pyVal == NULL) {
181				Py_DECREF(seq);
182				return NULL;
183			}
184
185			if (PyDict_SetItemString(module_globals,
186					[name UTF8String], pyVal) == -1) {
187				Py_DECREF(seq);
188				Py_DECREF(pyVal);
189				return NULL;
190			}
191			Py_DECREF(pyVal);
192		}
193	}
194	Py_DECREF(seq);
195	Py_INCREF(Py_None);
196	return Py_None;
197}
198
199PyObject* PyObjC_loadBundleFunctions(PyObject* self __attribute__((__unused__)),
200		PyObject* args, PyObject* kwds)
201{
202static char* keywords[] = { "bundle", "module_globals", "functionInfo", "skip_undefined", NULL };
203	NSBundle*	bundle;
204	PyObject*	module_globals;
205	PyObject*	functionInfo;
206	int		skip_undefined = 1;
207	CFBundleRef	cfBundle;
208	PyObject*       seq;
209	Py_ssize_t	i, len;
210
211	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&OO|i",
212			keywords, PyObjCObject_Convert, &bundle,
213			&module_globals, &functionInfo, &skip_undefined)) {
214		return NULL;
215	}
216
217
218	PyObjC_DURING
219		cfBundle = NSBundle2CFBundle(bundle);
220
221	PyObjC_HANDLER
222		PyObjCErr_FromObjC(localException);
223		cfBundle = NULL;
224
225	PyObjC_ENDHANDLER
226
227	if  (cfBundle == NULL && PyErr_Occurred()) {
228		return NULL;
229	}
230
231	if (cfBundle == NULL) {
232		PyErr_Format(PyObjCExc_Error,
233			"Cannot convert NSBundle to CFBundle");
234		return NULL;
235	}
236
237	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
238	if (seq == NULL) {
239		return NULL;
240	}
241
242	len = PySequence_Fast_GET_SIZE(seq);
243	for (i = 0; i < len; i++) {
244		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
245		void*		value;
246		char*		signature;
247		NSString*	name;
248		PyObject*	doc;
249		PyObject*       meta = NULL;
250
251		if (!PyTuple_Check(item)) {
252			PyErr_Format(PyExc_TypeError,
253				"item %" PY_FORMAT_SIZE_T
254				"d has type %s not tuple",
255				i, item->ob_type->tp_name);
256			Py_DECREF(seq);
257			return NULL;
258		}
259
260		doc = NULL;
261		if (!PyArg_ParseTuple(item, "O&s|SO;functionInfo",
262				PyObjCObject_Convert, &name, &signature, &doc, &meta)){
263			Py_DECREF(seq);
264			return NULL;
265		}
266
267		if (![name isKindOfClass:[NSString class]]) {
268			PyErr_SetString(PyExc_TypeError,
269					"functionInfo name not a string");
270			Py_DECREF(seq);
271			return NULL;
272		}
273
274		value = CFBundleGetFunctionPointerForName(cfBundle,
275				(CFStringRef)name);
276		if (value == NULL) {
277			if (!skip_undefined) {
278				PyErr_SetString(PyObjCExc_Error,
279					"cannot find a function");
280				Py_DECREF(seq);
281				return NULL;
282			}
283		} else {
284			PyObject* py_name = PyObjC_IdToPython(name);
285			PyObject* pyVal = PyObjCFunc_New(
286					py_name,
287					value,
288					signature,
289					doc,
290					meta);
291			if (pyVal == NULL) {
292				Py_DECREF(seq);
293				Py_DECREF(py_name);
294				return NULL;
295			}
296
297			if (PyDict_SetItem(module_globals,
298					py_name, pyVal) == -1) {
299				Py_DECREF(seq);
300				Py_DECREF(py_name);
301				Py_DECREF(pyVal);
302				return NULL;
303			}
304			Py_DECREF(py_name);
305			Py_DECREF(pyVal);
306		}
307	}
308	Py_DECREF(seq);
309	Py_INCREF(Py_None);
310	return Py_None;
311}
312
313typedef void(*function)(void);
314struct functionlist {
315	char*	 name;
316	function func;
317};
318
319static function find_function(struct functionlist* functions, char* name)
320{
321	while (functions->name != NULL) {
322		if (strcmp(functions->name, name) == 0) {
323			return functions->func;
324		}
325		functions++;
326	}
327	return NULL;
328}
329
330PyObject* PyObjC_loadFunctionList(PyObject* self __attribute__((__unused__)),
331		PyObject* args, PyObject* kwds)
332{
333static char* keywords[] = { "function_list", "module_globals", "functionInfo", "skip_undefined", NULL };
334	PyObject* 	pyFunctionsList;
335	PyObject*	module_globals;
336	PyObject*	functionInfo;
337	int		skip_undefined = 1;
338	PyObject*       seq;
339	Py_ssize_t	i, len;
340	struct functionlist* function_list;
341
342
343	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|i",
344			keywords, &pyFunctionsList,
345			&module_globals, &functionInfo, &skip_undefined)) {
346		return NULL;
347	}
348
349	if (!PyCObject_Check(pyFunctionsList)) {
350		PyErr_SetString(PyExc_TypeError, "function_list not a CObject");
351		return NULL;
352	}
353	function_list = PyCObject_AsVoidPtr(pyFunctionsList);
354	if (function_list == NULL) {
355		PyErr_SetString(PyExc_ValueError, "no function list\n");
356		return NULL;
357	}
358
359	seq = PySequence_Fast(functionInfo, "functionInfo not a sequence");
360	if (seq == NULL) {
361		return NULL;
362	}
363
364	len = PySequence_Fast_GET_SIZE(seq);
365	for (i = 0; i < len; i++) {
366		PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
367		void*		value;
368		char*		signature;
369		char*		name;
370		PyObject*	doc;
371		PyObject*       meta = NULL;
372
373		if (!PyTuple_Check(item)) {
374			PyErr_Format(PyExc_TypeError,
375				"item %" PY_FORMAT_SIZE_T
376				"d has type %s not tuple",
377				i, item->ob_type->tp_name);
378			Py_DECREF(seq);
379			return NULL;
380		}
381
382		doc = NULL;
383		if (!PyArg_ParseTuple(item, "ss|SO:functionInfo tuple",
384				&name, &signature, &doc, &meta)){
385			Py_DECREF(seq);
386			return NULL;
387		}
388
389		value = find_function(function_list, name);
390		if (value == NULL) {
391			if (!skip_undefined) {
392				PyErr_Format(PyObjCExc_Error,
393					"cannot find function %s", name);
394				Py_DECREF(seq);
395				return NULL;
396			}
397		} else {
398			PyObject* py_name = PyString_FromString(name);
399			PyObject* pyVal = PyObjCFunc_New(
400					py_name,
401					value,
402					signature,
403					doc,
404					meta);
405			if (pyVal == NULL) {
406				Py_DECREF(seq);
407				Py_DECREF(py_name);
408				return NULL;
409			}
410
411			if (PyDict_SetItem(module_globals,
412					py_name, pyVal) == -1) {
413				Py_DECREF(seq);
414				Py_DECREF(py_name);
415				Py_DECREF(pyVal);
416				return NULL;
417			}
418			Py_DECREF(py_name);
419			Py_DECREF(pyVal);
420		}
421	}
422	Py_DECREF(seq);
423	Py_INCREF(Py_None);
424	return Py_None;
425}
426