summaryrefslogtreecommitdiff
path: root/Objective-C
diff options
context:
space:
mode:
Diffstat (limited to 'Objective-C')
-rw-r--r--Objective-C/GNUmakefile5
-rw-r--r--Objective-C/libobjcl.h18
-rw-r--r--Objective-C/libobjcl.m42
-rw-r--r--Objective-C/objc-runtime-apple.h132
-rw-r--r--Objective-C/objc-runtime-apple.m158
-rw-r--r--Objective-C/objc-runtime-gnu.h174
-rw-r--r--Objective-C/objc-runtime-gnu.m216
-rw-r--r--Objective-C/objc_support.h93
-rw-r--r--Objective-C/objc_support.m521
9 files changed, 1357 insertions, 2 deletions
diff --git a/Objective-C/GNUmakefile b/Objective-C/GNUmakefile
index 231a78b..7cae671 100644
--- a/Objective-C/GNUmakefile
+++ b/Objective-C/GNUmakefile
@@ -6,7 +6,8 @@ LIBRARY_NAME = libobjcl
RPM_DISABLE_RELOCATABLE = YES
ADDITIONAL_OBJCFLAGS = -Wall -g -DVERSION=\"$(VERSION)\"
-libobjcl_OBJC_FILES = libobjcl.m
-LIBRARIES_DEPEND_UPON = $(FND_LIBS) $(GUI_LIBS) $(OBJC_LIBS) $(SYSTEM_LIBS) $(CONFIG_SYSTEM_LIBS)
+#ADDITIONAL_LDFLAGS = -lavcall
+libobjcl_OBJC_FILES = libobjcl.m objc_support.m objc-runtime-apple.m objc-runtime-gnu.m
+LIBRARIES_DEPEND_UPON = $(FND_LIBS) $(GUI_LIBS) $(OBJC_LIBS) $(SYSTEM_LIBS) $(CONFIG_SYSTEM_LIBS)
include $(GNUSTEP_MAKEFILES)/library.make
diff --git a/Objective-C/libobjcl.h b/Objective-C/libobjcl.h
index cb47440..5ca49f4 100644
--- a/Objective-C/libobjcl.h
+++ b/Objective-C/libobjcl.h
@@ -3,6 +3,14 @@
#import "Foundation/Foundation.h"
#include <objc/objc-api.h>
+#ifdef USE_LIBFFI
+#include <ffi.h>
+#else
+#include <vacall.h>
+#include <avcall.h>
+#endif
+
+
typedef struct objcl_object
{
char* type;
@@ -42,6 +50,16 @@ objcl_invoke_method (OBJCL_OBJ_DATA receiver,
int argc,
...);
+void
+objcl_invoke_with_types (void *receiver,
+ SEL method_selector,
+ char *(types[]),
+ size_t arg_sizes[],
+ id *exception,
+ void *return_value,
+ int argc,
+ ...);
+
OBJCL_OBJ_DATA
objcl_find_class (const char *class_name);
diff --git a/Objective-C/libobjcl.m b/Objective-C/libobjcl.m
index 833a4fb..aff3c4c 100644
--- a/Objective-C/libobjcl.m
+++ b/Objective-C/libobjcl.m
@@ -199,6 +199,8 @@ _objcl_invoke_method (id self_,
[invocation getReturnValue: result_ptr];
if (result->type[0] == '#')
NSLog (@"Returning: %@", result->data.id_val);
+ else
+ NSLog (@"Returning.");
}
@@ -255,6 +257,46 @@ objcl_invoke_method (OBJCL_OBJ_DATA receiver,
}
+void
+objcl_invoke_with_types (void *receiver,
+ SEL method_selector,
+ char *(types[]),
+ size_t arg_sizes[],
+ id *exception,
+ void *return_value,
+ int argc,
+ ...)
+{
+ va_list arglist;
+ IMP method;
+ int i;
+
+ *exception = NULL;
+
+#ifdef __NEXT_RUNTIME__
+ method = class_getInstanceMethod ([obj class], method_selector)->method_imp;
+#else
+ method = objc_msg_lookup (receiver, method_selector);
+#endif
+
+ NS_DURING
+ {
+ va_start (arglist, argc);
+ for (i = 0; i < argc; i++)
+ {
+ va_arg (arglist, OBJCL_OBJ_DATA);
+ }
+ va_end (arglist);
+ }
+ NS_HANDLER
+ {
+ *exception = localException;
+ NS_VOIDRETURN;
+ }
+ NS_ENDHANDLER
+}
+
+
OBJCL_OBJ_DATA
objcl_find_class (const char *class_name)
{
diff --git a/Objective-C/objc-runtime-apple.h b/Objective-C/objc-runtime-apple.h
new file mode 100644
index 0000000..fb15b27
--- /dev/null
+++ b/Objective-C/objc-runtime-apple.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved
+ * Copyright (c) 2003 Ronald Oussoren
+ *
+ * This software may be used and distributed freely for any purpose
+ * provided that this notice is included unchanged on any and all
+ * copies. The author does not warrant or guarantee this software in
+ * any way.
+ *
+ * This file is part of the PyObjC package.
+ *
+ * RCSfile: objc_support.h,v
+ * Revision: 1.16
+ * Date: 1998/08/18 15:35:57
+ *
+ * Created Tue Sep 10 14:11:38 1996.
+ */
+
+#ifndef PyObjC_RUNTIME_APPLE_H
+#define PyObjC_RUNTIME_APPLE_H
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSString.h>
+
+#include <objc/objc-runtime.h>
+#include <objc/Protocol.h>
+
+static inline int
+PyObjCRT_SameSEL(SEL a, SEL b)
+{
+ return a == b;
+}
+
+static inline const char*
+PyObjCRT_SELName(SEL sel)
+{
+ return sel_getName(sel);
+}
+
+static inline SEL
+PyObjCRT_SELUID(const char* str)
+{
+ return sel_getUid(str);
+}
+
+static inline Class
+PyObjCRT_LookUpClass(const char* name)
+{
+ return objc_lookUpClass(name);
+}
+
+static inline struct objc_method_list *
+PyObjCRT_NextMethodList(Class c, void ** p)
+{
+ return class_nextMethodList(c, p);
+}
+
+static inline void
+PyObjCRT_InitMethod(Method m, SEL name, const char* types, IMP imp)
+{
+ memset(m, 0, sizeof(*m));
+ m->method_name = name;
+ m->method_types = strdup((char*)types);
+ m->method_imp = imp;
+}
+
+static inline void
+PyObjCRT_ClassAddMethodList(Class cls, struct objc_method_list* lst)
+{
+ class_addMethods(cls, lst);
+}
+
+
+extern struct objc_method_list* PyObjCRT_AllocMethodList(Py_ssize_t);
+extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(Py_ssize_t);
+
+typedef Method PyObjCRT_Method_t;
+typedef Ivar PyObjCRT_Ivar_t;
+
+#define GETISA(c) ((c)->isa)
+
+#define RECEIVER(c) ((c).receiver)
+
+#define _C_CONST 'r'
+#define _C_IN 'n'
+#define _C_INOUT 'N'
+#define _C_OUT 'o'
+#define _C_BYCOPY 'O'
+#define _C_ONEWAY 'V'
+#define _C_LNGLNG 'q'
+#define _C_ULNGLNG 'Q'
+#define _C_BOOL 'B' /* (Objective-)C++ 'bool' */
+
+
+/* Return a number that is likely to change when the method list changes,
+ * and is cheap to compute.
+ */
+static inline int
+objc_methodlist_magic(Class cls)
+{
+ int res = 0;
+ int cnt = 0;
+
+ /* This is the documented way of enumerating the method list. It
+ * is slower than the obvious way, but does not explode under
+ * esoteric situations.
+ */
+ void *iterator = NULL;
+ struct objc_method_list *mlist;
+
+ if (cls == NULL) return -1;
+
+ while ( (mlist = class_nextMethodList( cls, &iterator )) != NULL ) {
+ res += mlist->method_count;
+ cnt++;
+ }
+
+ return (cnt << 16) | (res & 0xFFFF);
+}
+
+static inline const char *
+get_selector_encoding (id self, SEL sel)
+{
+ struct objc_method* m = class_getInstanceMethod(self->isa, sel);
+
+ if (!m) {
+ return NULL;
+ } else {
+ return m->method_types;
+ }
+}
+
+#endif /* PyObjC_RUNTIME_APPLE_H */
diff --git a/Objective-C/objc-runtime-apple.m b/Objective-C/objc-runtime-apple.m
new file mode 100644
index 0000000..a20713b
--- /dev/null
+++ b/Objective-C/objc-runtime-apple.m
@@ -0,0 +1,158 @@
+/* This file is part of the PyObjC package. */
+/*
+ * Support code for the Apple runtime
+ */
+#include "pyobjc.h"
+
+#if defined(APPLE_RUNTIME)
+
+int PyObjCRT_SetupClass(
+ Class cls,
+ Class metaCls,
+ const char*name,
+ Class superCls,
+ Class rootCls,
+ Py_ssize_t ivarSize,
+ struct objc_ivar_list* ivarList,
+ struct objc_protocol_list* protocolList
+)
+
+{
+ /* Initialize the structure */
+ memset(cls, 0, sizeof(*cls));
+ memset(metaCls, 0, sizeof(*cls));
+
+ cls->methodLists = NULL;
+ metaCls->methodLists = NULL;
+ cls->isa = metaCls;
+
+ cls->info = CLS_CLASS; // |CLS_METHOD_ARRAY;
+ metaCls->info = CLS_META; // |CLS_METHOD_ARRAY;
+
+ cls->name = strdup(name);
+ if (cls->name == NULL) {
+ return -1;
+ }
+ metaCls->name = strdup(name);
+ if (metaCls->name == NULL) {
+ free((char*)(cls->name));
+ cls->name = NULL;
+ return -1;
+ }
+
+ cls->methodLists = malloc(sizeof(struct objc_method_list*));
+ if (cls->methodLists == NULL) {
+ PyErr_NoMemory();
+ free((char*)(cls->name));
+ cls->name = NULL;
+ free((char*)(metaCls->name));
+ metaCls->name = NULL;
+ return -1;
+ }
+ memset(cls->methodLists, 0, sizeof(*(cls->methodLists)));
+
+ metaCls->methodLists = malloc(sizeof(struct objc_method_list*));
+ if (cls->methodLists == NULL) {
+ PyErr_NoMemory();
+ free((char*)(cls->name));
+ cls->name = NULL;
+ free((char*)(metaCls->name));
+ metaCls->name = NULL;
+ free(cls->methodLists);
+ cls->methodLists = NULL;
+ return -1;
+ }
+ memset(metaCls->methodLists, 0, sizeof(*(metaCls->methodLists)));
+
+ /*
+ * This is MacOS X specific, and an undocumented feature (long live
+ * Open Source!).
+ *
+ * The code in the objc runtime assumes that the method lists are
+ * terminated by '-1', and will happily overwite existing data if
+ * they aren't.
+ *
+ * Ronald filed a bugreport for this: Radar #3317376
+ */
+ cls->methodLists[0] = (struct objc_method_list*)-1;
+ metaCls->methodLists[0] = (struct objc_method_list*)-1;
+
+ cls->super_class = superCls;
+ metaCls->super_class = superCls->isa;
+ metaCls->isa = rootCls->isa;
+
+ cls->instance_size = ivarSize;
+ cls->ivars = ivarList;
+
+ metaCls->instance_size = metaCls->super_class->instance_size;
+ metaCls->ivars = NULL;
+
+ metaCls->protocols = cls->protocols = protocolList;
+
+ return 0;
+}
+
+void PyObjCRT_ClearClass(Class cls)
+{
+ if (cls->methodLists) {
+ if (cls->methodLists) {
+ struct objc_method_list** cur;
+
+ cur = cls->methodLists;
+ while (*cur != (struct objc_method_list*)-1) {
+ if (*cur != NULL) {
+ free(*cur);
+ *cur = NULL;
+ }
+ cur++;
+ }
+ free(cls->methodLists);
+ cls->methodLists = NULL;
+ }
+ cls->methodLists = NULL;
+ }
+
+ if (cls->name) {
+ free((char*)(cls->name));
+ }
+}
+
+struct objc_method_list *PyObjCRT_AllocMethodList(Py_ssize_t numMethods)
+{
+ struct objc_method_list *mlist;
+
+ mlist = malloc(sizeof(struct objc_method_list)
+ + ((numMethods+1) * sizeof(struct objc_method)));
+
+ if (mlist == NULL) {
+ return NULL;
+ }
+
+ mlist->method_count = 0;
+ mlist->obsolete = NULL;
+
+ return mlist;
+}
+
+struct objc_protocol_list* PyObjCRT_AllocProtocolList(Py_ssize_t numProtocols)
+{
+ struct objc_protocol_list *plist;
+
+ plist = malloc(sizeof(struct objc_protocol_list)
+ + ((numProtocols+1) * sizeof(Protocol *)));
+
+ if (plist == NULL) {
+ return NULL;
+ }
+
+ plist->count = 0;
+ plist->next = NULL;
+
+ return plist;
+}
+
+#else /* !APPLE_RUNTIME */
+
+static int dummy __attribute__((__unused__));
+
+#endif /* !APPLE_RUNTIME */
diff --git a/Objective-C/objc-runtime-gnu.h b/Objective-C/objc-runtime-gnu.h
new file mode 100644
index 0000000..644dfde
--- /dev/null
+++ b/Objective-C/objc-runtime-gnu.h
@@ -0,0 +1,174 @@
+#ifndef PyObjC_RUNTIME_GNU_H
+#define PyObjC_RUNTIME_GNU_H
+
+/*
+ * Specific support for the GNU Objective-C runtime
+ */
+
+#include <Foundation/NSException.h>
+#include <Foundation/NSString.h>
+
+#define objc_msgSendSuper(super, op, args...) \
+ ((super)->self == NULL \
+ ? 0 \
+ : ( \
+ class_get_instance_method( \
+ (super)->class, (op) \
+ )->method_imp)( \
+ (super)->self, \
+ (op) ,##args))
+
+
+/*
+ * XXX: AFAIK as I (Ronald) know, there should be an include named
+ * <objc/runtime.h> on systems with the GNU runtime. However, this file
+ * not present on my Linux playmachine (running Debian testing)...
+ *
+ * The alternative is to declare some prototypes ourselves...
+ */
+#if 0
+# include <objc/runtime.h>
+#else
+ extern void class_add_method_list(Class, MethodList_t);
+ extern void __objc_add_class_to_hash(Class);
+#endif
+
+
+#ifndef nil
+#define nil NULL
+#endif
+
+/* What we call _C_LNGLNG is actually _C_LNG_LNG in the GNU runtime */
+#define _C_LNGLNG _C_LNG_LNG
+#define _C_ULNGLNG _C_ULNG_LNG
+
+/* XXX: names don't conform to the coding-style! */
+extern Ivar_t class_getInstanceVariable(Class aClass, const char *name);
+extern Ivar_t object_getInstanceVariable(id obj, const char *name, void **out);
+extern Ivar_t object_setInstanceVariable(id obj, const char *name, void *value);
+extern void objc_addClass(Class aClass);
+//extern id objc_msgSendSuper(struct objc_super *super, SEL op, ...);
+extern void objc_freeMethodList(struct objc_method_list *list);
+
+static inline int PyObjCRT_SameSEL(SEL a, SEL b)
+{
+ return sel_eq(a, b);
+}
+
+
+static inline const char*
+PyObjCRT_SELName(SEL sel)
+{
+ return sel_get_name(sel);
+}
+
+static inline SEL
+PyObjCRT_SELUID(const char* str)
+{
+ return sel_get_uid(str);
+}
+
+static inline void
+PyObjCRT_ClassAddMethodList(Class cls, MethodList_t lst)
+{
+ int i;
+
+ /* First convert the method_names to strings, class_add_method_list
+ * assumes the method_names are strings and converts these back
+ * to selectors.
+ */
+ for (i = 0; i < lst->method_count; i++) {
+ lst->method_list[i].method_name = (SEL)PyObjCRT_SELName(lst->method_list[i].method_name);
+ }
+
+ class_add_method_list(cls, lst);
+}
+
+static inline Class
+PyObjCRT_LookUpClass(const char* name)
+{
+ return objc_lookup_class(name);
+}
+
+static inline struct objc_method_list *
+PyObjCRT_NextMethodList(Class c, void ** p)
+{
+ if (*p == 0) {
+ *p = c->methods;
+ } else {
+ *p = (*((MethodList_t*)p))->method_next;
+ }
+ return *(MethodList_t*)p;
+}
+
+static inline void
+PyObjCRT_InitMethod(Method_t m, SEL name, const char* types, IMP imp)
+{
+ /* XXX: With some versions of the GNU runtime, the runtime assumes
+ * that method_name is initialy a string instead of a selector, other
+ * versions do not. The version on my development box currently
+ * doesn't.
+ *
+ * m->method_name = (SEL)PyObjCRT_SELName(name);
+ */
+ m->method_name = name;
+ m->method_types = types;
+ m->method_imp = imp;
+}
+
+
+extern MethodList_t PyObjCRT_AllocMethodList(Py_ssize_t);
+extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(Py_ssize_t);
+
+
+typedef Method_t PyObjCRT_Method_t;
+typedef Ivar_t PyObjCRT_Ivar_t;
+
+static inline Class GETISA(id obj)
+{
+ return obj->class_pointer;
+}
+
+//#define GETISA(c) (*((struct objc_object**)&(c))->class_pointer)
+#define CLS_CLASS _CLS_CLASS
+#define CLS_META _CLS_META
+#define RECEIVER(c) (c).self
+
+static inline const char *
+get_selector_encoding (id self, SEL sel)
+{
+ return sel->sel_types;
+}
+
+
+
+extern void PyObjCRT_AddClass(Class cls);
+#define objc_addClass PyObjCRT_AddClass
+
+/* Return a number that is likely to change when the method list changes,
+ * and is cheap to compute.
+ */
+static inline int
+objc_methodlist_magic(Class cls)
+{
+ struct objc_method_list *mlist;
+ int res, cnt;
+ void *iterator = 0;
+
+ res = cnt = 0;
+
+ if (cls == NULL)
+ return -1;
+
+ while ((mlist = PyObjCRT_NextMethodList(cls, &iterator)))
+ {
+ res += mlist->method_count;
+ cnt ++;
+ }
+
+ return (cnt << 16) | (res & 0xFFFF);
+}
+
+
+
+#endif /* PyObjC_RUNTIME_GNU_H */
diff --git a/Objective-C/objc-runtime-gnu.m b/Objective-C/objc-runtime-gnu.m
new file mode 100644
index 0000000..0f585e1
--- /dev/null
+++ b/Objective-C/objc-runtime-gnu.m
@@ -0,0 +1,216 @@
+/* This file is part of the PyObjC package. */
+/*
+ * Support code for the GNU runtime
+ *
+ * NOTE: This file uses some private functions in the GNU runtime as that seems
+ * to be the only way to properly interface with that runtime.
+ */
+#include "pyobjc.h"
+
+#if defined(GNU_RUNTIME)
+
+struct objc_protocol_list* PyObjCRT_AllocProtocolList(int numProtocols)
+{
+ struct objc_protocol_list *plist;
+
+ plist = malloc(sizeof(struct objc_protocol_list)
+ + ((numProtocols+1) * sizeof(Protocol *)));
+
+ if (plist == NULL) {
+ return NULL;
+ }
+
+ plist->count = 0;
+ plist->next = NULL;
+
+ return plist;
+}
+
+int PyObjCRT_SetupClass(
+ Class cls,
+ Class metaCls,
+ const char*name,
+ Class superCls,
+ Class rootCls,
+ int ivarSize,
+ struct objc_ivar_list* ivarList,
+ struct objc_protocol_list* protocolList
+)
+
+{
+ /* This is a private function, but seems to be the only way to
+ * really create the class.
+ */
+ extern void __objc_install_premature_dtable (Class);
+
+ /* Initialize the structure */
+ memset(cls, 0, sizeof(*cls));
+ memset(metaCls, 0, sizeof(*cls));
+
+ cls->version = 0;
+ metaCls->version = 0;
+ cls->subclass_list = NULL;
+ metaCls->subclass_list = NULL;
+ cls->sibling_class = NULL;
+ metaCls->sibling_class = NULL;
+
+ cls->methods = NULL;
+ metaCls->methods = NULL;
+ cls->class_pointer = metaCls;
+
+ cls->info = CLS_CLASS;
+ metaCls->info = CLS_META;
+
+ cls->name = strdup(name);
+ if (cls->name == NULL) {
+ return -1;
+ }
+ metaCls->name = strdup(name);
+ if (metaCls->name == NULL) {
+ free((char*)(cls->name));
+ cls->name = NULL;
+ return -1;
+ }
+
+ cls->methods = NULL;
+ metaCls->methods = NULL;
+
+ cls->super_class = superCls;
+ metaCls->super_class = superCls->class_pointer;
+ metaCls->class_pointer = rootCls->class_pointer;
+ CLS_SETRESOLV(cls);
+ CLS_SETRESOLV(metaCls);
+
+ cls->instance_size = ivarSize;
+ cls->ivars = ivarList;
+
+ metaCls->instance_size = metaCls->super_class->instance_size;
+ metaCls->ivars = NULL;
+
+ metaCls->protocols = cls->protocols = protocolList;
+
+ metaCls->dtable = objc_get_uninstalled_dtable();
+ cls->dtable = objc_get_uninstalled_dtable();
+
+ return 0;
+}
+
+void PyObjCRT_AddClass(Class cls)
+{
+ cls->sibling_class = cls->super_class->subclass_list;
+ cls->super_class->subclass_list = cls;
+ cls->class_pointer->sibling_class = cls->super_class->class_pointer->subclass_list;
+ cls->super_class->class_pointer->subclass_list = cls->class_pointer;
+ __objc_add_class_to_hash(cls);
+}
+
+
+void PyObjCRT_ClearClass(Class cls)
+{
+ if (cls->methods) {
+ MethodList_t next, cur;
+
+ cur = cls->methods;
+
+ while (cur != NULL) {
+ next = cur->method_next;
+
+ objc_free(cur);
+ cur = next;
+ }
+ cls->methods = NULL;
+ }
+
+ if (cls->name) {
+ free((char*)(cls->name));
+ cls->name = NULL;
+ }
+}
+
+struct objc_method_list *PyObjCRT_AllocMethodList(int numMethods)
+{
+ struct objc_method_list *mlist;
+
+ mlist = objc_malloc(sizeof(struct objc_method_list)
+ + ((numMethods+1) * sizeof(struct objc_method)));
+
+ if (mlist == NULL) {
+ return NULL;
+ }
+
+ mlist->method_count = 0;
+ mlist->method_next = NULL;
+
+ return mlist;
+}
+
+/*
+ * XXX: This functions should be renamed to avoid name classes with
+ * the actual ObjC runtime
+ */
+
+Ivar_t class_getInstanceVariable(Class aClass, const char *name)
+{
+ if (!aClass || !name)
+ return NULL;
+
+ for (; aClass != Nil; aClass = aClass->super_class)
+ {
+ int i;
+
+ if (!aClass->ivars)
+ continue;
+
+ for (i = 0; i < aClass->ivars->ivar_count; i++)
+ {
+ if (!strcmp(aClass->ivars->ivar_list[i].ivar_name, name))
+ return &aClass->ivars->ivar_list[i];
+ }
+ }
+
+ return NULL;
+}
+
+Ivar_t object_getInstanceVariable(id obj, const char *name, void **out)
+{
+ Ivar_t var = NULL;
+
+ if (obj && name)
+ {
+ void **varIndex = NULL;
+
+ if ((var = class_getInstanceVariable(obj->class_pointer, name)))
+ varIndex = (void **)((char *)obj + var->ivar_offset);
+
+ if (out)
+ *out = *varIndex;
+ }
+
+ return var;
+}
+
+Ivar_t object_setInstanceVariable(id obj, const char *name, void *value)
+{
+ Ivar_t var = NULL;
+
+ if (obj && name)
+ {
+ void **varIndex;
+
+ if ((var = class_getInstanceVariable(obj->class_pointer, name)))
+ {
+ varIndex = (void **)((char *)obj + var->ivar_offset);
+
+ *varIndex = value;
+ }
+ }
+
+ return var;
+}
+
+
+#else /* !GNU_RUNTIME */
+
+static int dummy __attribute__((__unused__));
+
+#endif /* !GNU_RUNTIME */
diff --git a/Objective-C/objc_support.h b/Objective-C/objc_support.h
new file mode 100644
index 0000000..6c4028e
--- /dev/null
+++ b/Objective-C/objc_support.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved
+ * Copyright (2) 2003 Ronald Oussoren
+ *
+ * This software may be used and distributed freely for any purpose
+ * provided that this notice is included unchanged on any and all
+ * copies. The author does not warrant or guarantee this software in
+ * any way.
+ *
+ * This file is part of the PyObjC package.
+ *
+ * RCSfile: objc_support.h,v
+ * Revision: 1.16
+ * Date: 1998/08/18 15:35:57
+ *
+ * Created Tue Sep 10 14:11:38 1996.
+ *
+ * TODO: the functions exported by this file should be changed, the names
+ * should start with 'PyObjC' and should be the same as the names used in
+ * pyobjc-api.h (where appropriate).
+ */
+
+#ifndef _objc_support_H
+#define _objc_support_H
+
+#ifdef GNU_RUNTIME
+
+# include "objc-runtime-gnu.h"
+
+#else /* NeXTSTEP / Mac OS X */
+
+# include "objc-runtime-apple.h"
+
+#endif
+
+/*#F Takes a C value pointed by @var{datum} with its type encoded in
+ @var{type}, that should be coming from an ObjC @encode directive,
+ and returns an equivalent Python object where C structures and
+ arrays are represented as tuples. */
+extern PyObject *pythonify_c_value (const char *type,
+ void *datum);
+extern PyObject *pythonify_c_return_value (const char *type,
+ void *datum);
+
+/*#F Takes a Python object @var{arg} and translate it into a C value
+ pointed by @var{datum} accordingly with the type specification
+ encoded in @var{type}, that should be coming from an ObjC @encode
+ directive.
+ Returns NULL on success, or a static error string describing the
+ error. */
+extern int depythonify_c_value (const char *type,
+ PyObject *arg,
+ void *datum);
+extern int depythonify_c_return_value (const char *type,
+ PyObject *arg,
+ void *datum);
+
+extern Py_ssize_t PyObjCRT_SizeOfReturnType(const char* type);
+extern Py_ssize_t PyObjCRT_SizeOfType(const char *type);
+extern Py_ssize_t PyObjCRT_AlignOfType(const char *type);
+extern const char *PyObjCRT_SkipTypeSpec (const char *type);
+extern const char* PyObjCRT_SkipTypeQualifiers (const char* type);
+
+/*
+ * Compatibility with pyobjc-api.h
+ */
+static inline id PyObjC_PythonToId(PyObject* value)
+{
+ id res;
+ int r;
+
+ r = depythonify_c_value(@encode(id), value, &res);
+ if (r == -1) {
+ return NULL;
+ } else {
+ return res;
+ }
+}
+
+static inline PyObject* PyObjC_IdToPython(id value)
+{
+ PyObject* res;
+
+ res = pythonify_c_value(@encode(id), &value);
+ return res;
+}
+
+
+extern int PyObjCRT_SetupClass(
+ Class, Class, const char*, Class, Class, Py_ssize_t, struct objc_ivar_list*,
+ struct objc_protocol_list*);
+extern void PyObjCRT_ClearClass(Class cls);
+
+#endif /* _objc_support_H */
diff --git a/Objective-C/objc_support.m b/Objective-C/objc_support.m
new file mode 100644
index 0000000..5bbd338
--- /dev/null
+++ b/Objective-C/objc_support.m
@@ -0,0 +1,521 @@
+/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved
+ * Copyright (c) 2002, 2003 Ronald Oussoren
+ *
+ * This software may be used and distributed freely for any purpose
+ * provided that this notice is included unchanged on any and all
+ * copies. The author does not warrant or guarantee this software in
+ * any way.
+ *
+ * This file is part of the PyObjC package.
+ *
+ * RCSfile: objc_support.m,v
+ * Revision: 1.24
+ * Date: 1998/08/18 15:35:58
+ *
+ * Created Tue Sep 10 14:16:02 1996.
+ */
+
+#include <objc/Protocol.h>
+
+#include <unistd.h>
+
+#ifdef MACOSX
+/* OSX 10.1 doesn't define LLONG_MIN, LLONG_MAX and ULLONG_MAX */
+#ifndef LLONG_MIN
+#error "Mac OS X 10.1 not supported"
+#endif
+#endif
+
+#import <Foundation/NSInvocation.h>
+#import <Foundation/NSData.h>
+#import <Foundation/NSValue.h>
+#import <Foundation/NSDecimalNumber.h>
+
+#ifdef MACOSX
+#include <CoreFoundation/CFNumber.h>
+#endif /* MACOSX */
+
+
+#ifndef MAX
+static inline ssize_t
+MAX(ssize_t x, ssize_t y)
+{
+ return x > y ? x : y;
+}
+#endif
+
+static inline ssize_t
+ROUND(ssize_t v, ssize_t a)
+{
+ if (v % a == 0) {
+ return v;
+ } else {
+ return v + a - (v % a);
+ }
+}
+
+
+const char*
+PyObjCRT_SkipTypeQualifiers (const char* type)
+{
+ while (
+ *type == _C_CONST ||
+ *type == _C_IN ||
+ *type == _C_INOUT ||
+ *type == _C_OUT ||
+ *type == _C_BYCOPY ||
+ *type == _C_ONEWAY) {
+ type++;
+ }
+ while (*type && isdigit(*type)) type++;
+ return type;
+}
+
+
+const char *
+PyObjCRT_SkipTypeSpec (const char *type)
+{
+ type = PyObjCRT_SkipTypeQualifiers (type);
+
+ switch (*type) {
+ /* The following are one character type codes */
+ case _C_UNDEF:
+ case _C_CLASS:
+ case _C_SEL:
+ case _C_CHR:
+ case _C_UCHR:
+ case _C_CHARPTR:
+#ifdef _C_ATOM
+ case _C_ATOM:
+#endif
+#ifdef _C_BOOL
+ case _C_BOOL:
+#endif
+ case _C_SHT:
+ case _C_USHT:
+ case _C_INT:
+ case _C_UINT:
+ case _C_LNG:
+ case _C_ULNG:
+ case _C_FLT:
+ case _C_DBL:
+ case _C_VOID:
+ case _C_LNGLNG:
+ case _C_ULNGLNG:
+ case _C_BFLD: /* Not really 1 character, but close enough */
+ ++type;
+ break;
+
+ case _C_ID:
+ ++type;
+#ifdef MACOSX
+ if (*type == '"') {
+ /* embedded field name in an ivar_type */
+ type=strchr(type+1, '"');
+ if (type != NULL) {
+ type++;
+ }
+ }
+#endif
+ break;
+
+ case _C_ARY_B:
+ /* skip digits, typespec and closing ']' */
+
+ while (isdigit (*++type));
+ type = PyObjCRT_SkipTypeSpec (type);
+ assert (type == NULL || *type == _C_ARY_E);
+ if (type) type++;
+ break;
+
+ case _C_STRUCT_B:
+ /* skip name, and elements until closing '}' */
+ while (*type != _C_STRUCT_E && *type++ != '=');
+ while (type && *type != _C_STRUCT_E) {
+ if (*type == '"') {
+ /* embedded field names */
+ type = strchr(type+1, '"');
+ if (type != NULL) {
+ type++;
+ } else {
+ return NULL;
+ }
+ }
+ type = PyObjCRT_SkipTypeSpec (type);
+ }
+ if (type) type++;
+ break;
+
+ case _C_UNION_B:
+ /* skip name, and elements until closing ')' */
+ while (*type != _C_UNION_E && *type++ != '=');
+ while (type && *type != _C_UNION_E) {
+ type = PyObjCRT_SkipTypeSpec (type);
+ }
+ if (type) type++;
+ break;
+
+ case _C_PTR:
+ case _C_CONST:
+ case _C_IN:
+ case _C_INOUT:
+ case _C_OUT:
+ case _C_BYCOPY:
+ case _C_ONEWAY:
+
+ /* Just skip the following typespec */
+ type = PyObjCRT_SkipTypeSpec (type+1);
+ break;
+
+
+ default:
+ PyErr_Format(PyObjCExc_InternalError,
+ "PyObjCRT_SkipTypeSpec: Unhandled type '%#x'", *type);
+ return NULL;
+ }
+
+ /* The compiler inserts a number after the actual signature,
+ * this number may or may not be usefull depending on the compiler
+ * version. We never use it.
+ */
+ while (type && *type && isdigit(*type)) type++;
+ return type;
+}
+
+/*
+Return the alignment of an object specified by type
+*/
+
+/*
+* On MacOS X, the elements of a struct are aligned differently inside the
+* struct than outside. That is, the maximum alignment of any struct field
+* (except the first) is 4, doubles outside of a struct have an alignment of
+* 8.
+*
+* Other platform don't seem to have this inconsistency.
+*
+* XXX: sizeof_struct, alignof_struct and {de,}pythonify_c_struct should
+* probably be moved to platform dependend files. As long as this is the
+* only platform dependent code this isn't worth the effort.
+*/
+#ifdef MACOSX
+
+static inline ssize_t
+PyObjC_EmbeddedAlignOfType (const char* type)
+{
+ ssize_t align = PyObjCRT_AlignOfType(type);
+
+#ifdef __i386__
+ return align;
+
+#else
+ if (align < 4 || align == 16) {
+ return align;
+ } else {
+ return 4;
+ }
+#endif
+}
+
+#else
+
+static inline int
+PyObjC_EmbeddedAlignOfType (const char* type)
+{
+ ssize_t align = PyObjCRT_AlignOfType(type);
+
+ /* GNUstep/ix86 seems to behave like this: */
+ if (align < 4) {
+ return align;
+ } else {
+ return 4;
+ }
+}
+
+#endif
+
+ssize_t
+PyObjCRT_AlignOfType (const char *type)
+{
+ switch (*type) {
+ case _C_ID: return __alignof__ (id);
+ case _C_CLASS: return __alignof__ (Class);
+ case _C_SEL: return __alignof__ (SEL);
+ case _C_CHR: return __alignof__ (char);
+ case _C_UCHR: return __alignof__ (unsigned char);
+ case _C_SHT: return __alignof__ (short);
+ case _C_USHT: return __alignof__ (unsigned short);
+#ifdef _C_BOOL
+ case _C_BOOL: return __alignof__ (bool);
+#endif
+ case _C_INT: return __alignof__ (int);
+ case _C_UINT: return __alignof__ (unsigned int);
+ case _C_LNG: return __alignof__ (long);
+ case _C_ULNG: return __alignof__ (unsigned long);
+ case _C_FLT: return __alignof__ (float);
+ case _C_DBL:
+#if defined(__APPLE__) && defined(__i386__)
+ /* The ABI says natural alignment is 4 bytes, but
+ * GCC's __alignof__ says 8. The latter is wrong.
+ */
+ return 4;
+#else
+ return __alignof__ (double);
+#endif
+
+ case _C_CHARPTR: return __alignof__ (char *);
+#ifdef _C_ATOM
+ case _C_ATOM: return __alignof__ (char *);
+#endif
+ case _C_PTR: return __alignof__ (void *);
+#if defined(__APPLE__) && defined(__i386__)
+ /* The ABI says natural alignment is 4 bytes, but
+ * GCC's __alignof__ says 8. The latter is wrong.
+ */
+ case _C_LNGLNG: return 4;
+ case _C_ULNGLNG: return 4;
+#else
+ case _C_LNGLNG: return __alignof__(long long);
+ case _C_ULNGLNG: return __alignof__(unsigned long long);
+#endif
+
+ case _C_ARY_B:
+ while (isdigit(*++type)) /* do nothing */;
+ return PyObjCRT_AlignOfType (type);
+
+ case _C_STRUCT_B:
+ {
+ struct { int x; double y; } fooalign;
+ while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
+ if (*type != _C_STRUCT_E) {
+ int have_align = 0;
+ ssize_t align = 0;
+
+ while (type != NULL && *type != _C_STRUCT_E) {
+ if (*type == '"') {
+ type = strchr(type+1, '"');
+ if (type) type++;
+ }
+ if (have_align) {
+ align = MAX(align,
+ PyObjC_EmbeddedAlignOfType(type));
+ } else {
+ align = PyObjCRT_AlignOfType(type);
+ have_align = 1;
+ }
+ type = PyObjCRT_SkipTypeSpec(type);
+ }
+ if (type == NULL) return -1;
+ return align;
+ } else {
+ return __alignof__ (fooalign);
+ }
+ }
+
+ case _C_UNION_B:
+ {
+ int maxalign = 0;
+ type++;
+ while (*type != _C_UNION_E)
+ {
+ int item_align = PyObjCRT_AlignOfType(type);
+ if (item_align == -1) return -1;
+ maxalign = MAX (maxalign, item_align);
+ type = PyObjCRT_SkipTypeSpec (type);
+ }
+ return maxalign;
+ }
+
+ case _C_CONST:
+ case _C_IN:
+ case _C_INOUT:
+ case _C_OUT:
+ case _C_BYCOPY:
+ case _C_ONEWAY:
+ return PyObjCRT_AlignOfType(type+1);
+
+ default:
+ PyErr_Format(PyObjCExc_InternalError,
+ "PyObjCRT_AlignOfType: Unhandled type '%#x'", *type);
+ return -1;
+ }
+}
+
+/*
+The aligned size if the size rounded up to the nearest alignment.
+*/
+
+static ssize_t
+PyObjCRT_AlignedSize (const char *type)
+{
+ ssize_t size = PyObjCRT_SizeOfType (type);
+ ssize_t align = PyObjCRT_AlignOfType (type);
+
+ if (size == -1 || align == -1) return -1;
+ return ROUND(size, align);
+}
+
+/*
+return the size of an object specified by type
+*/
+
+ssize_t
+PyObjCRT_SizeOfType (const char *type)
+{
+ ssize_t itemSize;
+ switch (*type) {
+ case _C_VOID: return 0;
+ case _C_ID: return sizeof(id);
+ case _C_CLASS: return sizeof(Class);
+ case _C_SEL: return sizeof(SEL);
+ case _C_CHR: return sizeof(char);
+ case _C_UCHR: return sizeof(unsigned char);
+ case _C_SHT: return sizeof(short);
+ case _C_USHT: return sizeof(unsigned short);
+#ifdef _C_BOOL
+ case _C_BOOL: return sizeof(bool);
+#endif
+ case _C_INT: return sizeof(int);
+ case _C_UINT: return sizeof(unsigned int);
+ case _C_LNG: return sizeof(long);
+ case _C_ULNG: return sizeof(unsigned long);
+ case _C_FLT: return sizeof(float);
+ case _C_DBL: return sizeof(double);
+ case _C_LNGLNG: return sizeof(long long);
+ case _C_ULNGLNG: return sizeof(unsigned long long);
+
+ case _C_PTR:
+ case _C_CHARPTR:
+#ifdef _C_ATOM
+ case _C_ATOM:
+#endif
+ return sizeof(char*);
+
+ case _C_ARY_B:
+ {
+ ssize_t len = atoi(type+1);
+ ssize_t item_align;
+ while (isdigit(*++type))
+ ;
+ item_align = PyObjCRT_AlignedSize(type);
+ if (item_align == -1) return -1;
+ return len*item_align;
+ }
+ break;
+
+ case _C_STRUCT_B:
+ {
+ ssize_t acc_size = 0;
+ int have_align = 0;
+ ssize_t align;
+ ssize_t max_align = 0;
+
+ while (*type != _C_STRUCT_E && *type++ != '=')
+ ; /* skip "<name>=" */
+ while (*type != _C_STRUCT_E) {
+ if (*type == '"') {
+ type = strchr(type+1, '"');
+ if (type) type++;
+ }
+ if (have_align) {
+ align = PyObjC_EmbeddedAlignOfType(type);
+ if (align == -1) return -1;
+ } else {
+ align = PyObjCRT_AlignOfType(type);
+ if (align == -1) return -1;
+ have_align = 1;
+ }
+ max_align = MAX(align, max_align);
+ acc_size = ROUND (acc_size, align);
+
+ itemSize = PyObjCRT_SizeOfType (type);
+ if (itemSize == -1) return -1;
+ acc_size += itemSize;
+ type = PyObjCRT_SkipTypeSpec (type);
+ }
+ if (max_align) {
+ acc_size = ROUND(acc_size, max_align);
+ }
+ return acc_size;
+ }
+
+ case _C_UNION_B:
+ {
+ ssize_t max_size = 0;
+ type++;
+ while (*type != _C_UNION_E) {
+ itemSize = PyObjCRT_SizeOfType (type);
+ if (itemSize == -1) return -1;
+ max_size = MAX (max_size, itemSize);
+ type = PyObjCRT_SkipTypeSpec (type);
+ }
+ return max_size;
+ }
+
+ case _C_CONST:
+ case _C_IN:
+ case _C_INOUT:
+ case _C_OUT:
+ case _C_BYCOPY:
+ case _C_ONEWAY:
+ return PyObjCRT_SizeOfType(type+1);
+
+ default:
+ PyErr_Format(PyObjCExc_InternalError,
+ "PyObjCRT_SizeOfType: Unhandled type '%#x", *type);
+ return -1;
+ }
+}
+
+
+/*#F Returns a tuple of objects representing the content of a C array
+of type @var{type} pointed by @var{datum}. */
+static PyObject *
+pythonify_c_array (const char *type, void *datum)
+{
+ PyObject *ret;
+ ssize_t nitems, itemidx, sizeofitem;
+ unsigned char* curdatum;
+
+ nitems = atoi (type+1);
+ while (isdigit (*++type))
+ ;
+ sizeofitem = PyObjCRT_SizeOfType (type);
+ if (sizeofitem == -1) return NULL;
+
+ ret = PyTuple_New (nitems);
+ if (!ret) return NULL;
+
+ curdatum = datum;
+ for (itemidx=0; itemidx < nitems; itemidx++) {
+ PyObject *pyitem = NULL;
+
+ pyitem = pythonify_c_value (type, curdatum);
+
+ if (pyitem) {
+ PyTuple_SET_ITEM (ret, itemidx, pyitem);
+ } else {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ curdatum += sizeofitem;
+ }
+
+ return ret;
+}
+
+
+ssize_t
+PyObjCRT_SizeOfReturnType(const char* type)
+{
+ switch(*type) {
+ case _C_CHR:
+ case _C_UCHR:
+ case _C_SHT:
+ case _C_USHT:
+ return sizeof(int);
+ default:
+ return PyObjCRT_SizeOfType(type);
+ }
+}