blob: 25d51885bdddc40780f9c6d570befb68a5f9510c [file] [log] [blame]
//---------------------------------------------------------------------------------------
// $Id$
// Copyright (c) 2006-2009 by Mulle Kybernetik. See License file for details.
//---------------------------------------------------------------------------------------
#import "NSInvocation+OCMAdditions.h"
@implementation NSInvocation(OCMAdditions)
- (id)getArgumentAtIndexAsObject:(int)argIndex
{
const char* argType;
argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
while(strchr("rnNoORV", argType[0]) != NULL)
argType += 1;
if((strlen(argType) > 1) && (strchr("{^", argType[0]) == NULL) && (strcmp("@?", argType) != 0))
[NSException raise:NSInvalidArgumentException format:@"Cannot handle argument type '%s'.", argType];
switch (argType[0])
{
case '#':
case '@':
{
id value;
[self getArgument:&value atIndex:argIndex];
return value;
}
case ':':
{
SEL s = (SEL)0;
[self getArgument:&s atIndex:argIndex];
id value = NSStringFromSelector(s);
return value;
}
case 'i':
{
int value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithInt:value];
}
case 's':
{
short value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithShort:value];
}
case 'l':
{
long value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithLong:value];
}
case 'q':
{
long long value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithLongLong:value];
}
case 'c':
{
char value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithChar:value];
}
case 'C':
{
unsigned char value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithUnsignedChar:value];
}
case 'I':
{
unsigned int value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithUnsignedInt:value];
}
case 'S':
{
unsigned short value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithUnsignedShort:value];
}
case 'L':
{
unsigned long value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithUnsignedLong:value];
}
case 'Q':
{
unsigned long long value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithUnsignedLongLong:value];
}
case 'f':
{
float value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithFloat:value];
}
case 'd':
{
double value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithDouble:value];
}
case 'B':
{
bool value;
[self getArgument:&value atIndex:argIndex];
return [NSNumber numberWithBool:value];
}
case '^':
{
void *value = NULL;
[self getArgument:&value atIndex:argIndex];
return [NSValue valueWithPointer:value];
}
case '{': // structure
{
NSUInteger maxArgSize = [[self methodSignature] frameLength];
NSMutableData *argumentData = [[[NSMutableData alloc] initWithLength:maxArgSize] autorelease];
[self getArgument:[argumentData mutableBytes] atIndex:argIndex];
return [NSValue valueWithBytes:[argumentData bytes] objCType:argType];
}
}
[NSException raise:NSInvalidArgumentException format:@"Argument type '%s' not supported", argType];
return nil;
}
- (NSString *)invocationDescription
{
NSMethodSignature *methodSignature = [self methodSignature];
NSUInteger numberOfArgs = [methodSignature numberOfArguments];
if (numberOfArgs == 2)
return NSStringFromSelector([self selector]);
NSArray *selectorParts = [NSStringFromSelector([self selector]) componentsSeparatedByString:@":"];
NSMutableString *description = [[NSMutableString alloc] init];
unsigned int i;
for(i = 2; i < numberOfArgs; i++)
{
[description appendFormat:@"%@%@:", (i > 2 ? @" " : @""), [selectorParts objectAtIndex:(i - 2)]];
[description appendString:[self argumentDescriptionAtIndex:i]];
}
return [description autorelease];
}
- (NSString *)argumentDescriptionAtIndex:(int)argIndex
{
const char *argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
if(strchr("rnNoORV", argType[0]) != NULL)
argType += 1;
switch(*argType)
{
case '@': return [self objectDescriptionAtIndex:argIndex];
case 'B': return [self boolDescriptionAtIndex:argIndex];
case 'c': return [self charDescriptionAtIndex:argIndex];
case 'C': return [self unsignedCharDescriptionAtIndex:argIndex];
case 'i': return [self intDescriptionAtIndex:argIndex];
case 'I': return [self unsignedIntDescriptionAtIndex:argIndex];
case 's': return [self shortDescriptionAtIndex:argIndex];
case 'S': return [self unsignedShortDescriptionAtIndex:argIndex];
case 'l': return [self longDescriptionAtIndex:argIndex];
case 'L': return [self unsignedLongDescriptionAtIndex:argIndex];
case 'q': return [self longLongDescriptionAtIndex:argIndex];
case 'Q': return [self unsignedLongLongDescriptionAtIndex:argIndex];
case 'd': return [self doubleDescriptionAtIndex:argIndex];
case 'f': return [self floatDescriptionAtIndex:argIndex];
// Why does this throw EXC_BAD_ACCESS when appending the string?
// case NSObjCStructType: return [self structDescriptionAtIndex:index];
case '^': return [self pointerDescriptionAtIndex:argIndex];
case '*': return [self cStringDescriptionAtIndex:argIndex];
case ':': return [self selectorDescriptionAtIndex:argIndex];
default: return [@"<??" stringByAppendingString:@">"]; // avoid confusion with trigraphs...
}
}
- (NSString *)objectDescriptionAtIndex:(int)anInt
{
id object;
[self getArgument:&object atIndex:anInt];
if (object == nil)
return @"nil";
else if(![object isProxy] && [object isKindOfClass:[NSString class]])
return [NSString stringWithFormat:@"@\"%@\"", [object description]];
else
return [object description];
}
- (NSString *)boolDescriptionAtIndex:(int)anInt
{
bool value;
[self getArgument:&value atIndex:anInt];
return value ? @"YES" : @"NO";
}
- (NSString *)charDescriptionAtIndex:(int)anInt
{
unsigned char buffer[128];
memset(buffer, 0x0, 128);
[self getArgument:&buffer atIndex:anInt];
// If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL
if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1))
return [NSString stringWithFormat:@"%@", (buffer[0] == 1 ? @"YES" : @"NO")];
else
return [NSString stringWithFormat:@"'%c'", *buffer];
}
- (NSString *)unsignedCharDescriptionAtIndex:(int)anInt
{
unsigned char buffer[128];
memset(buffer, 0x0, 128);
[self getArgument:&buffer atIndex:anInt];
return [NSString stringWithFormat:@"'%c'", *buffer];
}
- (NSString *)intDescriptionAtIndex:(int)anInt
{
int intValue;
[self getArgument:&intValue atIndex:anInt];
return [NSString stringWithFormat:@"%d", intValue];
}
- (NSString *)unsignedIntDescriptionAtIndex:(int)anInt
{
unsigned int intValue;
[self getArgument:&intValue atIndex:anInt];
return [NSString stringWithFormat:@"%d", intValue];
}
- (NSString *)shortDescriptionAtIndex:(int)anInt
{
short shortValue;
[self getArgument:&shortValue atIndex:anInt];
return [NSString stringWithFormat:@"%hi", shortValue];
}
- (NSString *)unsignedShortDescriptionAtIndex:(int)anInt
{
unsigned short shortValue;
[self getArgument:&shortValue atIndex:anInt];
return [NSString stringWithFormat:@"%hu", shortValue];
}
- (NSString *)longDescriptionAtIndex:(int)anInt
{
long longValue;
[self getArgument:&longValue atIndex:anInt];
return [NSString stringWithFormat:@"%ld", longValue];
}
- (NSString *)unsignedLongDescriptionAtIndex:(int)anInt
{
unsigned long longValue;
[self getArgument:&longValue atIndex:anInt];
return [NSString stringWithFormat:@"%lu", longValue];
}
- (NSString *)longLongDescriptionAtIndex:(int)anInt
{
long long longLongValue;
[self getArgument:&longLongValue atIndex:anInt];
return [NSString stringWithFormat:@"%qi", longLongValue];
}
- (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt
{
unsigned long long longLongValue;
[self getArgument:&longLongValue atIndex:anInt];
return [NSString stringWithFormat:@"%qu", longLongValue];
}
- (NSString *)doubleDescriptionAtIndex:(int)anInt;
{
double doubleValue;
[self getArgument:&doubleValue atIndex:anInt];
return [NSString stringWithFormat:@"%f", doubleValue];
}
- (NSString *)floatDescriptionAtIndex:(int)anInt
{
float floatValue;
[self getArgument:&floatValue atIndex:anInt];
return [NSString stringWithFormat:@"%f", floatValue];
}
- (NSString *)structDescriptionAtIndex:(int)anInt;
{
void *buffer;
[self getArgument:&buffer atIndex:anInt];
return [NSString stringWithFormat:@":(struct)%p", buffer];
}
- (NSString *)pointerDescriptionAtIndex:(int)anInt
{
void *buffer;
[self getArgument:&buffer atIndex:anInt];
return [NSString stringWithFormat:@"%p", buffer];
}
- (NSString *)cStringDescriptionAtIndex:(int)anInt
{
char buffer[128];
memset(buffer, 0x0, 128);
[self getArgument:&buffer atIndex:anInt];
return [NSString stringWithFormat:@"\"%s\"", buffer];
}
- (NSString *)selectorDescriptionAtIndex:(int)anInt
{
SEL selectorValue;
[self getArgument:&selectorValue atIndex:anInt];
return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)];
}
@end