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 '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 338