1/*
2 * Objective-C runtime 2.0 compatibility for MacOS X 10.4 and earlier.
3 *
4 * This code works by poking into the ObjC runtime, which means loads of
5 * warnings on 10.5+ ;-)
6 */
7
8#define PYOBJC_COMPAT_IMPL
9#include "pyobjc.h"
10
11
12
13
14#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__)
15
16BOOL PyObjC_class_isSubclassOf(Class child, Class parent)
17{
18	if (parent == nil) return YES;
19
20	while (child != nil) {
21		if (child == parent) {
22			return YES;
23		}
24		child = PyObjC_class_getSuperclass(child);
25	}
26	return NO;
27}
28
29#import <mach-o/dyld.h>
30#import <mach-o/getsect.h>
31#import <mach-o/loader.h>
32
33typedef struct _ProtocolTemplate { @defs(Protocol) } ProtocolTemplate;
34
35
36
37struct objc10_object {
38	Class	isa;
39};
40
41struct PyObjC_ivar {
42	char* name;
43	size_t size;
44	uint8_t alignment;
45	char* types;
46};
47
48
49static Protocol** compat_objc_copyProtocolList(unsigned int* outCount)
50{
51	Protocol** protocols = NULL;
52	*outCount = 0;
53
54	uint32_t image_count, image_index;
55	image_count = _dyld_image_count();
56	for (image_index = 0; image_index < image_count; image_index++) {
57		uint32_t size = 0;
58		const struct mach_header *mh = _dyld_get_image_header(image_index);
59		intptr_t slide = _dyld_get_image_vmaddr_slide(image_index);
60		ProtocolTemplate *protos = (ProtocolTemplate*)(
61			((char *)getsectdatafromheader(mh, SEG_OBJC, "__protocol", &size)) +
62			slide);
63		uint32_t nprotos = size / sizeof(ProtocolTemplate);
64		uint32_t i;
65
66		if (nprotos == 0) continue;
67
68		if (protocols == NULL) {
69			protocols = malloc(sizeof(Protocol*) * nprotos);
70			if (protocols == NULL) {
71				return NULL;
72			}
73		} else {
74			Protocol** tmp = realloc(protocols,
75				sizeof(Protocol*) * (*outCount+nprotos));
76			if (tmp == NULL) {
77				free(protocols);
78				return NULL;
79			}
80			protocols = tmp;
81		}
82
83		for (i = 0; i < nprotos; i++) {
84			protocols[(*outCount)++] = (Protocol*)&protos[i];
85		}
86	}
87	return protocols;
88}
89
90static void
91compat_objc_registerClassPair(Class cls)
92{
93	struct objc_method_list* list;
94
95	/* Add the list in the official way, just in case class_addMethods
96	 * does something special.
97	 */
98	list = cls->methodLists[0];
99	cls->methodLists[0] = (struct objc_method_list*)-1;
100	class_addMethods(cls, list);
101
102	list = cls->isa->methodLists[0];
103	cls->isa->methodLists[0] = (struct objc_method_list*)-1;
104	class_addMethods(cls->isa, list);
105
106	objc_addClass(cls);
107}
108
109static Class
110compat_objc_allocateClassPair(Class super_class, const char* name, size_t extra)
111{
112	struct objc_class* result;
113	Class root_class;
114
115	if (objc_getClass(name)) {
116		return Nil;
117	}
118
119	root_class = super_class;
120	while (root_class->super_class) {
121		root_class = root_class->super_class;
122	}
123
124	result = malloc(sizeof(struct objc_class) * 2 + extra);
125	if (result == NULL) {
126		return Nil;
127	}
128	memset(result, 0, sizeof(struct objc_class) * 2 + extra);
129
130	result->super_class = super_class;
131	result->isa = result + 1;
132
133	result[0].methodLists = NULL;
134	result[1].methodLists = NULL;
135
136	result[0].info = CLS_CLASS;
137	result[1].info = CLS_META;
138
139	result[0].name = strdup(name);
140	if (result[0].name == NULL) goto error_cleanup;
141
142	result[1].name = result[0].name;
143	result[0].methodLists = malloc(sizeof(struct objc_method_list*));
144	if (result[0].methodLists == NULL) goto error_cleanup;
145	memset(result[0].methodLists, 0, sizeof(struct objc_method_list*));
146
147	result[1].methodLists = malloc(sizeof(struct objc_method_list*));
148	if (result[1].methodLists == NULL) goto error_cleanup;
149	memset(result[1].methodLists, 0, sizeof(struct objc_method_list*));
150
151	/*
152	 * This is MacOS X specific, and an undocumented feature (long live
153	 * Open Source!).
154	 *
155	 * The code in the objc runtime assumes that the method lists are
156	 * terminated by '-1', and will happily overwite existing data if
157	 * they aren't.
158	 *
159	 * Ronald filed a bugreport for this: Radar #3317376
160	 */
161	result[0].methodLists[0] = (struct objc_method_list*)-1;
162	result[1].methodLists[0] = (struct objc_method_list*)-1;
163
164	result[0].methodLists[0] = malloc(sizeof(struct objc_method_list));
165	if (result[0].methodLists[0] == NULL) goto error_cleanup;
166	result[0].methodLists[0]->method_count = 0;
167	result[0].methodLists[0]->obsolete = NULL;
168
169	result[1].methodLists[0] = malloc(sizeof(struct objc_method_list));
170	if (result[1].methodLists[0] == NULL) goto error_cleanup;
171	result[1].methodLists[0]->method_count = 0;
172	result[1].methodLists[0]->obsolete = NULL;
173
174
175	result[0].super_class = super_class;
176	result[1].super_class = ((struct objc10_object*)super_class)->isa;
177	result[1].isa = ((struct objc10_object*)root_class)->isa;
178
179	result[0].instance_size = super_class->instance_size;
180	result[1].instance_size = result[1].super_class->instance_size;
181
182	/* Initialize to NULL, otherwise poseAs: won't work */
183	result[0].ivars = result[1].ivars = NULL;
184
185	result[0].protocols = result[1].protocols = NULL;
186
187	return result;
188
189
190error_cleanup:
191	if (result) {
192		if (result[0].methodLists) {
193			if (result[0].methodLists[0] != 0 &&
194					result[0].methodLists[0] != 0)  {
195				free(result[0].methodLists[0]);
196			}
197			free(result[0].methodLists);
198		}
199		if (result[1].methodLists) {
200			if (result[1].methodLists[1] != 0 &&
201					result[1].methodLists[0] != 0)  {
202				free(result[1].methodLists[0]);
203			}
204			free(result[1].methodLists);
205		}
206
207		if (result[0].ivars) {
208			free(result[0].ivars);
209		}
210		if (result[1].ivars) {
211			free(result[1].ivars);
212		}
213
214		if (result[0].name) {
215			free((char*)result[0].name);
216		}
217		free(result);
218	}
219	return Nil;
220
221}
222
223static void
224compat_objc_disposeClassPair(Class cls)
225{
226	struct objc_class* val = cls;
227	int i;
228
229	for (i = 0; i < 2; i++) {
230		if (val[i].methodLists) {
231			struct objc_method_list** cur;
232
233			cur = val[i].methodLists;
234			if (*cur != (struct objc_method_list*)-1) {
235				free(*cur);
236				*cur = NULL;
237			}
238			free(val[i].methodLists);
239			val[i].methodLists = NULL;
240		}
241	}
242
243	free((char*)val[0].name);
244	val[0].name = val[1].name = NULL;
245	free(val);
246}
247
248
249static size_t
250compat_methodlist_magic(Class cls)
251{
252	void* iterator = NULL;
253	struct objc_method_list* mlist;
254	size_t res = 0, cnt = 0;
255
256        if (cls == NULL) return -1;
257
258	while ( (mlist = class_nextMethodList(cls, &iterator )) != NULL ) {
259		res += mlist->method_count;
260		cnt++;
261	}
262
263	return (cnt << 16) | (res & 0xFFFF);
264}
265
266#ifndef NO_OBJC2_RUNTIME
267static size_t
268objc20_methodlist_magic(Class cls)
269{
270	Method* methods;
271	unsigned int count;
272	unsigned int i;
273	size_t result;
274
275	methods = class_copyMethodList(cls, &count);
276	result = 0;
277	for (i = 0; i < count; i++) {
278		result = (1000003*result) ^ ((size_t)(
279				method_getImplementation(methods[i])) >> 3);
280	}
281	result = result | (count << 16);
282	free(methods);
283	return result;
284}
285#endif
286
287static Class
288compat_object_setClass(id obj, Class cls)
289{
290	Class prev;
291	if (obj == nil) {
292		return Nil;
293	}
294	prev = ((struct objc10_object*)obj)->isa;
295	((struct objc10_object*)obj)->isa = cls;
296	return prev;
297}
298
299
300
301static Class
302compat_object_getClass(id obj)
303{
304	return ((struct objc10_object*)obj)->isa;
305}
306
307static const char*
308compat_object_getClassName(id obj)
309{
310	return ((struct objc10_object*)obj)->isa->name;
311}
312
313
314
315static Method*
316compat_class_copyMethodList(Class cls, unsigned int* outCount)
317{
318	struct objc_method_list* mlist;
319	void* iterator;
320	unsigned int count;
321	Method* result;
322	Method* tmp;
323
324	iterator = NULL;
325	count = 0;
326
327	mlist = class_nextMethodList(cls, &iterator);
328	result = NULL;
329	while (mlist != NULL) {
330		int i;
331
332		tmp = realloc(result, (count + mlist->method_count) * sizeof(Method));
333		if (tmp == NULL) {
334			free(result);
335			return NULL;
336		} else {
337			result = tmp;
338		}
339
340		for (i = 0; i < mlist->method_count; i++) {
341			result[count] = mlist->method_list + i;
342			if (result[count] == NULL) continue;
343			count++;
344		}
345		mlist = class_nextMethodList(cls, &iterator);
346	}
347
348	if (outCount != NULL) {
349		*outCount = count;
350	}
351	return result;
352}
353
354static Ivar*
355compat_class_copyIvarList(Class cls, unsigned int* outCount)
356{
357	Ivar* list;
358	int   i;
359	struct objc_ivar_list* ivars = cls->ivars;
360
361	if (ivars) {
362		list = malloc(sizeof(Ivar) * ivars->ivar_count);
363		if (list == NULL) {
364			return NULL;
365		}
366
367
368		for (i = 0; i < ivars->ivar_count; i++) {
369			list[i] = ivars->ivar_list + i;
370		}
371		*outCount = ivars->ivar_count;
372		return list;
373
374	} else {
375		list = malloc(1);
376		if (list == NULL) {
377			return NULL;
378		}
379
380		*outCount = 0;
381		return list;
382	}
383
384}
385
386static Protocol**
387compat_class_copyProtocolList(Class cls, unsigned int* outCount)
388{
389	Protocol** list;
390	unsigned int count = 0;
391	struct objc_protocol_list *protocol_list;
392
393	protocol_list = cls->protocols;
394	list = malloc(0);
395
396	while (protocol_list != NULL) {
397		list = realloc(list, (count + protocol_list->count)*sizeof(Protocol*));
398		if (list == NULL) {
399			/* Whoops, memory leak */
400			*outCount = 0;
401			return NULL;
402		}
403		memcpy(list + count, protocol_list->list, protocol_list->count*sizeof(Protocol*));
404		count += protocol_list->count;
405		protocol_list = protocol_list->next;
406	}
407
408	*outCount = count;
409	return list;
410}
411
412
413static const char*
414compat_class_getName(Class cls)
415{
416	return cls->name;
417}
418
419static Class
420compat_class_getSuperclass(Class cls)
421{
422	return cls->super_class;
423}
424
425static BOOL
426compat_class_addMethod(Class cls, SEL name, IMP imp, const char* types)
427{
428	struct objc_method_list* methodsToAdd;
429	struct objc_method* objcMethod;
430
431	methodsToAdd = malloc(sizeof(struct objc_method_list) +
432			2*sizeof(struct objc_method));
433	methodsToAdd->method_count = 1;
434	methodsToAdd->obsolete = NULL;
435
436	objcMethod = methodsToAdd->method_list;
437	objcMethod->method_name = name;
438	objcMethod->method_imp = imp;
439	objcMethod->method_types = (char*)types;
440
441	class_addMethods(cls, methodsToAdd);
442	return YES; /* Have to return something ... */
443}
444
445static BOOL
446compat_preclass_addMethod(Class cls, SEL name, IMP imp, const char* types)
447{
448	/* Resize in-place, this is only valid during class construction. */
449	struct objc_method_list* new_list;
450	struct objc_method* objcMethod;
451
452	new_list = realloc(cls->methodLists[0],
453			sizeof(struct objc_method_list) +
454			(sizeof(struct objc_method
455				)*(cls->methodLists[0]->method_count+1)));
456	if (new_list == NULL) {
457		return NO;
458	}
459	cls->methodLists[0] = new_list;
460	objcMethod = new_list->method_list + (new_list->method_count)++;
461
462	objcMethod->method_name = name;
463	objcMethod->method_imp = imp;
464	objcMethod->method_types = strdup(types);
465	if (objcMethod == NULL) {
466		new_list->method_count--;
467		return NO;
468	}
469
470	return YES;
471}
472
473static BOOL
474compat_preclass_addIvar(
475		Class cls,
476		const char* name,
477		size_t size,
478		uint8_t align, const char* types)
479{
480	/* Update the class structure, only valid during class construction */
481	struct objc_ivar_list* new_ivars;
482	struct objc_ivar* ivar;
483
484	if (cls->ivars) {
485		new_ivars = realloc(cls->ivars,
486			sizeof(struct objc_ivar_list) +
487			((cls->ivars->ivar_count+1) * sizeof(struct objc_ivar)));
488	} else {
489		new_ivars = malloc(
490				sizeof(struct objc_ivar_list) +
491				sizeof(struct objc_ivar));
492		new_ivars->ivar_count = 0;
493	}
494	if (new_ivars == NULL) {
495		return NO;
496	}
497	cls->ivars = new_ivars;
498	ivar = new_ivars->ivar_list + new_ivars->ivar_count;
499	ivar->ivar_name = strdup(name);
500	if (ivar->ivar_name == NULL) {
501		return NO;
502	}
503
504	ivar->ivar_type = strdup(types);
505	if (ivar->ivar_type == NULL) {
506		free(ivar->ivar_name);
507		return NO;
508	}
509
510	ivar->ivar_offset = cls->instance_size;
511	if (ivar->ivar_offset % align) {
512		ivar->ivar_offset += align - (ivar->ivar_offset % align);
513	}
514
515	new_ivars->ivar_count ++;
516	cls->instance_size = ivar->ivar_offset + size;
517	return YES;
518}
519
520static BOOL
521compat_preclass_addProtocol(Class cls, Protocol* protocol)
522{
523	struct objc_protocol_list* protocols;
524
525	if (cls->protocols) {
526		protocols = realloc(cls->protocols,
527			sizeof(struct objc_protocol_list) +
528			  (sizeof(Protocol*)*(cls->protocols->count+1)));
529	} else {
530		protocols = malloc(sizeof(struct objc_protocol_list)
531				+ sizeof(Protocol*));
532		protocols->count = 0;
533		protocols->next = NULL;
534	}
535	if (protocols == NULL) {
536		return NO;
537	}
538	cls->protocols = protocols;
539	protocols->list[protocols->count] = protocol;
540	protocols->count++;
541	return YES;
542}
543
544static SEL
545compat_method_getName(Method m)
546{
547	return m->method_name;
548}
549
550static IMP
551compat_method_getImplementation(Method m)
552{
553	return m->method_imp;
554}
555
556static IMP
557compat_method_setImplementation(Method m, IMP imp)
558{
559	IMP result =  m->method_imp;
560	m->method_imp = imp;
561	return result;
562}
563
564static const char *
565compat_method_getTypeEncoding(Method m)
566{
567	return m->method_types;
568}
569
570static BOOL
571compat_sel_isEqual(SEL lhs, SEL rhs)
572{
573	return lhs == rhs;
574}
575
576static const char*
577compat_ivar_getName(Ivar var)
578{
579	return var->ivar_name;
580}
581
582static const char*
583compat_ivar_getTypeEncoding(Ivar var)
584{
585	return var->ivar_type;
586}
587
588static ptrdiff_t
589compat_ivar_getOffset(Ivar var)
590{
591	return var->ivar_offset;
592}
593
594
595#ifndef NO_OBJC2_RUNTIME
596static BOOL
597objc20_class_addMethodList(Class cls,
598		struct PyObjC_method* list, unsigned int count)
599{
600	unsigned int i;
601	BOOL r;
602	Method m;
603
604	for (i = 0; i < count; i++) {
605		r = class_addMethod(cls,
606			list[i].name, list[i].imp, list[i].type);
607		if (!r) {
608			m = class_getInstanceMethod(cls, list[i].name);
609			if (m != NULL) {
610				method_setImplementation(m, list[i].imp);
611			} else {
612				return NO;
613			}
614		}
615	}
616	return YES;
617}
618#endif
619
620static BOOL
621compat_class_isMetaClass(Class cls)
622{
623	return CLS_GETINFO(cls, CLS_META) == CLS_META;
624}
625
626static BOOL
627compat_class_addMethodList(Class cls,
628		struct PyObjC_method* list, unsigned int count)
629{
630	unsigned int i;
631	struct objc_method_list* method_list;
632
633	method_list = malloc(
634			sizeof(struct objc_method_list) +
635			((count+1) * sizeof(struct objc_method)));
636	if (method_list == NULL) {
637		return NO;
638	}
639	memset(method_list, 0,
640			sizeof(struct objc_method_list) +
641			((count+1) * sizeof(struct objc_method)));
642
643	method_list->method_count = 0;
644	method_list->obsolete = 0;
645
646	for (i = 0; i < count; i++) {
647		method_list->method_list[i].method_name = list[i].name;
648		method_list->method_list[i].method_types = (char*)list[i].type;
649		method_list->method_list[i].method_imp = list[i].imp;
650	}
651	method_list->method_count = count;
652	class_addMethods(cls, method_list);
653	return YES;
654}
655
656static BOOL
657compat_protocol_conformsToProtocol(Protocol *proto, Protocol *other)
658{
659	return [proto conformsTo:other];
660}
661
662static const char *
663compat_protocol_getName(Protocol *p)
664{
665	return [p name];
666}
667
668static struct objc_method_description *
669compat_protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount)
670{
671	if (!isRequiredMethod) {
672		*outCount = 0;
673		return NULL;
674	}
675
676	struct objc_method_description_list* list;
677
678	if (isInstanceMethod) {
679		list = ((ProtocolTemplate*)p)->instance_methods;
680	} else {
681		list = ((ProtocolTemplate*)p)->class_methods;
682	}
683
684	if (list == NULL || list->count == 0) {
685		*outCount = 0;
686		return NULL;
687	}
688
689	*outCount = list->count;
690	struct objc_method_description* result;
691
692	result = malloc(sizeof(struct objc_method_description) * list->count);
693	if (result == NULL) {
694		return NULL;
695	}
696
697	int i;
698	*outCount = 0;
699	for (i = 0; i < list->count; i++) {
700		if (list->list[i].name == NULL) continue;
701		result[*outCount].name = list->list[i].name;
702		result[*outCount].types = list->list[i].types;
703		(*outCount)++;
704	}
705
706	return result;
707}
708
709static Protocol **
710compat_protocol_copyProtocolList(Protocol *proto, unsigned int *outCount)
711{
712	struct objc_protocol_list* list =
713		((ProtocolTemplate*)proto)->protocol_list;
714
715	*outCount = 0;
716
717	struct objc_protocol_list* cur;
718	for (cur = list; cur != NULL; cur = cur->next) {
719		*outCount += cur->count;
720	}
721
722	Protocol** result = (Protocol**)malloc(sizeof(Protocol*) * *outCount);
723	if (result == NULL) {
724		return NULL;
725	}
726
727	unsigned curIdx = 0;
728	for (cur = list; cur != NULL; cur = cur->next) {
729		int i;
730		for (i = 0; i < cur->count; i++) {
731			if (cur->list[i] != NULL) {
732				result[curIdx++] = cur->list[i];
733			} else {
734				*outCount--;
735			}
736		}
737	}
738	return result;
739}
740
741static struct objc_method_description
742compat_protocol_getMethodDescription(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod)
743{
744static struct objc_method_description empty_description =  { NULL, NULL };
745	if (!isRequiredMethod) {
746		return empty_description;
747	}
748
749	struct objc_method_description* result;
750
751	if (isInstanceMethod) {
752		result = [p descriptionForInstanceMethod: aSel];
753	} else {
754		result = [p descriptionForClassMethod: aSel];
755	}
756
757	if (result == NULL) {
758		return empty_description;
759	} else {
760		return *result;
761	}
762}
763
764static id
765compat_object_getIvar(id obj, Ivar ivar)
766{
767	return *(id*)(((char*)obj) + ivar->ivar_offset);
768}
769static void
770compat_object_setIvar(id obj, Ivar ivar, id value)
771{
772	*(id*)(((char*)obj) + ivar->ivar_offset) = value;
773}
774
775/* Dispatch table */
776BOOL (*PyObjC_protocol_conformsToProtocol)(Protocol *proto, Protocol *other) = NULL;
777const char *(*PyObjC_protocol_getName)(Protocol *p) = NULL;
778struct objc_method_description *(*PyObjC_protocol_copyMethodDescriptionList)(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) = NULL;
779Protocol **(*PyObjC_protocol_copyProtocolList)(Protocol *proto, unsigned int *outCount) = NULL;
780struct objc_method_description (*PyObjC_protocol_getMethodDescription)(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) = NULL;
781
782id (*PyObjC_object_getIvar)(id obj, Ivar ivar) = NULL;
783void (*PyObjC_object_setIvar)(id obj, Ivar ivar, id value) = NULL;
784
785
786
787Class (*PyObjC_objc_allocateClassPair)(Class, const char*, size_t) = NULL;
788void (*PyObjC_objc_registerClassPair)(Class) = NULL;
789void (*PyObjC_objc_disposeClassPair)(Class) = NULL;
790Protocol** (*PyObjC_objc_copyProtocolList)(unsigned int*) = NULL;
791
792BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*) = NULL;
793BOOL (*PyObjC_preclass_addIvar)(Class cls,
794	const char *name, size_t size, uint8_t alignment,
795	const char *types) = NULL;
796BOOL (*PyObjC_preclass_addProtocol)(Class cls, Protocol *protocol) = NULL;
797
798
799Class   (*PyObjC_object_getClass)(id obj) = NULL;
800Class (*PyObjC_object_setClass)(id obj, Class cls) = NULL;
801const char* (*PyObjC_object_getClassName)(id obj) = NULL;
802
803Method* (*PyObjC_class_copyMethodList)(Class, unsigned int*) = NULL;
804const char*  (*PyObjC_class_getName)(Class) = NULL;
805Class (*PyObjC_class_getSuperclass)(Class) = NULL;
806BOOL (*PyObjC_class_addMethod)(Class, SEL, IMP, const char*) = NULL;
807BOOL (*PyObjC_class_addMethodList)(Class,
808		struct PyObjC_method*, unsigned int) = NULL;
809Ivar* (*PyObjC_class_copyIvarList)(Class, unsigned int*) = NULL;
810Protocol** (*PyObjC_class_copyProtocolList)(Class, unsigned int*) = NULL;
811BOOL (*PyObjC_class_isMetaClass)(Class) = NULL;
812
813SEL (*PyObjC_method_getName)(Method m) = NULL;
814IMP (*PyObjC_method_getImplementation)(Method m) = NULL;
815IMP (*PyObjC_method_setImplementation)(Method m, IMP imp) = NULL;
816const char *(*PyObjC_method_getTypeEncoding)(Method m) = NULL;
817
818BOOL (*PyObjC_sel_isEqual)(SEL, SEL) = NULL;
819
820size_t (*PyObjC_methodlist_magic)(Class cls);
821
822const char*  (*PyObjC_ivar_getName)(Ivar) = NULL;
823const char*  (*PyObjC_ivar_getTypeEncoding)(Ivar) = NULL;
824ptrdiff_t    (*PyObjC_ivar_getOffset)(Ivar) = NULL;
825
826
827
828void PyObjC_SetupRuntimeCompat(void)
829{
830#ifdef NO_OBJC2_RUNTIME
831	/*
832	 * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always
833	 * use the compat implementation.
834	 */
835	PyObjC_class_addMethodList  = compat_class_addMethodList;
836	PyObjC_methodlist_magic     = compat_methodlist_magic;
837	PyObjC_objc_disposeClassPair   = compat_objc_disposeClassPair;
838	PyObjC_preclass_addMethod   = compat_preclass_addMethod;
839	PyObjC_preclass_addIvar     = compat_preclass_addIvar;
840	PyObjC_preclass_addProtocol = compat_preclass_addProtocol;
841
842#   define SETUP(funcname) \
843		PyObjC_##funcname = compat_##funcname
844
845#else
846	if (class_addMethod) {
847		PyObjC_class_addMethodList = objc20_class_addMethodList;
848		PyObjC_preclass_addMethod  = class_addMethod;
849		PyObjC_preclass_addIvar    = class_addIvar;
850		PyObjC_preclass_addProtocol= class_addProtocol;
851	} else {
852		PyObjC_class_addMethodList = compat_class_addMethodList;
853		PyObjC_preclass_addMethod  = compat_preclass_addMethod;
854		PyObjC_preclass_addIvar    = compat_preclass_addIvar;
855		PyObjC_preclass_addProtocol= compat_preclass_addProtocol;
856	}
857
858
859	if (class_copyMethodList) {
860		PyObjC_methodlist_magic = objc20_methodlist_magic;
861	} else {
862		PyObjC_methodlist_magic = compat_methodlist_magic;
863	}
864
865#   define SETUP(funcname) \
866	if ((funcname) == NULL) { \
867		PyObjC_##funcname = compat_##funcname; \
868	} else { \
869		PyObjC_##funcname = funcname; \
870	}
871#endif
872	SETUP(protocol_getName);
873	SETUP(protocol_conformsToProtocol);
874	SETUP(protocol_copyMethodDescriptionList);
875	SETUP(protocol_copyProtocolList);
876	SETUP(protocol_getMethodDescription);
877
878	SETUP(objc_allocateClassPair);
879	SETUP(objc_registerClassPair);
880	SETUP(objc_disposeClassPair);
881	SETUP(objc_copyProtocolList);
882
883	SETUP(object_getClass);
884	SETUP(object_setClass);
885	SETUP(object_getClassName);
886	SETUP(object_getIvar);
887	SETUP(object_setIvar);
888
889	SETUP(class_getSuperclass);
890	SETUP(class_addMethod);
891	SETUP(class_copyIvarList);
892	SETUP(class_copyProtocolList);
893	SETUP(class_copyMethodList);
894	SETUP(class_getName);
895	SETUP(class_isMetaClass);
896
897	SETUP(method_getName);
898	SETUP(method_getTypeEncoding);
899	SETUP(method_getImplementation);
900	SETUP(method_setImplementation);
901
902	SETUP(sel_isEqual);
903
904	SETUP(ivar_getName);
905	SETUP(ivar_getTypeEncoding);
906	SETUP(ivar_getOffset);
907#undef SETUP
908
909}
910
911#else
912
913
914BOOL PyObjC_class_isSubclassOf(Class child, Class parent)
915{
916	if (parent == nil) return YES;
917
918	while (child != nil) {
919		if (child == parent) {
920			return YES;
921		}
922		child = class_getSuperclass(child);
923	}
924	return NO;
925}
926
927BOOL PyObjC_class_addMethodList(Class cls,
928		struct PyObjC_method* list, unsigned int count)
929{
930	unsigned int i;
931	BOOL r;
932	Method m;
933
934	for (i = 0; i < count; i++) {
935		/*
936		 * XXX: First try class_addMethod, if that fails assume this is
937		 * because the method already exists in the class.
938		 * Strictly speaking this isn't correct, but this is the best
939		 * we can do through the 2.0 API (see 4809039 in RADAR)
940		 */
941		r = class_addMethod(cls,
942			list[i].name, list[i].imp, list[i].type);
943		if (!r) {
944			m = class_getInstanceMethod(cls, list[i].name);
945			if (m != NULL) {
946				method_setImplementation(m, list[i].imp);
947			} else {
948				return NO;
949			}
950		}
951	}
952	return YES;
953}
954
955size_t PyObjC_methodlist_magic(Class cls)
956{
957	/* This is likely to be much slower than compat_methodlist_magic,
958	 * but should works on the 64-bit runtime. Hopefully a callback will
959	 * be added to the 2.0 runtime that will take away the need for this
960	 * function...
961	 */
962	Method* methods;
963	unsigned int count;
964
965	methods = class_copyMethodList(cls, &count);
966#if 0
967	unsigned int i;
968	size_t result;
969	result = 0;
970	for (i = 0; i < count; i++) {
971		result = (1000003*result) ^ ((size_t)(
972				method_getImplementation(methods[i])) >> 3);
973	}
974	result = result | (count << 16);
975	free(methods);
976	return result;
977#endif
978	free(methods);
979	return (size_t)count;
980}
981
982#endif
983
984#if __OBJC2__
985
986@implementation Protocol (NSOBjectCompat)
987- self
988{
989	return self;
990}
991@end
992
993@implementation Object (NSOBjectCompat)
994- self
995{
996	return self;
997}
998
999-doesNotRecognizeSelector:(SEL)sel
1000{
1001	printf("--> %s\n", sel_getName(sel));
1002	abort();
1003}
1004@end
1005
1006
1007#endif
1008