libs-steptalk/Source/NSInvocation+additions.m
Stefan Urbanek 6f349497a5 Workaround for gnustep-base DO bug
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/steptalk/trunk@16925 72102866-910b-0410-8b05-ffd578937521
2003-06-15 09:35:28 +00:00

325 lines
9.6 KiB
Objective-C

/**
NSInvocation+additions
Various NSInvocation additions
Copyright (c) 2002 Free Software Foundation
Written by: Stefan Urbanek <urbanek@host.sk>
Date: 2000
This file is part of the StepTalk project.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02111, USA.
<title>NSInvocation class additions</title>
*/
#import <StepTalk/NSInvocation+additions.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSException.h>
#import <Foundation/NSValue.h>
#import <StepTalk/STExterns.h>
#import <StepTalk/STObjCRuntime.h>
#import <StepTalk/STScripting.h>
#import <StepTalk/STSelector.h>
#import <StepTalk/STStructure.h>
#if 0
static Class NSNumber_class = nil;
static Class NSString_class = nil;
static Class NSValue_class = nil;
#endif
#define CASE_NUMBER_TYPE(otype,type,msgtype)\
case otype: object = [NSNumber numberWith##msgtype:*((type *)value)];\
NSDebugLLog(@"STStructure",\
@" is number value '%@'", object);\
break
id STObjectFromValueOfType(void *value, const char *type)
{
id object;
NSDebugLLog(@"STStructure",
@"object from value %p of of type '%c'",value,*type);
switch(*type)
{
case _C_ID:
case _C_CLASS:
object = *((id *)value);
NSDebugLLog(@"STStructure",
@" is object value %p", object);
break;
CASE_NUMBER_TYPE(_C_CHR,char,Char);
CASE_NUMBER_TYPE(_C_UCHR,unsigned char, UnsignedChar);
CASE_NUMBER_TYPE(_C_SHT,short,Short);
CASE_NUMBER_TYPE(_C_USHT,unsigned short,UnsignedShort);
CASE_NUMBER_TYPE(_C_INT,int,Int);
CASE_NUMBER_TYPE(_C_UINT,unsigned int,UnsignedInt);
CASE_NUMBER_TYPE(_C_LNG,long,Long);
CASE_NUMBER_TYPE(_C_ULNG,unsigned long,UnsignedLong);
CASE_NUMBER_TYPE(_C_LNG_LNG,long long,LongLong);
CASE_NUMBER_TYPE(_C_ULNG_LNG,unsigned long long,UnsignedLongLong);
CASE_NUMBER_TYPE(_C_FLT,float,Float);
CASE_NUMBER_TYPE(_C_DBL,double,Double);
case _C_PTR:
object = [NSValue valueWithPointer:*((void **)value)];
NSDebugLLog(@"STStructure",
@" is pointer value %p", *((void **)value));
break;
case _C_CHARPTR:
object = [NSString stringWithCString:*((char **)value)];
NSDebugLLog(@"STStructure",
@" is string value '%s'", *((char **)value));
break;
case _C_VOID:
object = nil;
break;
case _C_STRUCT_B:
object = [[STStructure alloc] initWithValue:value
type:type];
AUTORELEASE(object);
break;
case _C_SEL:
object = [[STSelector alloc] initWithSelector:*((SEL *)value)];
AUTORELEASE(object);
break;
case _C_BFLD:
case _C_UNDEF:
case _C_ATOM:
case _C_ARY_B:
case _C_ARY_E:
case _C_UNION_B:
case _C_UNION_E:
case _C_STRUCT_E:
default:
[NSException raise:STInvalidArgumentException
format:@"unhandled ObjC type '%s'",
type];
}
return object;
}
#define CASE_TYPE(otype,type,msgtype)\
case otype:(*((type *)value)) = [anObject msgtype##Value];\
NSDebugLLog(@"STStructure",\
@" is number value '%@'", anObject);\
break
void STGetValueOfTypeFromObject(void *value, const char *type, id anObject)
{
NSDebugLLog(@"STStructure",
@"value at %p from object '%@' of type '%c'",
value,anObject,*type);
switch(*type)
{
case _C_ID:
case _C_CLASS:
NSDebugLLog(@"STStructure",
@" is object value");
(*(id *)value) = anObject;
break;
CASE_TYPE(_C_CHR,char,char);
CASE_TYPE(_C_UCHR,unsigned char,unsignedChar);
CASE_TYPE(_C_SHT,short,short);
CASE_TYPE(_C_USHT,unsigned short,unsignedShort);
CASE_TYPE(_C_INT,int,int);
CASE_TYPE(_C_UINT,unsigned int,unsignedInt);
CASE_TYPE(_C_LNG,long,long);
CASE_TYPE(_C_ULNG,unsigned long,unsignedLong);
CASE_TYPE(_C_LNG_LNG,long long,longLong);
CASE_TYPE(_C_ULNG_LNG,unsigned long long,unsignedLongLong);
CASE_TYPE(_C_FLT,float,float);
CASE_TYPE(_C_DBL,double,double);
CASE_TYPE(_C_PTR,void *,pointer);
case _C_CHARPTR: /* FIXME: check if this is good (copy/no copy)*/
(*((const char **)value)) = [[anObject stringValue] cString];
NSDebugLLog(@"STStructure",
@" is cstring '%@'", [anObject stringValue]);
break;
case _C_STRUCT_B:
/* FIXME: chech for struct compatibility */
NSDebugLLog(@"STStructure",
@" is structure");
[(STStructure*)anObject getValue:value];
break;
case _C_SEL:
(*((SEL *)value)) = [anObject selectorValue];
break;
case _C_BFLD:
case _C_VOID:
case _C_UNDEF:
case _C_ATOM:
case _C_ARY_B:
case _C_ARY_E:
case _C_UNION_B:
case _C_UNION_E:
case _C_STRUCT_E:
default:
[NSException raise:STInvalidArgumentException
format:@"unhandled ObjC type '%s'",
type];
}
}
@implementation NSInvocation(STAdditions)
#if 0
/* with this method it does not work, it is not posiible to create an
invocation*/
+ (void)initialize
{
NSNumber_class = [NSNumber class];
NSString_class = [NSString class];
NSValue_class = [NSValue class];
}
#endif
+ invocationWithTarget:(id)target selectorName:(NSString *)selectorName
{
NSMethodSignature *signature;
NSInvocation *invocation;
SEL sel;
BOOL requiresRegistration = NO;
// NSLog(@"GETTING SELECTOR %@", selectorName);
sel = NSSelectorFromString(selectorName);
if(!sel)
{
// NSLog(@"REGISTERING SELECTOR");
char *name = [selectorName cString];
sel = sel_register_name(name);
if(!sel)
{
[NSException raise:STInternalInconsistencyException
format:@"Unable to register selector '%@'",
selectorName];
return nil;
}
requiresRegistration = YES;
}
signature = [target methodSignatureForSelector:sel];
/* FIXME: this is workaround for gnustep DO bug (hight priority) */
if(requiresRegistration)
{
// NSLog(@"REGISTERING SELECTOR TYPES");
sel = sel_register_typed_name([selectorName cString], [signature methodReturnType]);
// NSLog(@"REGISTERED %@", NSStringFromSelector(sel));
}
if(!signature)
{
[NSException raise:STInternalInconsistencyException
format:@"No method signature for selector '%@' for "
@"receiver of type %@",
selectorName,[target className]];
return nil;
}
invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:sel];
[invocation setTarget:target];
return invocation;
}
- (void)setArgumentAsObject:(id)anObject atIndex:(int)anIndex
{
const char *type;
void *value;
type = [[self methodSignature] getArgumentTypeAtIndex:anIndex];
value = NSZoneMalloc(STMallocZone,objc_sizeof_type(type));
STGetValueOfTypeFromObject(value, type, anObject);
[self setArgument:(void *)value atIndex:anIndex];
NSZoneFree(STMallocZone,value);
}
- (id)getArgumentAsObjectAtIndex:(int)anIndex
{
const char *type;
void *value;
id object;
type = [[self methodSignature] getArgumentTypeAtIndex:anIndex];
value = NSZoneMalloc(STMallocZone,objc_sizeof_type(type));
[self getArgument:value atIndex:anIndex];
object = STObjectFromValueOfType(value,type);
NSZoneFree(STMallocZone,value);
return object;
}
- (id)returnValueAsObject
{
const char *type;
int returnLength;
void *value;
id returnObject = nil;
NSMethodSignature *signature = [self methodSignature];
type = [signature methodReturnType];
returnLength = [signature methodReturnLength];
NSDebugLLog(@"STSending",
@" return type '%s', buffer length %i",type,returnLength);
if(returnLength!=0)
{
value = NSZoneMalloc(STMallocZone,returnLength);
[self getReturnValue:value];
if( *type == _C_VOID )
{
returnObject = [self target];
}
else
{
returnObject = STObjectFromValueOfType(value, type);
}
NSZoneFree(STMallocZone,value);
NSDebugLLog(@"STSending",
@" returned object %@",returnObject);
}
else
{
returnObject = [self target];
}
return returnObject;
}
@end