samhuri.net-ios/Pods/libextobjc/extobjc/NSInvocation+EXT.m
2014-10-18 14:19:51 -07:00

350 lines
9.5 KiB
Objective-C

//
// NSInvocation+EXT.m
// extobjc
//
// Created by Justin Spahr-Summers on 2011-03-11.
// Copyright (C) 2012 Justin Spahr-Summers.
// Released under the MIT license.
//
#import "NSInvocation+EXT.h"
typedef struct { int i; } *empty_struct_ptr_t;
typedef union { int i; } *empty_union_ptr_t;
@implementation NSInvocation (EXTExtensions)
- (BOOL)setArgumentsFromArgumentList:(va_list)args {
NSMethodSignature *signature = [self methodSignature];
NSUInteger count = [signature numberOfArguments];
for (NSUInteger i = 2;i < count;++i) {
const char *type = [signature getArgumentTypeAtIndex:i];
while (
*type == 'r' ||
*type == 'n' ||
*type == 'N' ||
*type == 'o' ||
*type == 'O' ||
*type == 'R' ||
*type == 'V'
) {
++type;
}
switch (*type) {
case 'c':
{
char val = (char)va_arg(args, int);
[self setArgument:&val atIndex:i];
}
break;
case 'i':
{
int val = va_arg(args, int);
[self setArgument:&val atIndex:i];
}
break;
case 's':
{
short val = (short)va_arg(args, int);
[self setArgument:&val atIndex:i];
}
break;
case 'l':
{
long val = va_arg(args, long);
[self setArgument:&val atIndex:i];
}
break;
case 'q':
{
long long val = va_arg(args, long long);
[self setArgument:&val atIndex:i];
}
break;
case 'C':
{
unsigned char val = (unsigned char)va_arg(args, unsigned int);
[self setArgument:&val atIndex:i];
}
break;
case 'I':
{
unsigned int val = va_arg(args, unsigned int);
[self setArgument:&val atIndex:i];
}
break;
case 'S':
{
unsigned short val = (unsigned short)va_arg(args, unsigned int);
[self setArgument:&val atIndex:i];
}
break;
case 'L':
{
unsigned long val = va_arg(args, unsigned long);
[self setArgument:&val atIndex:i];
}
break;
case 'Q':
{
unsigned long long val = va_arg(args, unsigned long long);
[self setArgument:&val atIndex:i];
}
break;
case 'f':
{
float val = (float)va_arg(args, double);
[self setArgument:&val atIndex:i];
}
break;
case 'd':
{
double val = va_arg(args, double);
[self setArgument:&val atIndex:i];
}
break;
case 'B':
{
_Bool val = (_Bool)va_arg(args, int);
[self setArgument:&val atIndex:i];
}
break;
case '*':
{
char *val = va_arg(args, char *);
[self setArgument:&val atIndex:i];
}
break;
case '@':
{
__unsafe_unretained id val = va_arg(args, id);
[self setArgument:&val atIndex:i];
if (type[1] == '?') {
// @? is undocumented, but apparently used to represent
// a block -- not sure how to disambiguate it from
// a separate @ and ?, but I assume that a block parameter
// is a more common case than that
++type;
}
}
break;
case '#':
{
Class val = va_arg(args, Class);
[self setArgument:&val atIndex:i];
}
break;
case ':':
{
SEL val = va_arg(args, SEL);
[self setArgument:&val atIndex:i];
}
break;
case '[':
NSLog(@"Unexpected array within method argument type code \"%s\", cannot set invocation argument!", type);
return NO;
case 'b':
NSLog(@"Unexpected bitfield within method argument type code \"%s\", cannot set invocation argument!", type);
return NO;
case '{':
NSLog(@"Cannot get variable argument for a method that takes a struct argument!");
return NO;
case '(':
NSLog(@"Cannot get variable argument for a method that takes a union argument!");
return NO;
case '^':
switch (type[1]) {
case 'c':
case 'C':
{
char *val = va_arg(args, char *);
[self setArgument:&val atIndex:i];
}
break;
case 'i':
case 'I':
{
int *val = va_arg(args, int *);
[self setArgument:&val atIndex:i];
}
break;
case 's':
case 'S':
{
short *val = va_arg(args, short *);
[self setArgument:&val atIndex:i];
}
break;
case 'l':
case 'L':
{
long *val = va_arg(args, long *);
[self setArgument:&val atIndex:i];
}
break;
case 'q':
case 'Q':
{
long long *val = va_arg(args, long long *);
[self setArgument:&val atIndex:i];
}
break;
case 'f':
{
float *val = va_arg(args, float *);
[self setArgument:&val atIndex:i];
}
break;
case 'd':
{
double *val = va_arg(args, double *);
[self setArgument:&val atIndex:i];
}
break;
case 'B':
{
_Bool *val = va_arg(args, _Bool *);
[self setArgument:&val atIndex:i];
}
break;
case 'v':
{
void *val = va_arg(args, void *);
[self setArgument:&val atIndex:i];
}
break;
case '*':
case '@':
case '#':
case '^':
case '[':
{
void **val = va_arg(args, void **);
[self setArgument:&val atIndex:i];
}
break;
case ':':
{
SEL *val = va_arg(args, SEL *);
[self setArgument:&val atIndex:i];
}
break;
case '{':
{
empty_struct_ptr_t val = va_arg(args, empty_struct_ptr_t);
[self setArgument:&val atIndex:i];
}
break;
case '(':
{
empty_union_ptr_t val = va_arg(args, empty_union_ptr_t);
[self setArgument:&val atIndex:i];
}
break;
case '?':
{
// assume that this is a pointer to a function pointer
//
// even if it's not, the fact that it's
// a pointer-to-something gives us a good chance of not
// causing alignment or size problems
IMP *ptr = va_arg(args, IMP *);
[self setArgument:&ptr atIndex:i];
}
break;
case 'b':
default:
NSLog(@"Pointer to unexpected type within method argument type code \"%s\", cannot set method invocation!", type);
return NO;
}
break;
case '?':
{
// this is PROBABLY a function pointer, but the documentation
// leaves room open for uncertainty, so at least log a message
NSLog(@"Assuming method argument type code \"%s\" is a function pointer", type);
IMP ptr = va_arg(args, IMP);
[self setArgument:&ptr atIndex:i];
}
break;
default:
NSLog(@"Unexpected method argument type code \"%s\", cannot set method invocation!", type);
return NO;
}
}
return YES;
}
@end