1/*
2 * Wrappers for C structs
3 *
4 * Structs are represented as instance-like objects, with normal field access
5 * (e.g. myRect.size), but can also be accessed like read-write tuples (e.g.
6 * myRect[0]).
7 *
8 * Instances consist of the generic PyObject header followed by an array of
9 * fields.
10 *
11 * NOTE: The basic implementation is quite generic, but the end of this file
12 * is only usefull for PyObjC.
13 */
14#include "pyobjc.h"
15
16/*
17 * First some helpers: easy access to the actual fields
18 */
19static inline PyObject*
20GET_FIELD(PyObject* self, PyMemberDef* member)
21{
22	PyObject* v;
23
24	v =  *(PyObject**)(((char*)self) + member->offset);
25	if (v == NULL) {
26		return Py_None;
27	} else {
28		return v;
29	}
30}
31
32static inline void
33SET_FIELD(PyObject* self, PyMemberDef* member, PyObject* val)
34{
35	PyObject* tmp;
36	Py_XINCREF(val);
37
38	tmp = *(PyObject**)(((char*)self) + member->offset);
39	*((PyObject**)(((char*)self) + member->offset)) = val;
40	Py_XDECREF(tmp);
41}
42
43/*
44 * Implementation of the sequence interface.
45 */
46
47static Py_ssize_t
48struct_sq_length(PyObject* self)
49{
50	/* The object contains the generic PyObject header followed by an
51	 * array of PyObject*-s.
52	 */
53	return (Py_TYPE(self)->tp_basicsize - sizeof(PyObject)) / sizeof(PyObject*);
54}
55
56static PyObject*
57struct_sq_item(PyObject* self, Py_ssize_t offset)
58{
59	Py_ssize_t len = struct_sq_length(self);
60	PyMemberDef* member;
61	PyObject* res;
62
63	if (offset < 0 || offset >= len) {
64		PyErr_Format(PyExc_IndexError,
65				"%s index out of range",
66				Py_TYPE(self)->tp_name);
67		return NULL;
68	}
69
70	member = Py_TYPE(self)->tp_members + offset;
71	res = GET_FIELD(self, member);
72
73	Py_INCREF(res);
74	return res;
75}
76
77static PyObject*
78struct_sq_slice(PyObject* self, Py_ssize_t ilow, Py_ssize_t ihigh)
79{
80	PyObject* result;
81	Py_ssize_t i, len;
82
83	len = struct_sq_length(self);
84	if (ilow < 0)  ilow = 0;
85	if (ihigh > len) ihigh = len;
86
87	result = PyTuple_New(ihigh - ilow);
88	if (result == NULL) {
89		return NULL;
90	}
91
92	for (i = ilow; i < ihigh; i++) {
93		PyMemberDef* member = Py_TYPE(self)->tp_members + i;
94		PyObject* v = GET_FIELD(self, member);
95		Py_INCREF(v);
96		PyTuple_SET_ITEM(result, i-ilow, v);
97	}
98	return result;
99}
100
101static int
102struct_sq_ass_item(PyObject* self, Py_ssize_t offset, PyObject* newVal)
103{
104	Py_ssize_t len;
105	PyMemberDef* member;
106
107	if (newVal == NULL) {
108		PyErr_Format(PyExc_TypeError,
109			"Cannot delete item '%"PY_FORMAT_SIZE_T"d' in a %s instance",
110			offset, Py_TYPE(self)->tp_name);
111		return -1;
112	}
113
114	len = struct_sq_length(self);
115
116	if ((offset < 0) || (offset >= len)) {
117		PyErr_Format(PyExc_IndexError,
118				"%s index out of range",
119				Py_TYPE(self)->tp_name);
120		return -1;
121	}
122	member = Py_TYPE(self)->tp_members + offset;
123	SET_FIELD(self, member, newVal);
124	return 0;
125}
126
127static int
128struct_sq_ass_slice(PyObject* self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject* v)
129{
130	PyObject* seq;
131	Py_ssize_t i, len;
132
133	if (v == NULL) {
134		PyErr_Format(PyExc_TypeError,
135			"Cannot delete items in an %s instance",
136			Py_TYPE(self)->tp_name);
137		return -1;
138	}
139
140
141	len = struct_sq_length(self);
142	if (ilow < 0)  {
143		ilow = 0;
144	} else if (ilow > len) {
145		ilow = len;
146	}
147
148	if (ihigh < ilow) {
149		ihigh = ilow;
150	} else if (ihigh > len) {
151		ihigh = len;
152	}
153
154	seq = PySequence_Fast(v, "must assign sequence to slice");
155	if (seq == NULL) return -1;
156
157	if (PySequence_Fast_GET_SIZE(seq) != ihigh - ilow) {
158		Py_DECREF(seq);
159		PyErr_Format(PyExc_TypeError,
160			"slice assignment would change size of %s "
161			"instance", Py_TYPE(self)->tp_name);
162		return -1;
163	}
164
165	for (i = ilow; i < ihigh; i++) {
166		PyObject* x;
167		PyMemberDef* member = Py_TYPE(self)->tp_members + i;
168
169		x = PySequence_Fast_GET_ITEM(seq, i-ilow);
170		if (x == NULL) {
171			Py_DECREF(seq);
172			return -1;
173		}
174		SET_FIELD(self, member, x);
175	}
176	Py_DECREF(seq);
177	return 0;
178}
179
180static int
181struct_sq_contains(PyObject* self, PyObject* value)
182{
183	PyMemberDef* member = Py_TYPE(self)->tp_members;
184
185	while (member && member->name) {
186		int r;
187		PyObject* cur = GET_FIELD(self, member);
188
189		r = PyObject_RichCompareBool(cur, value, Py_EQ);
190		if (r == -1) {
191			PyErr_Clear();
192		} else if (r) {
193			return 1;
194		}
195	}
196	return 0;
197}
198
199static PyObject*
200struct_reduce(PyObject* self)
201{
202	PyObject* result;
203	PyObject* values;
204	Py_ssize_t i, len;
205
206	len = struct_sq_length(self);
207	values = PyTuple_New(len);
208	if (values == NULL) return NULL;
209
210	for (i = 0; i < len; i++) {
211		PyObject* v = GET_FIELD(self, Py_TYPE(self)->tp_members + i);
212		Py_INCREF(v);
213		PyTuple_SET_ITEM(values, i, v);
214	}
215
216	result = Py_BuildValue("(OO)", Py_TYPE(self), values);
217	Py_DECREF(values);
218	return result;
219}
220
221static PyObject*
222struct_copy(PyObject* self)
223{
224	PyObject* result;
225	PyMemberDef* member = Py_TYPE(self)->tp_members;
226
227	result = PyObject_GC_New(PyObject, Py_TYPE(self));
228	if (result == NULL) {
229		return NULL;
230	}
231
232	while (member && member->name) {
233		if (member->type != T_OBJECT) {
234			member++;
235			continue;
236		}
237		*((PyObject**)(((char*)result) + member->offset)) = NULL;
238		PyObject* t = GET_FIELD(self, member);
239
240		if (t != NULL) {
241			PyObject* m = PyObject_GetAttrString(t, "__pyobjc_copy__");
242			if (m == NULL) {
243				PyErr_Clear();
244				SET_FIELD(result, member, t);
245			} else {
246				PyObject* c = PyObject_CallObject(m, NULL);
247				Py_DECREF(m);
248				if (c == NULL) {
249					Py_DECREF(result);
250					return NULL;
251				}
252				SET_FIELD(result, member, c);
253				Py_DECREF(c);
254			}
255		}
256
257		member++;
258	}
259
260	PyObject_GC_Track(result);
261	return result;
262}
263
264static PyObject*
265struct_replace(PyObject* self, PyObject* args, PyObject* kwds)
266{
267	/* XXX: This is a fairly inefficient implementation, first
268	 * perform a deep copy, then replace attributes. The deep copy
269	 * provides the nicest transition path to read-only structs:
270	 * the result of _replace is completely independent of the original.
271	 */
272	PyObject* result;
273	Py_ssize_t pos = 0;
274	PyObject* key;
275	PyObject* value;
276
277	if (args && PySequence_Length(args) != 0) {
278		PyErr_SetString(PyExc_TypeError,
279		 	"_replace called with positional arguments");
280		return NULL;
281	}
282
283	result = struct_copy(self);
284	if (result == NULL) {
285		return NULL;
286	}
287
288	while (PyDict_Next(kwds, &pos, &key, &value)) {
289		int r = PyObject_SetAttr(result, key, value);
290		if (r == -1) {
291			Py_DECREF(result);
292			return NULL;
293		}
294	}
295
296	return result;
297}
298
299static PyObject*
300struct_asdict(PyObject* self)
301{
302	PyObject* result;
303	PyMemberDef* member = Py_TYPE(self)->tp_members;
304	int r;
305
306	result = PyDict_New();
307	if (result == NULL) {
308		return NULL;
309	}
310
311	while (member && member->name) {
312		if (member->type != T_OBJECT) {
313			member++;
314			continue;
315		}
316		PyObject* t = GET_FIELD(self, member);
317		r = PyDict_SetItemString(result, member->name, t);
318		if (r == -1) {
319			Py_DECREF(result);
320			return NULL;
321		}
322		member++;
323	}
324
325	return result;
326}
327
328static PyObject*
329struct_mp_subscript(PyObject* self, PyObject* item)
330{
331	if (PyIndex_Check(item)) {
332		Py_ssize_t i;
333		i = PyNumber_AsSsize_t(item, PyExc_IndexError);
334		if (i == -1 && PyErr_Occurred()) {
335			return NULL;
336		}
337		if (i < 0) {
338			i += struct_sq_length(self);
339		}
340		return struct_sq_item(self, i);
341	} else if (PySlice_Check(item)) {
342		Py_ssize_t start, stop, step, slicelength, cur, i;
343		PyObject* result;
344		PyObject* it;
345
346		if (PySlice_GetIndicesEx(SLICE_CAST(item),
347				struct_sq_length(self),
348				&start, &stop, &step, &slicelength) < 0) {
349			return NULL;
350		}
351
352		if (slicelength <= 0) {
353			return PyTuple_New(0);
354		} else if (step == 1) {
355			return struct_sq_slice(self, start, stop);
356		} else {
357			result = PyTuple_New(slicelength);
358			if (result == NULL) {
359				return NULL;
360			}
361
362			for (cur = start, i = 0; i < slicelength;
363						cur += step, i++) {
364				it = struct_sq_item(self, cur);
365				PyTuple_SET_ITEM(result, i, it);
366			}
367			return result;
368		}
369
370	} else {
371		PyErr_Format(PyExc_TypeError,
372			"struct indices must be integers, not %.200s",
373			Py_TYPE(item)->tp_name);
374		return NULL;
375	}
376}
377
378static int
379struct_mp_ass_subscript(PyObject* self, PyObject* item, PyObject* value)
380{
381	if (PyIndex_Check(item)) {
382		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
383		if (i == -1 && PyErr_Occurred()) {
384			return -1;
385		}
386		if (i < 0) {
387			i += struct_sq_length(self);
388		}
389		return struct_sq_ass_item(self, i, value);
390	} else if (PySlice_Check(item)) {
391		Py_ssize_t start, stop, step, slicelength;
392
393		if (PySlice_GetIndicesEx(SLICE_CAST(item),
394				struct_sq_length(self), &start, &stop,
395				&step, &slicelength) < 0) {
396			return -1;
397		}
398		if (step == 1) {
399			return struct_sq_ass_slice(self, start, stop, value);
400		}
401
402		if (value == NULL) {
403			PyErr_Format(PyExc_TypeError,
404				"Cannot delete items in an %s instance",
405				Py_TYPE(self)->tp_name);
406			return -1;
407		}
408
409		PyObject* seq = PySequence_Fast(value,
410				"must assign sequence to slice");
411		if (seq == NULL) return -1;
412
413		if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
414			Py_DECREF(seq);
415			PyErr_Format(PyExc_TypeError,
416				"slice assignment would change size of %s "
417				"instance", Py_TYPE(self)->tp_name);
418			return -1;
419		}
420
421		Py_ssize_t cur, i;
422		for (cur = start, i = 0; i < slicelength; cur += step, i++) {
423			int r = struct_sq_ass_item(self, cur,
424				PySequence_Fast_GET_ITEM(seq, i));
425			if (r == -1) {
426				Py_DECREF(seq);
427				return -1;
428			}
429		}
430
431		Py_DECREF(seq);
432		return 0;
433	} else {
434		PyErr_Format(PyExc_TypeError,
435			"struct indices must be integers, not %.200s",
436			Py_TYPE(item)->tp_name);
437		return -1;
438	}
439}
440
441
442static PySequenceMethods struct_as_sequence = {
443	struct_sq_length,	/* sq_length */
444	NULL,			/* sq_concat */
445	NULL,			/* sq_repeat */
446	struct_sq_item,		/* sq_item */
447	struct_sq_slice,	/* sq_slice */
448	struct_sq_ass_item,	/* sq_ass_item */
449	struct_sq_ass_slice,	/* sq_ass_slice */
450	struct_sq_contains,	/* sq_contains */
451	NULL,			/* sq_inplace_concat */
452	NULL			/* sq_inplace_repeat */
453};
454
455static PyMappingMethods struct_as_mapping = {
456	struct_sq_length,
457	struct_mp_subscript,
458	struct_mp_ass_subscript,
459};
460
461static PyMethodDef struct_methods[] = {
462	{
463		"__reduce__",
464		(PyCFunction)struct_reduce,
465		METH_NOARGS,
466		NULL
467	},
468	{
469		"copy",
470		(PyCFunction)struct_copy,
471		METH_NOARGS,
472		"Return a copy of the struct",
473	},
474	{
475		"__pyobjc_copy__",
476		(PyCFunction)struct_copy,
477		METH_NOARGS,
478		NULL,
479	},
480	/* NamedTuple interface */
481	{
482		"_asdict",
483		(PyCFunction)struct_asdict,
484		METH_NOARGS,
485		NULL
486	},
487	{
488		"_replace",
489		(PyCFunction)struct_replace,
490		METH_VARARGS|METH_KEYWORDS,
491		NULL
492	},
493	{ NULL, NULL, 0, NULL }
494};
495
496
497/*
498 * Special methods
499 */
500
501static int
502struct_setattro(PyObject* self, PyObject* name, PyObject* value)
503{
504	if (value == NULL) {
505		PyErr_Format(PyExc_TypeError, "Cannot delete attributes of %s",
506				Py_TYPE(self)->tp_name);
507		return -1;
508	}
509	return PyObject_GenericSetAttr(self, name, value);
510}
511
512static void
513struct_dealloc(PyObject* self)
514{
515	PyMemberDef* member = Py_TYPE(self)->tp_members;
516
517	PyObject_GC_UnTrack(self);
518
519	while (member && member->name) {
520		Py_XDECREF(*(PyObject**)(((char*)self)+member->offset));
521		member++;
522	}
523
524	PyObject_GC_Del(self);
525}
526
527static PyObject*
528struct_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
529{
530	PyObject* result;
531	PyMemberDef* member = type->tp_members;
532	int r;
533
534	result = PyObject_GC_New(PyObject, type);
535	if (result == NULL) return NULL;
536
537	while (member && member->name) {
538		if (member->type != T_OBJECT) {
539			member++;
540			continue;
541		}
542		*((PyObject**)(((char*)result) + member->offset)) = NULL;
543		member++;
544	}
545	PyObject_GC_Track(result);
546
547	r = type->tp_init(result, args, kwds);
548	if (r == -1) {
549		Py_DECREF(result);
550		return NULL;
551	}
552	return result;
553}
554
555static int LOCATE_MEMBER(PyTypeObject* type, const char* name)
556{
557	int i = 0;
558	PyMemberDef* member;
559
560	for (i = 0,  member = type->tp_members;
561			member->name != NULL; i++, member++) {
562		if (strcmp(member->name, name) == 0) {
563			return i;
564		}
565	}
566	return -1;
567}
568
569static int set_defaults(PyObject* self, const char* typestr)
570{
571	Py_ssize_t i = 0;
572	int r;
573	PyObject* v;
574
575	while(*typestr != _C_STRUCT_E && *typestr++ != '=');
576	while(typestr && *typestr != _C_STRUCT_E) {
577		const char* next;
578
579		if (*typestr == '"') {
580			/* embedded field names */
581			typestr = strchr(typestr+1, '"');
582			if (typestr) {
583				typestr++;
584			} else {
585				break;
586			}
587		}
588		next = PyObjCRT_SkipTypeSpec(typestr);
589		switch (*typestr) {
590#ifdef _C_BOOL
591		case _C_BOOL:
592			v = PyBool_FromLong(0);
593			break;
594#endif
595		case _C_NSBOOL:
596			v = PyBool_FromLong(0);
597			break;
598
599		case _C_CHAR_AS_TEXT:
600			{
601				char ch = 0;
602				v = PyText_FromStringAndSize(&ch, 1);
603			}
604			break;
605
606		case _C_UNICHAR:
607			{
608				Py_UNICODE ch = 0;
609				v = PyUnicode_FromUnicode(&ch, 1);
610			}
611			break;
612
613		case _C_CHAR_AS_INT:
614		case _C_CHR: case _C_UCHR:
615		case _C_SHT: case _C_USHT:
616		case _C_INT: case _C_UINT:
617		case _C_LNG: case _C_ULNG:
618		case _C_LNG_LNG: case _C_ULNG_LNG:
619			v = PyInt_FromLong(0);
620			break;
621
622		case _C_FLT: case _C_DBL:
623			v = PyFloat_FromDouble(0.0);
624			break;
625
626		case _C_STRUCT_B:
627			v = PyObjC_CreateRegisteredStruct(typestr, next-typestr, NULL, NULL);
628			if (v != NULL) {
629				/* call init */
630				r = Py_TYPE(v)->tp_init(v, NULL, NULL);
631				if (r == -1) {
632					Py_DECREF(v);
633					return -1;
634				}
635			} else if (!PyErr_Occurred()) {
636				/* this is a struct-type without a struct
637				 * wrapper. Default to None
638				 */
639				v = Py_None;
640				Py_INCREF(Py_None);
641			}
642
643
644			break;
645
646		default:
647			v = Py_None;
648			Py_INCREF(Py_None);
649		}
650
651		if (v == NULL) {
652			return -1;
653		}
654
655		r = PySequence_SetItem(self, i++, v);
656		Py_DECREF(v);
657		if (r != 0) {
658			return -1;
659		}
660
661		typestr = next;
662	}
663
664	return 0;
665}
666
667
668static void
669struct_init(
670	ffi_cif* cif __attribute__((__unused__)),
671	void* retval,
672	void** cargs,
673	void* userdata
674	   )
675{
676	PyObject* self = *(PyObject**)cargs[0];
677	PyObject* args = *(PyObject**)cargs[1];
678	PyObject* kwds = *(PyObject**)cargs[2];
679	const char* typestr = (char*)userdata;
680	Py_ssize_t setUntil = -1;
681	int r;
682
683	if (self == NULL) {
684		*(int**)retval = 0;
685		return;
686	}
687
688	if (args != NULL && !PyTuple_Check(args)) {
689		PyErr_Format(PyExc_TypeError,
690				"%s() argument tuple is not a tuple",
691				Py_TYPE(self)->tp_name);
692		*(int*)retval = -1;
693		return;
694	}
695	if (kwds != NULL && !PyDict_Check(kwds)) {
696		PyErr_Format(PyExc_TypeError,
697				"%s() keyword dict is not a dict",
698				Py_TYPE(self)->tp_name);
699		*(int*)retval = -1;
700		return;
701	}
702
703	r = set_defaults(self, typestr);
704	if (r != 0) {
705		*(int*)retval = r;
706		return;
707	}
708
709	if (args != NULL) {
710		Py_ssize_t i, len;
711
712		len = PyTuple_GET_SIZE(args);
713		if (len > struct_sq_length(self)) {
714			PyErr_Format(PyExc_TypeError,
715				"%s() takes at most %"PY_FORMAT_SIZE_T"d %sarguments (%"PY_FORMAT_SIZE_T"d given)",
716				Py_TYPE(self)->tp_name,
717				struct_sq_length(self),
718				kwds?"non-keyword ":"", len);
719			*(int*)retval = -1;
720			return;
721		}
722		for (i = 0; i < len; i++) {
723			PyObject* v = PyTuple_GET_ITEM(args, i);
724
725			SET_FIELD(self, Py_TYPE(self)->tp_members+i, v);
726		}
727		setUntil = len-1;
728	}
729
730	if (kwds != NULL) {
731		PyObject* keys;
732		int i, len;
733
734		keys = PyDict_Keys(kwds);
735		if (keys == NULL) {
736			*(int*)retval = -1;
737			return;
738		}
739
740		if (!PyList_Check(keys)) {
741			Py_DECREF(keys);
742			PyErr_SetString(PyExc_TypeError,
743					"dict.keys didn't return a list");
744			*(int*)retval = -1;
745			return;
746		}
747
748		len = PyList_GET_SIZE(keys);
749		for (i = 0; i < len; i++) {
750			PyMemberDef* member;
751			Py_ssize_t off;
752			PyObject* k;
753			PyObject* v;
754			PyObject* k_bytes = NULL;
755
756			k = PyList_GET_ITEM(keys, i);
757			if (PyUnicode_Check(k)) {
758				k_bytes = PyUnicode_AsEncodedString(k, NULL, NULL);
759				if (k_bytes == NULL) {
760					*(int*)retval = -1;
761					return;
762				}
763#if PY_MAJOR_VERSION == 2
764			} else if (PyString_Check(k)) {
765				k_bytes = k; Py_INCREF(k_bytes);
766#endif
767			} else {
768				Py_DECREF(keys);
769				PyErr_Format(PyExc_TypeError,
770					"%s() keywords must be strings",
771					Py_TYPE(self)->tp_name);
772				*(int*)retval = -1;
773				return;
774			}
775
776
777			off = LOCATE_MEMBER(Py_TYPE(self),
778					PyBytes_AS_STRING(k_bytes));
779			if (off == -1) {
780				PyErr_Format(PyExc_TypeError,
781					"no keyword argument: %s",
782					PyBytes_AS_STRING(k_bytes));
783				Py_DECREF(k_bytes);
784				Py_DECREF(keys);
785				*(int*)retval = -1;
786				return;
787			}
788
789			if (off <= setUntil) {
790				PyErr_Format(PyExc_TypeError,
791					"%s() got multiple values for keyword "
792					"argument '%s'",
793					Py_TYPE(self)->tp_name,
794					PyBytes_AS_STRING(k_bytes));
795				Py_DECREF(k_bytes);
796				Py_DECREF(keys);
797				*(int*)retval = -1;
798				return;
799			}
800			Py_DECREF(k_bytes);
801
802			member = Py_TYPE(self)->tp_members + off;
803			v = PyDict_GetItem(kwds, k);
804			SET_FIELD(self, member, v);
805		}
806		Py_DECREF(keys);
807	}
808
809	*(int*)retval = 0;
810	return;
811}
812
813static initproc
814make_init(const char* typestr)
815{
816static 	ffi_cif* init_cif = NULL;
817	ffi_closure* cl = NULL;
818	ffi_status rv;
819
820	if (init_cif == NULL) {
821		PyObjCMethodSignature* signature;
822		signature = PyObjCMethodSignature_FromSignature("i^v^v^v", YES);
823		init_cif = PyObjCFFI_CIFForSignature(signature);
824		Py_DECREF(signature);
825		if (init_cif == NULL) {
826			return NULL;
827		}
828	}
829
830	cl = PyObjC_malloc_closure();
831	if (cl == NULL) {
832		return NULL;
833	}
834
835	rv = ffi_prep_closure(cl, init_cif, struct_init, (char*)typestr);
836	if (rv != FFI_OK) {
837		PyObjC_free_closure(cl);
838		PyErr_Format(PyExc_RuntimeError,
839			"Cannot create FFI closure: %d", rv);
840		return NULL;
841	}
842
843	return (initproc)cl;
844}
845
846
847
848static long
849struct_hash(PyObject* self)
850{
851	PyErr_Format(PyExc_TypeError, "%s objects are unhashable",
852			Py_TYPE(self)->tp_name);
853	return -1;
854}
855
856static PyObject*
857struct_richcompare(PyObject* self, PyObject* other, int op)
858{
859	Py_ssize_t self_len, other_len, i, len;
860	int cmp;
861	PyObject* self_cur;
862	PyObject* other_cur;
863
864	if (!PySequence_Check(other)) {
865		if (op == Py_EQ) {
866			Py_INCREF(Py_False);
867			return Py_False;
868		} else if (op == Py_NE) {
869			Py_INCREF(Py_True);
870			return Py_True;
871		} else {
872			PyErr_Format(PyExc_TypeError,
873				"Cannot compare instances of %s and %s",
874				Py_TYPE(self)->tp_name,
875				Py_TYPE(other)->tp_name);
876			return NULL;
877		}
878	}
879
880	self_len = struct_sq_length(self);
881	other_len = PySequence_Length(other);
882	len = self_len;
883	if (other_len < len) {
884		len = other_len;
885	}
886
887	if (self_len != other_len && (op == Py_EQ || op == Py_NE)){
888		/* Shortcut comparison for non-equals lengths */
889		if (op == Py_EQ) {
890			Py_INCREF(Py_False);
891			return Py_False;
892		} else {
893			Py_INCREF(Py_True);
894			return Py_True;
895		}
896	}
897
898	for (i = 0; i < len; i ++) {
899		int k;
900
901		self_cur = GET_FIELD(self, Py_TYPE(self)->tp_members+i);
902		other_cur = PySequence_GetItem(other, i);
903		if (other_cur == NULL) return NULL;
904
905		k = PyObject_RichCompareBool(self_cur, other_cur, Py_EQ);
906		if (k < 0) {
907			Py_DECREF(other_cur);
908			return NULL;
909		}
910
911		if (!k) {
912			/* Not equal, result is the comparison of the last
913			 * item, we can do better for '==' and '!='.
914			 */
915			PyObject* v;
916
917			if (op == Py_EQ) {
918				Py_INCREF(Py_False);
919				return Py_False;
920			} else if (op == Py_NE) {
921				Py_INCREF(Py_True);
922				return Py_True;
923			}
924			v = PyObject_RichCompare(self_cur, other_cur, op);
925			Py_DECREF(other_cur);
926			return v;
927		}
928		Py_DECREF(other_cur);
929	}
930
931	/* All items are equal, compare using sizes */
932	switch (op) {
933	case Py_LT: cmp = self_len < other_len; break;
934	case Py_LE: cmp = self_len <= other_len; break;
935	case Py_EQ: cmp = self_len == other_len; break;
936	case Py_NE: cmp = self_len != other_len; break;
937	case Py_GE: cmp = self_len >= other_len; break;
938	case Py_GT: cmp = self_len > other_len; break;
939	default:
940		    /* Should never happen */
941		    PyErr_SetString(PyExc_TypeError, "Invalid comparion");
942		    return NULL;
943	}
944	if (cmp) {
945		Py_INCREF(Py_True);
946		return Py_True;
947	} else {
948		Py_INCREF(Py_False);
949		return Py_False;
950	}
951}
952
953static int
954struct_traverse(PyObject* self, visitproc visit, void* arg)
955{
956	PyMemberDef* member;
957	PyObject* v;
958	int err;
959
960	for (member = Py_TYPE(self)->tp_members;
961				member && member->name; member++) {
962		v = GET_FIELD(self, member);
963		if (v == NULL) continue;
964		err = visit(v, arg);
965		if (err) return err;
966	}
967	return 0;
968}
969
970static int
971struct_clear(PyObject* self)
972{
973	PyMemberDef* member;
974
975	for (member = Py_TYPE(self)->tp_members;
976				member && member->name; member++) {
977		SET_FIELD(self, member, NULL);
978	}
979	return 0;
980}
981
982
983
984static PyObject*
985struct_repr(PyObject* self)
986{
987	Py_ssize_t i, len;
988	PyObject* cur;
989	PyMemberDef* member;
990
991	len = struct_sq_length(self);
992	if (len == 0) {
993		return PyText_FromFormat("<%s>",
994				Py_TYPE(self)->tp_name);
995	}
996
997	i = Py_ReprEnter(self);
998	if (i < 0) {
999		return NULL;
1000	} else if (i != 0) {
1001		/* Self-recursive struct */
1002		return PyText_FromFormat("<%s ...>",
1003				Py_TYPE(self)->tp_name);
1004	}
1005
1006	cur = PyText_FromFormat("<%s", Py_TYPE(self)->tp_name);
1007
1008	member = Py_TYPE(self)->tp_members;
1009	while (member->name != NULL) {
1010		PyObject* v;
1011
1012		PyText_Append(&cur,
1013			PyText_FromFormat(" %s=", member->name));
1014		if (cur == NULL) goto done;
1015
1016		v = GET_FIELD(self, member);
1017
1018		PyText_Append(&cur, PyObject_Repr(v));
1019		if (cur == NULL) goto done;
1020		member++;
1021	}
1022
1023	PyText_Append(&cur, PyText_FromString(">"));
1024
1025done:
1026	Py_ReprLeave(self);
1027	return cur;
1028}
1029
1030struct StructTypeObject {
1031	PyTypeObject     base;
1032	Py_ssize_t       pack; 		/* struct packing, -1 for default packing */
1033};
1034
1035/*
1036 * A template for the type object
1037 */
1038static struct StructTypeObject StructTemplate_Type = {
1039    {
1040	PyVarObject_HEAD_INIT(NULL, 0)
1041	"objc.StructTemplate",			/* tp_name */
1042	sizeof (PyObject*),			/* tp_basicsize */
1043	0,					/* tp_itemsize */
1044
1045	/* methods */
1046	struct_dealloc,				/* tp_dealloc */
1047	0,					/* tp_print */
1048	0,					/* tp_getattr */
1049	0,					/* tp_setattr */
1050	0,					/* tp_compare */
1051	struct_repr,				/* tp_repr */
1052	0,					/* tp_as_number */
1053	&struct_as_sequence,			/* tp_as_sequence */
1054	&struct_as_mapping,			/* tp_as_mapping */
1055	struct_hash,				/* tp_hash */
1056	0,					/* tp_call */
1057	0,					/* tp_str */
1058	PyObject_GenericGetAttr,		/* tp_getattro */
1059	struct_setattro,			/* tp_setattro */
1060	0,					/* tp_as_buffer */
1061	Py_TPFLAGS_DEFAULT
1062#if PY_MAJOR_VERSION == 2
1063		| Py_TPFLAGS_HAVE_RICHCOMPARE
1064#endif
1065		| Py_TPFLAGS_HAVE_GC, 		/* tp_flags */
1066	0,					/* tp_doc */
1067	struct_traverse,			/* tp_traverse */
1068	struct_clear,				/* tp_clear */
1069	struct_richcompare,			/* tp_richcompare */
1070	0,					/* tp_weaklistoffset */
1071	0,					/* tp_iter */
1072	0,					/* tp_iternext */
1073	struct_methods,				/* tp_methods */
1074	0,					/* tp_members */
1075	0,					/* tp_getset */
1076	0,					/* tp_base */
1077	0,					/* tp_dict */
1078	0,					/* tp_descr_get */
1079	0,					/* tp_descr_set */
1080	0,					/* tp_dictoffset */
1081	0,					/* tp_init */
1082	0,					/* tp_alloc */
1083	struct_new,				/* tp_new */
1084	0,					/* tp_free */
1085	0,					/* tp_is_gc */
1086	0,					/* tp_bases */
1087	0,					/* tp_mro */
1088	0,					/* tp_cache */
1089	0,					/* tp_subclasses */
1090	0,					/* tp_weaklist */
1091	0					/* tp_del */
1092#if PY_VERSION_HEX >= 0x02060000
1093	, 0                                     /* tp_version_tag */
1094#endif
1095    },
1096    -1
1097};
1098
1099PyObject*
1100PyObjC_MakeStructType(
1101		const char* name,
1102		const char* doc,
1103		initproc tpinit,
1104		Py_ssize_t numFields,
1105		const char** fieldnames,
1106		const char* typestr,
1107		Py_ssize_t pack)
1108{
1109	struct StructTypeObject* result;
1110	PyMemberDef* members;
1111	PyObject* fields;
1112	Py_ssize_t i;
1113
1114	fields = PyTuple_New(numFields);
1115	if (fields == NULL) {
1116		return NULL;
1117	}
1118
1119	members = PyMem_Malloc(sizeof(PyMemberDef) * (numFields+1));
1120	if (members == NULL) {
1121		Py_DECREF(fields);
1122		PyErr_NoMemory();
1123		return NULL;
1124	}
1125	for (i = 0; i < numFields; i++) {
1126		PyObject* nm = PyText_FromString(fieldnames[i]);
1127		if (nm == NULL) {
1128			Py_DECREF(fields);
1129			PyMem_Free(members);
1130			return NULL;
1131		}
1132		PyTuple_SET_ITEM(fields, i, nm); nm = NULL;
1133		members[i].name = (char*)fieldnames[i];
1134		members[i].type = T_OBJECT;
1135		members[i].offset = sizeof(PyObject) + i*sizeof(PyObject*);
1136		members[i].flags = 0; /* A read-write field */
1137		members[i].doc = NULL;
1138
1139	}
1140	members[numFields].name = NULL;
1141
1142	result = PyMem_Malloc(sizeof(struct StructTypeObject));
1143	if (result == NULL) {
1144		Py_DECREF(fields);
1145		PyMem_Free(members);
1146		PyErr_NoMemory();
1147		return NULL;
1148	}
1149
1150	*result = StructTemplate_Type;
1151	result->base.tp_name = (char*)name;
1152	result->base.tp_doc = (char*)doc;
1153	result->base.tp_dict = PyDict_New();
1154	if (result->base.tp_dict == NULL) {
1155		Py_DECREF(fields);
1156		PyMem_Free(members);
1157		PyMem_Free(result);
1158		return NULL;
1159	}
1160	Py_REFCNT(result) = 1;
1161	result->base.tp_members = members;
1162	result->base.tp_basicsize = sizeof(PyObject) + numFields*sizeof(PyObject*);
1163	if (PyDict_SetItemString(result->base.tp_dict, "_fields", fields)==-1){
1164		Py_DECREF(fields);
1165		PyMem_Free(members);
1166		PyMem_Free(result);
1167		return NULL;
1168	}
1169	Py_CLEAR(fields);
1170
1171	if (tpinit) {
1172		result->base.tp_init = tpinit;
1173	} else {
1174		result->base.tp_init = make_init(typestr);
1175		if (result->base.tp_init == NULL) {
1176			PyMem_Free(members);
1177			PyMem_Free(result);
1178			return NULL;
1179		}
1180	}
1181
1182	/* XXX: Add _fields to tp_dict (NamedTuple interface */
1183
1184	result->pack = pack;
1185
1186	if (PyType_Ready((PyTypeObject*)result) == -1) {
1187		/* Is freeing save? */
1188		PyMem_Free(result);
1189		PyMem_Free(members);
1190		return NULL;
1191	}
1192	return (PyObject*)result;
1193}
1194
1195/*
1196 * This is the start of PyObjC specific code
1197 */
1198
1199static PyObject* structRegistry = NULL;
1200
1201PyObject*
1202PyObjC_CreateRegisteredStruct(const char* signature, Py_ssize_t len, const char** objc_encoding, Py_ssize_t* ppack)
1203{
1204	PyTypeObject* type;
1205	PyObject* result;
1206	PyObject* v;
1207	PyMemberDef* member;
1208
1209	if (structRegistry == NULL) return NULL;
1210
1211	if (ppack != NULL) {
1212		*ppack = -1;
1213	}
1214
1215	v = PyText_FromStringAndSize(signature, len);
1216	type = (PyTypeObject*)PyDict_GetItem(structRegistry, v);
1217	Py_DECREF(v);
1218	if (type == NULL) {
1219		PyErr_Clear();
1220		return NULL;
1221	}
1222
1223	member = type->tp_members;
1224
1225	result = PyObject_GC_New(PyObject, type);
1226	if (result == NULL) {
1227		PyErr_Clear();
1228		return NULL;
1229	}
1230
1231	while (member && member->name) {
1232		if (member->type != T_OBJECT) {
1233			member++;
1234			continue;
1235		}
1236		*((PyObject**)(((char*)result) + member->offset)) = NULL;
1237		member++;
1238	}
1239
1240	PyObject_GC_Track(result);
1241
1242	if (objc_encoding) {
1243		PyObject* typestr = PyDict_GetItemString(type->tp_dict, "__typestr__");
1244		if (typestr != NULL) {
1245			*objc_encoding = PyBytes_AsString(typestr);
1246		} else {
1247			*objc_encoding = signature;
1248		}
1249	}
1250	if (ppack != NULL) {
1251		*ppack = ((struct StructTypeObject*)type)->pack;
1252	}
1253	return result;
1254}
1255
1256
1257PyObject*
1258PyObjC_RegisterStructType(
1259		const char* signature,
1260		const char* name,
1261		const char* doc,
1262		initproc tpinit,
1263		Py_ssize_t numFields,
1264		const char** fieldnames,
1265		Py_ssize_t pack)
1266{
1267	PyObject* structType;
1268	PyObject* v;
1269	int r;
1270	int freeNames = 0;
1271
1272	if (numFields == -1) {
1273		/* XXX: extract me into a seperate function,
1274		 * and improve error checking/recovery.
1275		 */
1276		/* Don't use fieldnames, but extract the names
1277		 * from the type signature.
1278		 */
1279		const char* sigcur = signature;
1280		const char* fieldstart;
1281
1282		if (*sigcur != _C_STRUCT_B) {
1283			PyErr_SetString(PyExc_ValueError, "invalid signature: not a struct encoding");
1284			return NULL;
1285		}
1286
1287
1288		while (*sigcur && *sigcur != _C_STRUCT_E && *sigcur != '=') sigcur++;
1289
1290		if (!*sigcur || *sigcur == _C_STRUCT_E) {
1291			PyErr_SetString(PyExc_ValueError, "invalid signature: not a complete struct encoding");
1292			return NULL;
1293		}
1294
1295		fieldstart = ++sigcur;
1296		numFields = 0;
1297
1298		while (*sigcur != _C_STRUCT_E) {
1299			numFields ++;
1300			if (*sigcur == '"') {
1301				sigcur++;
1302				sigcur = strchr(sigcur, '"');
1303				if (sigcur == NULL) {
1304					PyErr_SetString(PyExc_ValueError, "invalid signature: embedded field name without end");
1305					return NULL;
1306				}
1307				sigcur++;
1308			} else {
1309				PyErr_SetString(PyExc_ValueError, "invalid signature: not all fields have an embedded name");
1310				return NULL;
1311			}
1312			if (*sigcur == _C_STRUCT_E) break;
1313			sigcur = PyObjCRT_NextField(sigcur);
1314			if (sigcur == NULL) {
1315				return NULL;
1316			}
1317		}
1318
1319		fieldnames = PyMem_Malloc((numFields + 1) * sizeof(char*));
1320		numFields = 0;
1321
1322		sigcur = fieldstart;
1323		while (*sigcur != _C_STRUCT_E) {
1324			if (*sigcur == '"') {
1325				char* end;
1326				sigcur++;
1327				end = strchr(sigcur, '"');
1328
1329				if (end == NULL) {
1330					PyErr_SetString(PyExc_ValueError, "invalid signature: embedded field name without end");
1331					return NULL;
1332				}
1333				fieldnames[numFields] = PyMem_Malloc(end - sigcur + 1);
1334				memcpy((char*)fieldnames[numFields], sigcur, end-sigcur);
1335				((char*)fieldnames[numFields])[end-sigcur] = '\0';
1336				sigcur = end + 1;
1337			}
1338			numFields ++;
1339			sigcur = PyObjCRT_NextField(sigcur);
1340		}
1341		fieldnames[numFields] = NULL;
1342		freeNames = 1;
1343
1344		/*
1345		 * The signature string still contains embedded field names,
1346		 * remove those.
1347		 */
1348		char* sigtmp = PyMem_Malloc(strlen(signature)+20);
1349		if (sigtmp == NULL) {
1350			PyErr_NoMemory();
1351			return NULL;
1352		}
1353		if (PyObjCRT_RemoveFieldNames(sigtmp, signature) == NULL) {
1354			PyMem_Free(sigtmp);
1355			return NULL;
1356		}
1357		signature = sigtmp;
1358	}
1359
1360
1361	structType = PyObjC_MakeStructType(name, doc, tpinit,
1362				numFields, fieldnames, signature, pack);
1363	if (structType == NULL) {
1364		if (freeNames) {
1365			int i;
1366			PyMem_Free((char*)signature);
1367			for (i = 0; i < numFields; i++) {
1368				PyMem_Free((char*)fieldnames[i]);
1369			}
1370			PyMem_Free(fieldnames);
1371		}
1372		return NULL;
1373	}
1374
1375	v = PyBytes_FromString(signature);
1376	if (v == NULL) {
1377		Py_DECREF(structType);
1378		return NULL;
1379	}
1380
1381	r = PyDict_SetItemString(((PyTypeObject*)structType)->tp_dict, "__typestr__", v);
1382	Py_DECREF(v);
1383	if (r == -1) {
1384		Py_DECREF(structType);
1385		return NULL;
1386	}
1387
1388	if (pack != -1) {
1389		/* Store custom struct packing as an attribute of the type
1390		 * object, to be able to  fetch it when depythonifying the object.
1391		 *
1392		 * XXX: Need a cleaner method for doing this.
1393		 */
1394		v = Py_BuildValue(Py_ARG_SIZE_T, pack);
1395		if (v == NULL) {
1396			Py_DECREF(structType);
1397			return NULL;
1398		}
1399		r = PyDict_SetItemString(((PyTypeObject*)structType)->tp_dict, "__struct_pack__", v);
1400		Py_DECREF(v);
1401		if (v == NULL) {
1402			Py_DECREF(structType);
1403			return NULL;
1404		}
1405	}
1406
1407	if (structRegistry == NULL) {
1408		structRegistry = PyDict_New();
1409		if (structRegistry == NULL) {
1410			/* This leaks some memory, but we cannot safely
1411			 * deallocate the type
1412			 */
1413			return NULL;
1414		}
1415	}
1416
1417	r = PyDict_SetItemString(structRegistry, signature, structType);
1418	if (r == -1) {
1419		/* This leaks some memory, but we cannot safely
1420		 * deallocate the type
1421		 */
1422		return NULL;
1423	}
1424
1425	/* Register again using the typecode used in the ObjC runtime */
1426	PyObjC_RemoveInternalTypeCodes((char*)signature);
1427	r = PyDict_SetItemString(structRegistry, signature, structType);
1428	if (r == -1) {
1429		return NULL;
1430	}
1431
1432	return structType;
1433}
1434
1435int
1436PyObjC_RegisterStructAlias(const char* signature, PyObject* structType)
1437{
1438	char buf[1024];
1439	int r;
1440
1441	if (strlen(signature) > 1023) {
1442		PyErr_SetString(PyExc_ValueError, "typestr too long");
1443		return -1;
1444	}
1445	if (PyObjCRT_RemoveFieldNames(buf, signature) == NULL) {
1446		return -1;
1447	}
1448
1449	if (structRegistry == NULL) {
1450		structRegistry = PyDict_New();
1451		if (structRegistry == NULL) {
1452			return -1;
1453		}
1454	}
1455
1456	r = PyDict_SetItemString(structRegistry, buf, structType);
1457	if (r == -1) {
1458		return -1;
1459	}
1460
1461	/* Register again using the typecode used in the ObjC runtime */
1462	PyObjC_RemoveInternalTypeCodes(buf);
1463	r = PyDict_SetItemString(structRegistry, buf, structType);
1464	if (r == -1) {
1465		return -1;
1466	}
1467
1468	return 0;
1469}
1470