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 [NSNumber numberWithInt:value]; 43 } 44 case 's': 45 { 46 short value; 47 [self getArgument:&value atIndex:argIndex]; 48 return [NSNumber numberWithShort:value]; 49 } 50 case 'l': 51 { 52 long value; 53 [self getArgument:&value atIndex:argIndex]; 54 return [NSNumber numberWithLong:value]; 55 } 56 case 'q': 57 { 58 long long value; 59 [self getArgument:&value atIndex:argIndex]; 60 return [NSNumber numberWithLongLong:value]; 61 } 62 case 'c': 63 { 64 char value; 65 [self getArgument:&value atIndex:argIndex]; 66 return [NSNumber numberWithChar:value]; 67 } 68 case 'C': 69 { 70 unsigned char value; 71 [self getArgument:&value atIndex:argIndex]; 72 return [NSNumber numberWithUnsignedChar:value]; 73 } 74 case 'I': 75 { 76 unsigned int value; 77 [self getArgument:&value atIndex:argIndex]; 78 return [NSNumber numberWithUnsignedInt:value]; 79 } 80 case 'S': 81 { 82 unsigned short value; 83 [self getArgument:&value atIndex:argIndex]; 84 return [NSNumber numberWithUnsignedShort:value]; 85 } 86 case 'L': 87 { 88 unsigned long value; 89 [self getArgument:&value atIndex:argIndex]; 90 return [NSNumber numberWithUnsignedLong:value]; 91 } 92 case 'Q': 93 { 94 unsigned long long value; 95 [self getArgument:&value atIndex:argIndex]; 96 return [NSNumber numberWithUnsignedLongLong:value]; 97 } 98 case 'f': 99 { 100 float value; 101 [self getArgument:&value atIndex:argIndex]; 102 return [NSNumber numberWithFloat:value]; 103 } 104 case 'd': 105 { 106 double value; 107 [self getArgument:&value atIndex:argIndex]; 108 return [NSNumber numberWithDouble:value]; 109 } 110 case 'B': 111 { 112 bool value; 113 [self getArgument:&value atIndex:argIndex]; 114 return [NSNumber numberWithBool: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 objectAtIndex:(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 'B': return [self boolDescriptionAtIndex:argIndex]; 165 case 'c': return [self charDescriptionAtIndex:argIndex]; 166 case 'C': return [self unsignedCharDescriptionAtIndex:argIndex]; 167 case 'i': return [self intDescriptionAtIndex:argIndex]; 168 case 'I': return [self unsignedIntDescriptionAtIndex:argIndex]; 169 case 's': return [self shortDescriptionAtIndex:argIndex]; 170 case 'S': return [self unsignedShortDescriptionAtIndex:argIndex]; 171 case 'l': return [self longDescriptionAtIndex:argIndex]; 172 case 'L': return [self unsignedLongDescriptionAtIndex:argIndex]; 173 case 'q': return [self longLongDescriptionAtIndex:argIndex]; 174 case 'Q': return [self unsignedLongLongDescriptionAtIndex:argIndex]; 175 case 'd': return [self doubleDescriptionAtIndex:argIndex]; 176 case 'f': return [self floatDescriptionAtIndex:argIndex]; 177 // Why does this throw EXC_BAD_ACCESS when appending the string? 178 // case NSObjCStructType: return [self structDescriptionAtIndex:index]; 179 case '^': return [self pointerDescriptionAtIndex:argIndex]; 180 case '*': return [self cStringDescriptionAtIndex:argIndex]; 181 case ':': return [self selectorDescriptionAtIndex:argIndex]; 182 default: return [@"<??" stringByAppendingString:@">"]; // avoid confusion with trigraphs... 183 } 184 185 } 186 187 188 - (NSString *)objectDescriptionAtIndex:(int)anInt 189 { 190 id object; 191 192 [self getArgument:&object atIndex:anInt]; 193 if (object == nil) 194 return @"nil"; 195 else if(![object isProxy] && [object isKindOfClass:[NSString class]]) 196 return [NSString stringWithFormat:@"@\"%@\"", [object description]]; 197 else 198 return [object description]; 199 } 200 201 - (NSString *)boolDescriptionAtIndex:(int)anInt 202 { 203 bool value; 204 205 [self getArgument:&value atIndex:anInt]; 206 return value ? @"YES" : @"NO"; 207 } 208 209 - (NSString *)charDescriptionAtIndex:(int)anInt 210 { 211 unsigned char buffer[128]; 212 memset(buffer, 0x0, 128); 213 214 [self getArgument:&buffer atIndex:anInt]; 215 216 // If there's only one character in the buffer, and it's 0 or 1, then we have a BOOL 217 if (buffer[1] == '\0' && (buffer[0] == 0 || buffer[0] == 1)) 218 return [NSString stringWithFormat:@"%@", (buffer[0] == 1 ? @"YES" : @"NO")]; 219 else 220 return [NSString stringWithFormat:@"'%c'", *buffer]; 221 } 222 223 - (NSString *)unsignedCharDescriptionAtIndex:(int)anInt 224 { 225 unsigned char buffer[128]; 226 memset(buffer, 0x0, 128); 227 228 [self getArgument:&buffer atIndex:anInt]; 229 return [NSString stringWithFormat:@"'%c'", *buffer]; 230 } 231 232 - (NSString *)intDescriptionAtIndex:(int)anInt 233 { 234 int intValue; 235 236 [self getArgument:&intValue atIndex:anInt]; 237 return [NSString stringWithFormat:@"%d", intValue]; 238 } 239 240 - (NSString *)unsignedIntDescriptionAtIndex:(int)anInt 241 { 242 unsigned int intValue; 243 244 [self getArgument:&intValue atIndex:anInt]; 245 return [NSString stringWithFormat:@"%d", intValue]; 246 } 247 248 - (NSString *)shortDescriptionAtIndex:(int)anInt 249 { 250 short shortValue; 251 252 [self getArgument:&shortValue atIndex:anInt]; 253 return [NSString stringWithFormat:@"%hi", shortValue]; 254 } 255 256 - (NSString *)unsignedShortDescriptionAtIndex:(int)anInt 257 { 258 unsigned short shortValue; 259 260 [self getArgument:&shortValue atIndex:anInt]; 261 return [NSString stringWithFormat:@"%hu", shortValue]; 262 } 263 264 - (NSString *)longDescriptionAtIndex:(int)anInt 265 { 266 long longValue; 267 268 [self getArgument:&longValue atIndex:anInt]; 269 return [NSString stringWithFormat:@"%ld", longValue]; 270 } 271 272 - (NSString *)unsignedLongDescriptionAtIndex:(int)anInt 273 { 274 unsigned long longValue; 275 276 [self getArgument:&longValue atIndex:anInt]; 277 return [NSString stringWithFormat:@"%lu", longValue]; 278 } 279 280 - (NSString *)longLongDescriptionAtIndex:(int)anInt 281 { 282 long long longLongValue; 283 284 [self getArgument:&longLongValue atIndex:anInt]; 285 return [NSString stringWithFormat:@"%qi", longLongValue]; 286 } 287 288 - (NSString *)unsignedLongLongDescriptionAtIndex:(int)anInt 289 { 290 unsigned long long longLongValue; 291 292 [self getArgument:&longLongValue atIndex:anInt]; 293 return [NSString stringWithFormat:@"%qu", longLongValue]; 294 } 295 296 - (NSString *)doubleDescriptionAtIndex:(int)anInt; 297 { 298 double doubleValue; 299 300 [self getArgument:&doubleValue atIndex:anInt]; 301 return [NSString stringWithFormat:@"%f", doubleValue]; 302 } 303 304 - (NSString *)floatDescriptionAtIndex:(int)anInt 305 { 306 float floatValue; 307 308 [self getArgument:&floatValue atIndex:anInt]; 309 return [NSString stringWithFormat:@"%f", floatValue]; 310 } 311 312 - (NSString *)structDescriptionAtIndex:(int)anInt; 313 { 314 void *buffer; 315 316 [self getArgument:&buffer atIndex:anInt]; 317 return [NSString stringWithFormat:@":(struct)%p", buffer]; 318 } 319 320 - (NSString *)pointerDescriptionAtIndex:(int)anInt 321 { 322 void *buffer; 323 324 [self getArgument:&buffer atIndex:anInt]; 325 return [NSString stringWithFormat:@"%p", buffer]; 326 } 327 328 - (NSString *)cStringDescriptionAtIndex:(int)anInt 329 { 330 char buffer[128]; 331 332 memset(buffer, 0x0, 128); 333 334 [self getArgument:&buffer atIndex:anInt]; 335 return [NSString stringWithFormat:@"\"%s\"", buffer]; 336 } 337 338 - (NSString *)selectorDescriptionAtIndex:(int)anInt 339 { 340 SEL selectorValue; 341 342 [self getArgument:&selectorValue atIndex:anInt]; 343 return [NSString stringWithFormat:@"@selector(%@)", NSStringFromSelector(selectorValue)]; 344 } 345 346 @end 347