mirror of
https://github.com/samsonjs/samhuri.net-ios.git
synced 2026-03-25 09:25:47 +00:00
350 lines
9.5 KiB
Objective-C
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
|