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