/* -*- mode: objc; coding: utf-8 -*- */
/* Objective-CL, an Objective-C bridge for Common Lisp.
* Copyright (C) 2007 Matthias Andreas Benkard.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* .
*/
#import "libobjcl.h"
#import "PyObjC/libffi_support.h"
#import "PyObjC/objc_support.h"
#import
#include
#include
#ifdef __NEXT_RUNTIME__
#include
#endif
static NSAutoreleasePool *objcl_autorelease_pool = NULL;
/* Preallocate an exception to throw when memory is all used up. */
NSException *objcl_oom_exception = NULL;
void
objcl_initialise_runtime (void)
{
if (!objcl_autorelease_pool)
objcl_autorelease_pool = [[NSAutoreleasePool alloc] init];
if (!objcl_oom_exception)
{
objcl_oom_exception = [NSException exceptionWithName: @"MLKOutOfMemoryException"
reason: @"Out of memory"
userInfo: nil];
[objcl_oom_exception retain];
}
}
void
objcl_shutdown_runtime (void)
{
if (objcl_autorelease_pool)
{
[objcl_autorelease_pool release];
objcl_autorelease_pool = NULL;
}
if (objcl_oom_exception)
{
[objcl_oom_exception release];
objcl_oom_exception = NULL;
}
}
#ifdef USE_LIBFFI
id
objcl_invoke_with_types (int argc,
char *return_typespec,
char *arg_typespecs[],
void *return_value,
void **argv)
{
IMP method;
int i;
ffi_cif cif;
ffi_type *return_type;
ffi_type *arg_types[argc + 2];
ffi_status status;
id receiver = *((id*)argv[0]);
SEL method_selector = *((SEL*)argv[1]);
static ffi_type *id_type = NULL;
static ffi_type *sel_type = NULL;
if (!id_type)
id_type = objcl_pyobjc_arg_signature_to_ffi_type ("@");
if (!sel_type)
sel_type = objcl_pyobjc_arg_signature_to_ffi_type (":");
NS_DURING
{
#ifdef __NEXT_RUNTIME__
if (objcl_object_is_class (receiver))
method = class_getClassMethod (receiver, method_selector)->method_imp;
else
method = class_getInstanceMethod ([receiver class], method_selector)->method_imp;
#else
method = objc_msg_lookup (receiver, method_selector);
/* Alternatively:
method = [receiver methodForSelector: method_selector];
*/
#endif
if (method == NULL)
[[NSException exceptionWithName: @"MLKNoApplicableMethod"
reason: @"Tried to call a non-existent method."
userInfo: nil] raise];
return_type = objcl_pyobjc_signature_to_ffi_return_type (return_typespec);
arg_types[0] = id_type;
arg_types[1] = sel_type;
for (i = 0; i < argc; i++)
arg_types[i + 2] = objcl_pyobjc_arg_signature_to_ffi_type (arg_typespecs[i]);
status = ffi_prep_cif (&cif, FFI_DEFAULT_ABI, argc + 2, return_type, arg_types);
if (status != FFI_OK)
{
[[NSException exceptionWithName: @"MLKInvalidFFITypeException"
reason: @"FFI type is invalid (this is probably a bug)."
userInfo: nil] raise];
}
ffi_call (&cif, FFI_FN (method), return_value, argv);
}
NS_HANDLER
{
NS_VALUERETURN (localException, id);
}
NS_ENDHANDLER
return NULL;
}
#endif
Class
objcl_find_class (const char *class_name)
{
#ifdef __NEXT_RUNTIME__
return objc_lookUpClass (class_name);
#else
return objc_lookup_class (class_name);
#endif
}
Class
objcl_find_meta_class (const char *class_name)
{
#ifdef __NEXT_RUNTIME__
return objc_getMetaClass (class_name);
#else
/* FIXME: Is this correct? */
Class class = objcl_find_class (class_name);
if (class == NULL || class == nil)
return NULL;
else
return class_get_meta_class (class);
#endif
}
SEL
objcl_find_selector (const char *selector_name)
{
#ifdef __NEXT_RUNTIME__
if (!(sel_isMapped ((SEL) selector_name))) /* XXX Does this work? */
return NULL;
else
return sel_getUid (selector_name);
#else
return sel_get_any_uid (selector_name);
#endif
}
SEL
objcl_intern_selector (const char *selector_name)
{
/* sel_registerName and sel_register_name seem not to be necessary here. */
#ifdef __NEXT_RUNTIME__
return sel_getUid (selector_name);
#else
return sel_get_uid (selector_name);
#endif
}
const char *
objcl_class_name (Class class)
{
const char *ns_name;
char *name;
ns_name = [(NSStringFromClass (class)) UTF8String];
name = malloc (strlen (ns_name) + 1);
strcpy (name, ns_name);
return name;
}
const char *
objcl_selector_name (SEL selector)
{
const char *ns_name;
char *name;
ns_name = [(NSStringFromSelector (selector)) UTF8String];
name = malloc (strlen (ns_name) + 1);
strcpy (name, ns_name);
return name;
}
IMP
objcl_get_method_implementation (id object,
SEL selector)
{
#ifdef __NEXT_RUNTIME__
if (objcl_object_is_class (object))
{
return class_getClassMethod (object, selector)->method_imp;
}
else
{
return class_getInstanceMethod ([object class], selector)->method_imp;
}
#else
return objc_msg_lookup (object, selector);
#endif
}
BOOL
objcl_object_is_class (id obj)
{
#ifdef __NEXT_RUNTIME__
return [obj class] == obj;
#else
/* return CLS_ISCLASS (obj); */
return object_is_class (obj);
#endif
}
BOOL
objcl_object_is_meta_class (id obj)
{
#ifdef __NEXT_RUNTIME__
/* FIXME: What to do here? */
return objcl_object_get_meta_class (obj) == obj;
#else
/* return CLS_ISMETA (ptr); */
if (objcl_object_is_class (obj))
return class_is_meta_class (obj);
else
return object_is_meta_class (obj);
#endif
}
Class
objcl_object_get_class (id obj)
{
#ifdef __NEXT_RUNTIME__
/* XXX? return obj->isa; */
return [obj class];
#else
return object_get_class (obj);
#endif
}
Class
objcl_object_get_meta_class (id obj)
{
#ifdef __NEXT_RUNTIME__
/* FIXME: What to do here? */
return objc_getMetaClass ([(NSStringFromClass ([obj class])) UTF8String]);
#else
if (objcl_object_is_class (obj))
return class_get_meta_class (obj);
else
return object_get_meta_class (obj);
#endif
}
id
objcl_get_nil (void)
{
return nil;
}
long
objcl_get_yes (void)
{
if (sizeof (YES) > sizeof (long))
fprintf (stderr, "WARNING: objcl_get_yes: YES might not fit into a long.\n");
return YES;
}
long
objcl_get_no (void)
{
if (sizeof (NO) > sizeof (long))
fprintf (stderr, "WARNING: objcl_get_no: NO might not fit into a long.\n");
return NO;
}
const char *
objcl_get_runtime_type (void)
{
#ifdef __NEXT_RUNTIME__
return "NeXT";
#else
return "GNU";
#endif
}
int
objcl_objc2_p (void)
{
#ifdef __OBJC2__
return 1;
#else
return 0;
#endif
}
long
objcl_sizeof_type (const char *typespec)
{
if (sizeof (ssize_t) > sizeof (long))
fprintf (stderr, "WARNING: objcl_sizeof_typespec: Size might not fit into a long.\n");
return PyObjCRT_SizeOfType (typespec);
}
long
objcl_sizeof_return_type (const char *typespec)
{
if (sizeof (ssize_t) > sizeof (long))
fprintf (stderr, "WARNING: objcl_sizeof_return_typespec: Size might not fit into a long.\n");
return PyObjCRT_SizeOfReturnType (typespec);
}
long
objcl_alignof_type (const char *typespec)
{
if (sizeof (ssize_t) > sizeof (long))
fprintf (stderr, "WARNING: objcl_align_typespec: Alignment might not fit into a long.\n");
return PyObjCRT_AlignOfType (typespec);
}