1/*
2 * Some utility functions...
3 *
4 * TODO: Documentation
5 */
6
7#include "pyobjc.h"
8
9#import <Foundation/Foundation.h>
10
11PyObject* PyObjCExc_Error;
12PyObject* PyObjCExc_NoSuchClassError;
13PyObject* PyObjCExc_InternalError;
14PyObject* PyObjCExc_UnInitDeallocWarning;
15PyObject* PyObjCExc_ObjCRevivalWarning;
16PyObject* PyObjCExc_LockError;
17PyObject* PyObjCExc_BadPrototypeError;
18
19
20
21int
22PyObjCUtil_Init(PyObject* module)
23{
24#define NEW_EXC(identifier, name, base_class) \
25	identifier = PyErr_NewException("objc."name, base_class, NULL); \
26	if (identifier == NULL) return -1; \
27	Py_INCREF(identifier); \
28	if (PyModule_AddObject(module, name, identifier) < 0) return -1;
29
30	NEW_EXC(PyObjCExc_Error, "error", NULL);
31	NEW_EXC(PyObjCExc_NoSuchClassError, "nosuchclass_error", PyObjCExc_Error);
32	NEW_EXC(PyObjCExc_InternalError, "internal_error", PyObjCExc_Error);
33	NEW_EXC(PyObjCExc_UnInitDeallocWarning, "UninitializedDeallocWarning", PyExc_Warning);
34	NEW_EXC(PyObjCExc_ObjCRevivalWarning, "RevivedObjectiveCObjectWarning", PyExc_Warning);
35	NEW_EXC(PyObjCExc_LockError, "LockError", PyObjCExc_Error);
36	NEW_EXC(PyObjCExc_BadPrototypeError, "BadPrototypeError", PyObjCExc_Error);
37
38	return 0;
39}
40
41static PyObject*
42ObjCErr_PyExcForName(const char* value)
43{
44	/* XXX: This table should be changeable from python */
45	if (strcmp(value, "NSRangeException") == 0) {
46		return PyExc_IndexError;
47	}  else if (strcmp(value, "NSInvalidArgumentException") == 0) {
48		return PyExc_ValueError;
49	}  else if (strcmp(value, "NSMallocException") == 0) {
50		return PyExc_MemoryError;
51	}  else if (strcmp(value, "NSUnknownKeyException") == 0) {
52		return PyExc_KeyError;
53	}
54
55	return PyObjCExc_Error;
56}
57
58
59void
60PyObjCErr_FromObjC(NSException* localException)
61{
62	NSDictionary* userInfo;
63	PyObject*     dict;
64	PyObject*     exception;
65	PyObject*     v;
66	PyObject*	  buf;
67	PyObject*     exc_type;
68	PyObject*     exc_value;
69	PyObject*     exc_traceback;
70	PyObject*     c_localException_name;
71	PyObject*     c_localException_reason;
72	NSObject* t;
73
74	PyGILState_STATE state;
75
76	state = PyGILState_Ensure();
77
78	if (![localException isKindOfClass:[NSException class]]) {
79		/* We caught some random objects as the exception, so the minimal possible
80		 */
81		PyErr_SetString(PyObjCExc_Error, "non-NSException object caught");
82
83		PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
84		if (!exc_value || !PyObject_IsInstance(exc_value, exc_type)) {
85			PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
86		}
87
88		PyObject* exc = PyObjC_IdToPython(localException);
89		if (exc == NULL) {
90			PyErr_Clear();
91		} else {
92			PyObject_SetAttrString(exc_value, "_pyobjc_exc_", exc);
93		}
94		Py_DECREF(exc); exc = NULL;
95		PyErr_Restore(exc_type, exc_value, exc_traceback);
96		PyGILState_Release(state);
97		return;
98	}
99
100	exception = ObjCErr_PyExcForName([[localException name] UTF8String]);
101
102	userInfo = [localException userInfo];
103	if (userInfo) {
104		id val;
105
106		val = [userInfo objectForKey:@"__pyobjc_exc_type__"];
107		if (val) {
108			exc_type = [val pyObject];
109			exc_value = [[userInfo objectForKey:@"__pyobjc_exc_value__"]  pyObject];
110			exc_traceback = [[userInfo objectForKey:@"__pyobjc_exc_traceback__"]  pyObject];
111
112			/* -pyObject returns a borrowed reference and
113			 * PyErr_Restore steals one from us.
114			 */
115			Py_INCREF(exc_type);
116			Py_XINCREF(exc_value);
117			Py_XINCREF(exc_traceback);
118
119			PyErr_Restore(exc_type, exc_value, exc_traceback);
120			PyGILState_Release(state);
121			return;
122		}
123	}
124
125	t = [localException name];
126	c_localException_name = pythonify_c_value(@encode(NSObject*), &t);
127	if (c_localException_name == NULL) {
128		return;
129	}
130
131	t = [localException reason];
132	c_localException_reason = pythonify_c_value(@encode(NSObject*), &t);
133	if (c_localException_reason == NULL) {
134		Py_DECREF(c_localException_name);
135		return;
136	}
137
138	dict = PyDict_New();
139	if (dict == NULL) {
140		Py_DECREF(c_localException_name);
141		Py_DECREF(c_localException_reason);
142		return;
143	}
144	PyDict_SetItemString(dict, "name", c_localException_name);
145	Py_DECREF(c_localException_name);
146
147	PyDict_SetItemString(dict, "reason",  c_localException_reason);
148	Py_DECREF(c_localException_reason);
149	if (userInfo) {
150		v = PyObjCObject_New(userInfo, PyObjCObject_kDEFAULT, YES);
151		if (v != NULL) {
152			PyDict_SetItemString(dict, "userInfo", v);
153			Py_DECREF(v);
154		} else {
155			PyErr_Clear();
156		}
157	} else {
158		PyDict_SetItemString(dict, "userInfo", Py_None);
159	}
160
161#if 0
162	/* build the description as a NSString to maintain the highest
163	 * fidelity.
164	 * This code is disabled because the base exception class doesn't
165	 * like unicode arguments, that will wreak havoc when converting the
166	 * exception to text, which in turn makes it impossible to find out
167	 * what the exception actually was without poking in the PyObjC
168	 * specific fields.
169	 */
170	NSString* description = [NSString stringWithFormat:@"%@ - %@",
171			[localException name], [localException reason]];
172	if (description == nil) {
173		PyErr_SetString(exception, "<<<UNKNOWN REASON>>>");
174	} else {
175		buf = pythonify_c_value(@encode(NSObject*), &description);
176		if (buf == NULL) {
177			Py_DECREF(dict);
178			PyGILState_Release(state);
179			return;
180		}
181	}
182#else
183	 buf = PyString_FromFormat("%s - %s",
184               [[localException name] UTF8String],
185               [[localException reason] UTF8String]);
186	PyErr_SetObject(exception, buf);
187#endif
188	PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
189	if (!exc_value || !PyObject_IsInstance(exc_value, exc_type)) {
190		PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
191	}
192
193	PyObject_SetAttrString(exc_value, "_pyobjc_info_", dict);
194	Py_DECREF(dict); dict = NULL;
195	PyObject_SetAttrString(exc_value, "name", c_localException_name);
196	PyErr_Restore(exc_type, exc_value, exc_traceback);
197	PyGILState_Release(state);
198}
199
200void
201PyObjCErr_ToObjC(void)
202{
203	PyObjCErr_ToObjCWithGILState(NULL);
204}
205
206
207NSException*
208PyObjCErr_AsExc(void)
209{
210	PyObject* exc_type;
211	PyObject* exc_value;
212	PyObject* exc_traceback;
213	PyObject* args;
214	PyObject* repr;
215	PyObject* typerepr;
216	NSException* val;
217	NSMutableDictionary* userInfo;
218
219	PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
220	if (exc_type == NULL) {
221		return nil;
222	}
223
224	PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
225
226	args = PyObject_GetAttrString(exc_value, "_pyobjc_exc_");
227	if (args == NULL) {
228		PyErr_Clear();
229	} else {
230		return PyObjC_PythonToId(args);
231	}
232
233	args = PyObject_GetAttrString(exc_value, "_pyobjc_info_");
234	if (args == NULL) {
235		PyErr_Clear();
236	} else {
237		/* This may be an exception that started out in
238		 * Objective-C code.
239		 */
240		PyObject* v;
241		NSString* reason = NULL;
242		NSString* name = NULL;
243
244		v = PyDict_GetItemString(args, "reason");
245		if (v) {
246			if (depythonify_c_value(@encode(NSObject*), v, &reason) < 0) {
247				PyErr_Clear();
248			}
249		}
250
251		v = PyDict_GetItemString(args, "name");
252		if (v) {
253			if (depythonify_c_value(@encode(NSObject*), v, &name) < 0) {
254				PyErr_Clear();
255			}
256		}
257
258		v = PyDict_GetItemString(args, "userInfo");
259		if (v && PyObjCObject_Check(v)) {
260			userInfo = PyObjCObject_GetObject(v);
261		} else {
262			userInfo = nil;
263			PyErr_Clear();
264		}
265
266		if (name && reason) {
267			val = [NSException exceptionWithName:name
268				     reason:reason
269				     userInfo:userInfo];
270			Py_DECREF(args);
271			Py_XDECREF(exc_type);
272			Py_XDECREF(exc_value);
273			Py_XDECREF(exc_traceback);
274
275			return val;
276		}
277	}
278
279	repr = PyObject_Str(exc_value);
280	typerepr = PyObject_Str(exc_type);
281	userInfo = [NSMutableDictionary dictionaryWithCapacity: 3];
282	[userInfo setObject:
283		[OC_PythonObject newWithObject:exc_type]
284		forKey:@"__pyobjc_exc_type__"];
285	if (exc_value != NULL)
286		[userInfo setObject:
287			[OC_PythonObject newWithObject:exc_value]
288			forKey:@"__pyobjc_exc_value__"];
289	if (exc_traceback != NULL)
290		[userInfo setObject:
291			[OC_PythonObject newWithObject:exc_traceback]
292			forKey:@"__pyobjc_exc_traceback__"];
293
294	val = [NSException
295		exceptionWithName:@"OC_PythonException"
296		reason:[NSString stringWithFormat:@"%s: %s", PyString_AS_STRING(typerepr), PyString_AS_STRING(repr)]
297		userInfo:userInfo];
298
299	Py_DECREF(typerepr);
300	Py_DECREF(repr);
301
302	if (PyObjC_VerboseLevel) {
303		PyErr_Restore(exc_type, exc_value , exc_traceback);
304		NSLog(@"PyObjC: Converting exception to Objective-C:");
305		PyErr_Print();
306	} else {
307		Py_DECREF(exc_type);
308		Py_XDECREF(exc_value);
309		Py_XDECREF(exc_traceback);
310	}
311	return val;
312}
313
314void
315PyObjCErr_ToObjCWithGILState(PyGILState_STATE* state)
316{
317	NSException* exc = PyObjCErr_AsExc();
318
319	if (state) {
320		PyGILState_Release(*state);
321	}
322	[exc raise];
323}
324
325
326char*
327PyObjCUtil_Strdup(const char* value)
328{
329	Py_ssize_t len;
330	char* result;
331
332	len = strlen(value);
333	result = PyMem_Malloc(len+1);
334	if (result == NULL) return NULL;
335
336	memcpy(result, value, len);
337	result[len] = 0;
338	return result;
339}
340
341
342NSMapTableKeyCallBacks PyObjCUtil_PointerKeyCallBacks = {
343	NULL,
344	NULL,
345	NULL,
346	NULL,
347	NULL,
348	NULL,
349};
350
351NSMapTableValueCallBacks PyObjCUtil_PointerValueCallBacks = {
352	NULL,
353	NULL,
354	NULL,
355};
356
357static void
358nsmaptable_objc_retain(NSMapTable *table __attribute__((__unused__)), const void *datum) {
359	CFRetain((id)datum);
360}
361
362static void
363nsmaptable_objc_release(NSMapTable *table __attribute__((__unused__)), void *datum) {
364	CFRelease((id)datum);
365}
366
367NSMapTableKeyCallBacks PyObjCUtil_ObjCIdentityKeyCallBacks = {
368	NULL,
369	NULL,
370	&nsmaptable_objc_retain,
371	&nsmaptable_objc_release,
372	NULL,
373	NULL,
374};
375
376NSMapTableValueCallBacks PyObjCUtil_ObjCValueCallBacks = {
377	&nsmaptable_objc_retain,
378	&nsmaptable_objc_release,
379	NULL  // generic description
380};
381
382
383#define SHOULD_FREE 1
384#define SHOULD_IGNORE 2
385
386void
387PyObjC_FreeCArray(int code, void* array)
388{
389	if (code == SHOULD_FREE) {
390		PyMem_Free(array);
391	}
392}
393
394static PyTypeObject* array_type = NULL;
395
396static inline PyTypeObject*
397fetch_array_type(void)
398{
399	PyObject* mod;
400	PyObject* name;
401
402	if (array_type != NULL) return array_type;
403
404	name = PyString_FromString("array");
405	if (name == NULL) {
406		return NULL;
407	}
408
409	mod = PyImport_Import(name);
410	Py_DECREF(name);
411	if (mod == NULL) {
412		return NULL;
413	}
414
415	array_type = (PyTypeObject*)PyObject_GetAttrString(mod, "ArrayType");
416	Py_DECREF(mod);
417	if (array_type == NULL) {
418		return NULL;
419	}
420
421	/* XXX: check if array_type is realy a type! */
422
423	return array_type;
424}
425
426#define array_check(obj) PyObject_TypeCheck(obj, fetch_array_type())
427
428static char
429array_typestr(PyObject* array)
430{
431	PyObject* typecode;
432	char res;
433
434	typecode = PyObject_GetAttrString(array, "typecode");
435	if (typecode == NULL) {
436		return '\0';
437	}
438
439	if (!PyString_Check(typecode)) {
440		PyErr_SetString(PyExc_TypeError, "typecode not a string");
441		return '\0';
442	}
443
444	switch (*PyString_AS_STRING(typecode)) {
445	case 'c': res = _C_CHR; break;
446	case 'b': res = _C_CHR; break;
447	case 'B': res = _C_UCHR; break;
448	case 'u': res = _C_SHT; break;
449	case 'h': res = _C_SHT; break;
450	case 'H': res = _C_USHT; break;
451	case 'i': res = _C_INT; break;
452	case 'I': res = _C_UINT; break;
453	case 'l': res = _C_LNG; break;
454	case 'L': res = _C_ULNG; break;
455	case 'f': res = _C_FLT; break;
456	case 'd': res = _C_DBL; break;
457	default:
458		PyErr_SetString(PyExc_TypeError, "unsupported typecode");
459		res = '\0';
460	}
461	Py_DECREF(typecode);
462
463	return res;
464}
465
466static int
467buffer_get(BOOL writable, PyObject* obj, void** bufptr, Py_ssize_t* sizeptr)
468{
469	if (writable) {
470		return PyObject_AsWriteBuffer(obj, bufptr,  sizeptr);
471	} else {
472		return PyObject_AsReadBuffer(obj, (const void**)bufptr,  sizeptr);
473	}
474}
475
476static char struct_elem_code(const char* typestr);
477
478static char
479array_elem_code(const char* typestr)
480{
481	char res = '\0';
482	char tmp;
483
484	if (*typestr++ != _C_ARY_B) {
485		return '\0';
486	}
487	while (isdigit(*typestr)) typestr++;
488
489	if (*typestr == _C_ARY_E) {
490		return '\0';
491	}
492
493	while (typestr && *typestr != _C_ARY_E) {
494		switch(*typestr) {
495		case _C_ARY_B:
496			tmp = array_elem_code(typestr);
497			if (tmp == '\0') return '\0';
498			if (res == '\0') {
499				res = tmp;
500			} else if (tmp != res) {
501				return '\0';
502			}
503			break;
504		case _C_STRUCT_B:
505			tmp = struct_elem_code(typestr);
506			if (tmp == '\0') return '\0';
507			if (res == '\0') {
508				res = tmp;
509			} else if (tmp != res) {
510				return '\0';
511			}
512			break;
513		default:
514			if (res != '\0' && *typestr != res) return '\0';
515			res = *typestr;
516		}
517
518		typestr = PyObjCRT_SkipTypeSpec(typestr);
519	}
520	return res;
521}
522
523static char
524struct_elem_code(const char* typestr)
525{
526	char res = '\0';
527	char tmp;
528
529	if (*typestr++ != _C_STRUCT_B) {
530		return '\0';
531	}
532
533	while (*typestr != '=' && *typestr != _C_STRUCT_E) {
534		typestr++;
535	}
536
537	if (*typestr == _C_STRUCT_E) {
538		return '\0';
539	}
540	typestr++;
541
542	while (typestr && *typestr != _C_STRUCT_E) {
543		switch(*typestr) {
544		case _C_ARY_B:
545			tmp = array_elem_code(typestr);
546			if (tmp == '\0') return '\0';
547			if (res == '\0') {
548				res = tmp;
549			} else if (tmp != res) {
550				return '\0';
551			}
552			break;
553		case _C_STRUCT_B:
554			tmp = struct_elem_code(typestr);
555			if (tmp == '\0') return '\0';
556			if (res == '\0') {
557				res = tmp;
558			} else if (tmp != res) {
559				return '\0';
560			}
561			break;
562		default:
563			if (res != '\0' && *typestr != res) return '\0';
564			res = *typestr;
565		}
566
567		typestr = PyObjCRT_SkipTypeSpec(typestr);
568	}
569	return res;
570}
571
572static BOOL
573code_compatible(char array_code, char type_code)
574{
575	if (array_code == type_code) {
576		return YES;
577	}
578	switch (type_code) {
579	case _C_NSBOOL:
580		return (array_code == _C_CHR) || (array_code == _C_UCHR);
581	case _C_CHAR_AS_INT:
582		return (array_code == _C_CHR) || (array_code == _C_UCHR);
583	case _C_CHAR_AS_TEXT:
584		return (array_code == _C_CHR);
585	case _C_UNICHAR:
586		return (array_code == _C_SHT);
587	}
588	return NO;
589}
590
591
592/*
593 * Convert a Python object to an array of 'elementType'. The array should
594 * contain 'pythonCount' elements, Py_None or NULL is accepted and will result
595 * in converting the entire Python sequence.
596 *
597 * The pythonList should either be a python sequence with appropriate entries,
598 * an array.array whose element-types match the element-types of the
599 * 'elementType' or an appropriatly typed and shaped numeric array.
600 *
601 * XXX: Numeric arrays are not yet supported.
602 * XXX: Unicode arrays are not yet support (_C_UNICHAR)
603 */
604int
605PyObjC_PythonToCArray(
606	BOOL        writable, BOOL exactSize,
607	const char* elementType,
608	PyObject*   pythonList,
609	void** array,
610	Py_ssize_t*   size,
611	PyObject**    bufobj)
612{
613	Py_ssize_t eltsize = PyObjCRT_SizeOfType(elementType);
614	Py_ssize_t i;
615	int r;
616
617
618	if (eltsize == -1) {
619		return -1;
620	}
621
622	if ((eltsize == 1 || eltsize == 0) &&
623		!(*elementType == _C_NSBOOL || *elementType == _C_BOOL || *elementType == _C_CHAR_AS_INT)) {
624		/* A simple byte-array */
625		/* Note: PyUnicode is explicitly excluded because it
626		 * implemenents the character buffer interface giving access
627		 * to the raw implementation. That's almost always not want
628		 * you want.
629		 */
630		char* buf;
631		Py_ssize_t bufsize;
632		int have_buffer;
633
634		if (PyUnicode_Check(pythonList)) {
635			PyErr_Format(PyExc_TypeError,
636				"Expecting byte-buffer, got %s",
637				pythonList->ob_type->tp_name);
638			return -1;
639		}
640
641
642		have_buffer = buffer_get(writable, pythonList, (void**)&buf, &bufsize);
643		if (have_buffer == -1) {
644			if (writable) {
645				/* Ensure that the expected semantics still work
646				 * when the passed in buffer is read-only
647				 */
648				if (buffer_get(NO, pythonList, (void**)&buf, &bufsize) == -1) {
649					return -1;
650				}
651
652				if (size == NULL || *size == -1) {
653					*array = PyMem_Malloc(bufsize);
654					if (*array == NULL) {
655						return -1;
656					}
657					memcpy(*array, buf, bufsize);
658				} else {
659					if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
660						PyErr_Format(PyExc_ValueError,
661							"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
662							"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
663						return -1;
664					}
665					*array = PyMem_Malloc(*size);
666					if (*array == NULL) {
667						return -1;
668					}
669					memcpy(*array, buf, *size);
670				}
671				return SHOULD_FREE;
672			}
673		}
674
675		if (have_buffer != -1) {
676			if (size == NULL) {
677				*array = buf;
678				*bufobj = pythonList;
679				Py_INCREF(pythonList);
680
681			} else if (*size == -1) {
682				*array = buf;
683				*size = bufsize;
684				*bufobj = pythonList;
685				Py_INCREF(pythonList);
686
687			} else {
688				if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
689					PyErr_Format(PyExc_ValueError,
690						"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
691						"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
692					return -1;
693				}
694				*array = buf;
695				*bufobj = pythonList;
696				Py_INCREF(pythonList);
697			}
698			return SHOULD_IGNORE;
699		}
700
701		PyErr_Clear();
702	}
703
704	if (*elementType == _C_UNICHAR && PyUnicode_Check(pythonList)) {
705		Py_ssize_t bufsize = PyUnicode_GetSize(pythonList);
706
707		if (*size == -1) {
708			*size = bufsize;
709		} else if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
710			PyErr_Format(PyExc_ValueError,
711				"Requesting unicode buffer of %"PY_FORMAT_SIZE_T"d, have unicode buffer "
712				"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
713			return -1;
714		}
715
716		if (writable) {
717			*array = PyMem_Malloc(*size * sizeof(UniChar));
718			memcpy(*array, PyUnicode_AsUnicode(pythonList), *size * sizeof(UniChar));
719			return SHOULD_FREE;
720		} else {
721			*array = PyUnicode_AsUnicode(pythonList);
722			*bufobj = pythonList;
723			Py_INCREF(pythonList);
724			return SHOULD_IGNORE;
725		}
726
727	} else if (*elementType == _C_UNICHAR && PyString_Check(pythonList)) {
728		PyObject* u = PyUnicode_Decode(
729				PyString_AsString(pythonList),
730				PyString_Size(pythonList),
731				NULL, NULL);
732		if (u == NULL) {
733			return -1;
734		}
735
736		Py_ssize_t bufsize = PyUnicode_GetSize(u);
737
738		if (*size == -1) {
739			*size = bufsize;
740		} else if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
741			PyErr_Format(PyExc_ValueError,
742				"Requesting unicode buffer of %"PY_FORMAT_SIZE_T"d, have unicode buffer "
743				"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
744			Py_DECREF(u);
745			return -1;
746		}
747
748		if (writable) {
749			*array = PyMem_Malloc(*size * sizeof(UniChar));
750			memcpy(*array, PyUnicode_AsUnicode(u), *size * sizeof(UniChar));
751			Py_DECREF(u);
752			return SHOULD_FREE;
753		} else {
754			*array = PyUnicode_AsUnicode(u);
755			*bufobj = u;
756			return SHOULD_IGNORE;
757		}
758	}
759
760
761	/* A more complex array */
762
763#if PY_VERSION_HEX >= 0x02060000
764	if (PyObject_CheckBuffer(pythonList)) {
765		/* An object that implements the new-style buffer interface.
766		 * Use the buffer interface description to check if the buffer
767		 * type is compatible with what we expect.
768		 *
769		 * Specifically:
770		 * - If the C code expects an array of basic types:
771		 *   the buffer must be a single-dimensional array of
772		 *   a compatible type.
773		 * - If the C code expects and array of structures:
774		 *   The python array must be two dimensional, one row
775		 *   in the python array corresponds to one struct "instance"
776		 * - If the C code expects a multi-dimensional array:
777		 *   the python buffer must have a compatible dimension.
778		 *
779		 * The array must be large enough and  mustn't contain holes
780		 * in the fragment that gets used by us.
781		 */
782
783	}
784
785#endif
786
787	if (array_check(pythonList)) {
788		/* An array.array. Only convert if the typestr describes an
789		 * simple type of the same type as the array, or a struct/array
790		 * containing only elements of the type of the array.
791		 */
792		char* buf;
793		Py_ssize_t bufsize;
794		char code = array_typestr(pythonList);
795		if (code_compatible(code, *elementType)) {
796			/* Simple array, ok */
797		} else if (*elementType == _C_ARY_B) {
798			/* Array of arrays, 'code' must be the same as the
799			 * element-type of the array.
800			 */
801			if (!code_compatible(code, array_elem_code(elementType))) {
802				PyErr_Format(PyExc_ValueError,
803					"type mismatch between array.array "
804					"of %c and and C array of %s",
805					code, elementType);
806				return -1;
807			}
808
809		} else if (*elementType == _C_STRUCT_B) {
810			/* Array of structs, 'code' must be the same as the
811			 * the field-types of the structs (that is, the struct
812			 * must contain one or more fields of type 'code').
813			 */
814			if (!code_compatible(code, struct_elem_code(elementType))) {
815				PyErr_Format(PyExc_ValueError,
816					"type mismatch between array.array "
817					"of %c and and C array of %s",
818					code, elementType);
819				return -1;
820			}
821		} else {
822			PyErr_Format(PyExc_ValueError,
823				"type mismatch between array.array "
824				"of %c and and C array of %s",
825				code, elementType);
826			return -1;
827		}
828
829		if (buffer_get(writable, pythonList, (void**)&buf, &bufsize) == -1) {
830			return -1;
831		}
832		if ((bufsize % eltsize) != 0) {
833			PyErr_SetString(PyExc_ValueError,
834					"Badly shaped array.array");
835			return -1;
836		}
837
838		*array = buf;
839
840		if (size == NULL) {
841			/* pass */
842
843		} else if (*size == -1) {
844			*size = bufsize / eltsize;
845
846		} else {
847			bufsize /= eltsize;
848
849			if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
850				PyErr_Format(PyExc_ValueError,
851					"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
852					"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
853				return -1;
854			}
855			*array = buf;
856		}
857		*bufobj = pythonList;
858		Py_INCREF(pythonList);
859		return SHOULD_IGNORE;
860
861#ifdef PyObjC_ENABLE_NUMARRAY
862
863# error "Please implement Numarray/Numeric support"
864
865	} else if (...){
866		/* TODO: Convert the numeric array (or return a pointer to it's
867		 * data), but only if it is the right type:
868		 * - If typestr is a basic type, the array must be a 1D array
869		 *   of that type
870		 * - If typestr is a structured type, the array must be a 2D
871		 *   array where rows match the structured type
872		 *
873		 * XXX: I have no idea if this is feasable, not having used
874		 * numarray/numeric myself.
875		 */
876#endif /* PyObjC_ENABLE_NUMARRAY */
877	} else {
878		Py_ssize_t seqlen;
879		Py_ssize_t pycount;
880
881		if (*elementType == _C_NSBOOL) {
882			if (PyString_Check(pythonList)) {
883				PyErr_Format(PyExc_ValueError, "Need array of BOOL, got string");
884				return -1;
885			}
886		} else if (*elementType == _C_CHAR_AS_INT) {
887			if (PyString_Check(pythonList)) {
888				PyErr_Format(PyExc_ValueError, "Need array of small integers, got string");
889				return -1;
890			}
891		}
892		PyObject* seq = PySequence_Fast(pythonList,
893					"converting to a C array");
894		if (seq == NULL) {
895			return -1;
896		}
897
898		seqlen = PySequence_Fast_GET_SIZE(seq);
899		if (size == NULL || *size == -1) {
900			pycount = seqlen;
901		} else {
902			pycount = *size;
903		}
904
905		if ((exactSize && seqlen != pycount) || (!exactSize && seqlen < pycount)) {
906			Py_DECREF(seq);
907			PyErr_Format(PyExc_ValueError,
908					"too few values (%"PY_FORMAT_SIZE_T"d) expecting at "
909					"least %"PY_FORMAT_SIZE_T"d", seqlen, pycount);
910			return -1;
911		}
912		*array = PyMem_Malloc(eltsize * pycount);
913		if (*array == NULL) {
914			Py_DECREF(seq);
915			PyErr_NoMemory();
916			return -1;
917		}
918		if (size) {
919			*size = pycount;
920		}
921		*bufobj = NULL;
922
923		for (i = 0; i < pycount; i++) {
924			PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
925
926			r = depythonify_c_value(elementType, item,
927					((char*)*array)+(i*eltsize));
928			if (r == -1) {
929				Py_DECREF(seq);
930				PyMem_Free(*array); *array = NULL;
931				return -1;
932			}
933		}
934		return SHOULD_FREE;
935	}
936
937}
938
939
940PyObject*
941PyObjC_CArrayToPython(
942	const char* elementType,
943	void* array,
944	Py_ssize_t size)
945{
946	PyObject* result;
947	Py_ssize_t i;
948	Py_ssize_t eltsize;
949
950	eltsize = PyObjCRT_SizeOfType(elementType);
951	if (eltsize == -1) {
952		return NULL;
953	}
954
955
956	if (eltsize == 1 || eltsize == 0) {
957		if (*elementType != _C_NSBOOL && *elementType != _C_BOOL && *elementType != _C_CHAR_AS_INT) {
958			/* Special case for buffer-like objects */
959			return PyString_FromStringAndSize(array, size);
960		}
961	}
962
963	if (*elementType == _C_UNICHAR) {
964#if defined(PyObjC_UNICODE_FAST_PATH)
965		result = PyUnicode_FromUnicode((Py_UNICODE*)array, size);
966#else
967#		error "Sorry, Wide Unicode builds not supported at the moment"
968#endif
969		return result;
970	}
971
972	result = PyTuple_New(size);
973	if (result == NULL) {
974		return NULL;
975	}
976
977
978	for (i = 0; i < size; i++) {
979		PyObject* elt = pythonify_c_value(elementType, array);
980		if (elt == NULL) {
981			Py_DECREF(result);
982			return NULL;
983		}
984
985		PyTuple_SET_ITEM(result, i, elt);
986		array = ((char*)array) + eltsize;
987	}
988
989	return result;
990}
991
992int
993PyObjC_IsPythonKeyword(const char* word)
994{
995	/*
996	 * We cheat a little: this list only contains those keywords that
997	 * are actually used in Cocoa.
998	 *
999	 * XXX: If we ever add the complete list here we should optimize
1000	 * this function.
1001	 */
1002	static const char* keywords[] = {
1003		"class",
1004		"raise",
1005		NULL
1006	};
1007	const char** cur;
1008
1009	for (cur = keywords; *cur != NULL; cur++) {
1010		if (strcmp(word, *cur) == 0) {
1011			return 1;
1012		}
1013	}
1014	return 0;
1015}
1016
1017int
1018PyObjCRT_SimplifySignature(char* signature, char* buf, size_t buflen)
1019{
1020	char* cur;
1021	char* end;
1022	char* next;
1023
1024	cur = signature;
1025	*buf = '\0';
1026
1027	while (*cur != '\0') {
1028		next = end = (char*)PyObjCRT_SkipTypeSpec(cur);
1029		end -= 1;
1030		while (end != cur && isdigit(*end)) {
1031			end --;
1032		}
1033		end++;
1034
1035		if ((size_t)(end - cur) > buflen) {
1036			return -1;
1037		}
1038
1039		memcpy(buf, cur, end-cur);
1040		buflen -= (end-cur);
1041		buf += (end-cur);
1042		*buf = '\0';
1043		cur = next;
1044	}
1045	return 0;
1046}
1047
1048int
1049PyObjCObject_Convert(PyObject* object, void* pvar)
1050{
1051	int r;
1052	r = depythonify_c_value(@encode(id), object, (id*)pvar);
1053	if (r == -1) {
1054		return 0;
1055	} else {
1056		return 1;
1057	}
1058}
1059
1060int
1061PyObjC_ConvertBOOL(PyObject* object, void* pvar)
1062{
1063    BOOL* pbool = (BOOL*)pvar;
1064
1065    if (PyObject_IsTrue(object)) {
1066        *pbool = YES;
1067    } else {
1068        *pbool = NO;
1069    }
1070
1071    return 1;
1072}
1073
1074int
1075PyObjC_ConvertChar(PyObject* object, void* pvar)
1076{
1077    char* pchar = (char*)pvar;
1078
1079    if (!PyString_Check(object)) {
1080        PyErr_SetString(PyExc_TypeError, "Expecting string of len 1");
1081        return 0;
1082    }
1083
1084    if (PyString_Size(object) != 1) {
1085        PyErr_SetString(PyExc_TypeError, "Expecting string of len 1");
1086        return 0;
1087    }
1088
1089    *pchar = *PyString_AsString(object);
1090    return 1;
1091}
1092
1093int
1094PyObjCSelector_Convert(PyObject* object, void* pvar)
1095{
1096    int r;
1097
1098    if (object == Py_None) {
1099        *(SEL*)pvar = NULL;
1100        return 1;
1101    }
1102    if (PyObjCSelector_Check(object)) {
1103        *(SEL*)pvar = PyObjCSelector_GetSelector(object);
1104        return 1;
1105    }
1106    if (!PyString_Check(object)) {
1107        PyErr_SetString(PyExc_TypeError, "Expected string");
1108        return 0;
1109    }
1110
1111    r = depythonify_c_value(@encode(SEL), object, pvar);
1112    if (r == -1) {
1113           return 0;
1114    }
1115    return 1;
1116}
1117
1118int
1119PyObjCClass_Convert(PyObject* object, void* pvar)
1120{
1121    if (!PyObjCClass_Check(object)) {
1122        PyErr_SetString(PyExc_TypeError, "Expected objective-C class");
1123        return 0;
1124    }
1125
1126    *(Class*)pvar = PyObjCClass_GetClass(object);
1127    if (*(Class*)pvar == NULL) return 0;
1128    return 1;
1129}
1130
1131
1132PyObject*
1133PyObjC_CArrayToPython2(
1134	const char* elementType,
1135	void* array,
1136	Py_ssize_t size,
1137	bool alreadyRetained,
1138	bool alreadyCFRetained)
1139{
1140	PyObject* result;
1141	Py_ssize_t i;
1142	Py_ssize_t eltsize;
1143
1144	if (size == -1) {
1145		size = 0;
1146	}
1147
1148	eltsize = PyObjCRT_SizeOfType(elementType);
1149	if (eltsize == -1) {
1150		return NULL;
1151	}
1152
1153	if (eltsize == 1 || eltsize == 0) {
1154		if (*elementType != _C_NSBOOL && *elementType != _C_BOOL && *elementType != _C_CHAR_AS_INT) {
1155			/* Special case for buffer-like objects */
1156			return PyString_FromStringAndSize(array, size);
1157		}
1158	}
1159	if (*elementType == _C_UNICHAR) {
1160#if defined(PyObjC_UNICODE_FAST_PATH)
1161		result = PyUnicode_FromUnicode((Py_UNICODE*)array, size);
1162#else
1163#		error "Sorry, Wide Unicode builds not supported at the moment"
1164#endif
1165		return result;
1166	}
1167
1168	result = PyTuple_New(size);
1169	if (result == NULL) {
1170		return NULL;
1171	}
1172
1173
1174	for (i = 0; i < size; i++) {
1175		PyObject* elt = pythonify_c_value(elementType, array);
1176		if (elt == NULL) {
1177			Py_DECREF(result);
1178			return NULL;
1179		}
1180
1181		if (alreadyRetained) {
1182			[*(id*)array release];
1183		} else if (alreadyCFRetained) {
1184			CFRelease(*(id*)array);
1185		}
1186
1187		PyTuple_SET_ITEM(result, i, elt);
1188		array = ((char*)array) + eltsize;
1189	}
1190
1191	return result;
1192}
1193