main
  1//---------------------------------------------------------------------------------------
  2//  $Id$
  3//  Copyright (c) 2006-2009 by Mulle Kybernetik. See License file for details.
  4//---------------------------------------------------------------------------------------
  5
  6#import "NSInvocation+OCMAdditions.h"
  7
  8
  9@implementation NSInvocation(OCMAdditions)
 10
 11- (id)getArgumentAtIndexAsObject:(int)argIndex
 12{
 13	const char* argType;
 14	
 15	argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
 16	while(strchr("rnNoORV", argType[0]) != NULL)
 17		argType += 1;
 18	
 19	if((strlen(argType) > 1) && (strchr("{^", argType[0]) == NULL) && (strcmp("@?", argType) != 0))
 20		[NSException raise:NSInvalidArgumentException format:@"Cannot handle argument type '%s'.", argType];
 21	
 22	switch (argType[0]) 
 23	{
 24		case '#':
 25		case '@': 
 26		{
 27			id value;
 28			[self getArgument:&value atIndex:argIndex];
 29			return value;
 30		}
 31		case ':':
 32 		{
 33 			SEL s = (SEL)0;
 34 			[self getArgument:&s atIndex:argIndex];
 35 			id value = NSStringFromSelector(s);
 36 			return value;
 37 		}
 38		case 'i': 
 39		{
 40			int value;
 41			[self getArgument:&value atIndex:argIndex];
 42			return @(value);
 43		}	
 44		case 's':
 45		{
 46			short value;
 47			[self getArgument:&value atIndex:argIndex];
 48			return @(value);
 49		}	
 50		case 'l':
 51		{
 52			long value;
 53			[self getArgument:&value atIndex:argIndex];
 54			return @(value);
 55		}	
 56		case 'q':
 57		{
 58			long long value;
 59			[self getArgument:&value atIndex:argIndex];
 60			return @(value);
 61		}	
 62		case 'c':
 63		{
 64			char value;
 65			[self getArgument:&value atIndex:argIndex];
 66			return @(value);
 67		}	
 68		case 'C':
 69		{
 70			unsigned char value;
 71			[self getArgument:&value atIndex:argIndex];
 72			return @(value);
 73		}	
 74		case 'I':
 75		{
 76			unsigned int value;
 77			[self getArgument:&value atIndex:argIndex];
 78			return @(value);
 79		}	
 80		case 'S':
 81		{
 82			unsigned short value;
 83			[self getArgument:&value atIndex:argIndex];
 84			return @(value);
 85		}	
 86		case 'L':
 87		{
 88			unsigned long value;
 89			[self getArgument:&value atIndex:argIndex];
 90			return @(value);
 91		}	
 92		case 'Q':
 93		{
 94			unsigned long long value;
 95			[self getArgument:&value atIndex:argIndex];
 96			return @(value);
 97		}	
 98		case 'f':
 99		{
100			float value;
101			[self getArgument:&value atIndex:argIndex];
102			return @(value);
103		}	
104		case 'd':
105		{
106			double value;
107			[self getArgument:&value atIndex:argIndex];
108			return @(value);
109		}	
110		case 'B':
111		{
112			bool value;
113			[self getArgument:&value atIndex:argIndex];
114			return @(value);
115		}
116		case '^':
117        {
118            void *value = NULL;
119            [self getArgument:&value atIndex:argIndex];
120            return [NSValue valueWithPointer:value];
121        }
122		case '{': // structure
123		{
124			NSUInteger maxArgSize = [[self methodSignature] frameLength];
125			NSMutableData *argumentData = [[[NSMutableData alloc] initWithLength:maxArgSize] autorelease];
126			[self getArgument:[argumentData mutableBytes] atIndex:argIndex];
127			return [NSValue valueWithBytes:[argumentData bytes] objCType:argType];
128		}       
129			
130	}
131	[NSException raise:NSInvalidArgumentException format:@"Argument type '%s' not supported", argType];
132	return nil;
133}
134
135- (NSString *)invocationDescription
136{
137	NSMethodSignature *methodSignature = [self methodSignature];
138	NSUInteger numberOfArgs = [methodSignature numberOfArguments];
139	
140	if (numberOfArgs == 2)
141		return NSStringFromSelector([self selector]);
142	
143	NSArray *selectorParts = [NSStringFromSelector([self selector]) componentsSeparatedByString:@":"];
144	NSMutableString *description = [[NSMutableString alloc] init];
145	unsigned int i;
146	for(i = 2; i < numberOfArgs; i++)
147	{
148		[description appendFormat:@"%@%@:", (i > 2 ? @" " : @""), selectorParts[(i - 2)]];
149		[description appendString:[self argumentDescriptionAtIndex:i]];
150	}
151	
152	return [description autorelease];
153}
154
155- (NSString *)argumentDescriptionAtIndex:(int)argIndex
156{
157	const char *argType = [[self methodSignature] getArgumentTypeAtIndex:argIndex];
158	if(strchr("rnNoORV", argType[0]) != NULL)
159		argType += 1;
160
161	switch(*argType)
162	{
163		case '@':	return [self objectDescriptionAtIndex:argIndex];
164		case 'c':	return [self charDescriptionAtIndex:argIndex];
165		case 'C':	return [self unsignedCharDescriptionAtIndex:argIndex];
166		case 'i':	return [self intDescriptionAtIndex:argIndex];
167		case 'I':	return [self unsignedIntDescriptionAtIndex:argIndex];
168		case 's':	return [self shortDescriptionAtIndex:argIndex];
169		case 'S':	return [self unsignedShortDescriptionAtIndex:argIndex];
170		case 'l':	return [self longDescriptionAtIndex:argIndex];
171		case 'L':	return [self unsignedLongDescriptionAtIndex:argIndex];
172		case 'q':	return [self longLongDescriptionAtIndex:argIndex];
173		case 'Q':	return [self unsignedLongLongDescriptionAtIndex:argIndex];
174		case 'd':	return [self doubleDescriptionAtIndex:argIndex];
175		case 'f':	return [self floatDescriptionAtIndex:argIndex];
176		// Why does this throw EXC_BAD_ACCESS when appending the string?
177		//	case NSObjCStructType: return [self structDescriptionAtIndex:index];
178		case '^':	return [self pointerDescriptionAtIndex:argIndex];
179		case '*':	return [self cStringDescriptionAtIndex:argIndex];
180		case ':':	return [self selectorDescriptionAtIndex:argIndex];
181		default:	return [@"<??" stringByAppendingString:@">"];  // avoid confusion with trigraphs...
182	}
183	
184}
185
186
187- (NSString *)objectDescriptionAtIndex:(int)anInt
188{
189	id object;
190	
191	[self getArgument:&object atIndex:anInt];
192	if (object == nil)
193		return @"nil";
194	else if(![object isProxy] && [object isKindOfClass:[NSString class]])
195		return [NSString stringWithFormat:@"@\"%@\"", [object description]];
196	else
197		return [object description];
198}
199
200- (NSString *)charDescriptionAtIndex:(int)anInt
201{
202	unsigned char buffer[128];
203	memset(buffer, 0x0, 128);
204	
205	[self getArgument:&buffer atIndex:anInt];
206	
207	// If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL
208	if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1))
209		return [NSString stringWithFormat:@"%@", (buffer[0] == 1 ? @"YES" : @"NO")];
210	else
211		return [NSString stringWithFormat:@"'%c'", *buffer];
212}
213
214- (NSString *)unsignedCharDescriptionAtIndex:(int)anInt
215{
216	unsigned char buffer[128];
217	memset(buffer, 0x0, 128);
218	
219	[self getArgument:&buffer atIndex:anInt];
220	return [NSString stringWithFormat:@"'%c'", *buffer];
221}
222
223- (NSString *)intDescriptionAtIndex:(int)anInt
224{
225	int intValue;
226	
227	[self getArgument:&intValue atIndex:anInt];
228	return [NSString stringWithFormat:@"%d", intValue];
229}
230
231- (NSString *)unsignedIntDescriptionAtIndex:(int)anInt
232{
233	unsigned int intValue;
234	
235	[self getArgument:&intValue atIndex:anInt];
236	return [NSString stringWithFormat:@"%d", intValue];
237}
238
239- (NSString *)shortDescriptionAtIndex:(int)anInt
240{
241	short shortValue;
242	
243	[self getArgument:&shortValue atIndex:anInt];
244	return [NSString stringWithFormat:@"%hi", shortValue];
245}
246
247- (NSString *)unsignedShortDescriptionAtIndex:(int)anInt
248{
249	unsigned short shortValue;
250	
251	[self getArgument:&shortValue atIndex:anInt];
252	return [NSString stringWithFormat:@"%hu", shortValue];
253}
254
255- (NSString *)longDescriptionAtIndex:(int)anInt
256{
257	long longValue;
258	
259	[self getArgument:&longValue atIndex:anInt];
260	return [NSString stringWithFormat:@"%ld", longValue];
261}
262
263- (NSString *)unsignedLongDescriptionAtIndex:(int)anInt
264{
265	unsigned long longValue;
266	
267	[self getArgument:&longValue atIndex:anInt];
268	return [NSString stringWithFormat:@"%lu", longValue];
269}
270
271- (NSString *)longLongDescriptionAtIndex:(int)anInt
272{
273	long long longLongValue;
274	
275	[self getArgument:&longLongValue atIndex:anInt];
276	return [NSString stringWithFormat:@"%qi", longLongValue];
277}
278
279- (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt
280{
281	unsigned long long longLongValue;
282	
283	[self getArgument:&longLongValue atIndex:anInt];
284	return [NSString stringWithFormat:@"%qu", longLongValue];
285}
286
287- (NSString *)doubleDescriptionAtIndex:(int)anInt;
288{
289	double doubleValue;
290	
291	[self getArgument:&doubleValue atIndex:anInt];
292	return [NSString stringWithFormat:@"%f", doubleValue];
293}
294
295- (NSString *)floatDescriptionAtIndex:(int)anInt
296{
297	float floatValue;
298	
299	[self getArgument:&floatValue atIndex:anInt];
300	return [NSString stringWithFormat:@"%f", floatValue];
301}
302
303- (NSString *)structDescriptionAtIndex:(int)anInt;
304{
305	void *buffer;
306	
307	[self getArgument:&buffer atIndex:anInt];
308	return [NSString stringWithFormat:@":(struct)%p", buffer];
309}
310
311- (NSString *)pointerDescriptionAtIndex:(int)anInt
312{
313	void *buffer;
314	
315	[self getArgument:&buffer atIndex:anInt];
316	return [NSString stringWithFormat:@"%p", buffer];
317}
318
319- (NSString *)cStringDescriptionAtIndex:(int)anInt
320{
321	char buffer[128];
322	
323	memset(buffer, 0x0, 128);
324	
325	[self getArgument:&buffer atIndex:anInt];
326	return [NSString stringWithFormat:@"\"%s\"", buffer];
327}
328
329- (NSString *)selectorDescriptionAtIndex:(int)anInt
330{
331	SEL selectorValue;
332	
333	[self getArgument:&selectorValue atIndex:anInt];
334	return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)];
335}
336
337@end