diff options
-rw-r--r-- | Objective-C/GNUmakefile | 5 | ||||
-rw-r--r-- | Objective-C/libobjcl.h | 18 | ||||
-rw-r--r-- | Objective-C/libobjcl.m | 42 | ||||
-rw-r--r-- | Objective-C/objc-runtime-apple.h | 132 | ||||
-rw-r--r-- | Objective-C/objc-runtime-apple.m | 158 | ||||
-rw-r--r-- | Objective-C/objc-runtime-gnu.h | 174 | ||||
-rw-r--r-- | Objective-C/objc-runtime-gnu.m | 216 | ||||
-rw-r--r-- | Objective-C/objc_support.h | 93 | ||||
-rw-r--r-- | Objective-C/objc_support.m | 521 |
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); + } +} |