| Index: class-dump/src/CDTypeFormatter.m
|
| ===================================================================
|
| --- class-dump/src/CDTypeFormatter.m (revision 0)
|
| +++ class-dump/src/CDTypeFormatter.m (revision 0)
|
| @@ -0,0 +1,377 @@
|
| +// -*- mode: ObjC -*-
|
| +
|
| +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
|
| +// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard.
|
| +
|
| +#import "CDTypeFormatter.h"
|
| +
|
| +#include <assert.h>
|
| +#import "NSError-CDExtensions.h"
|
| +#import "NSScanner-Extensions.h"
|
| +#import "NSString-Extensions.h"
|
| +#import "CDClassDump.h" // not ideal
|
| +#import "CDMethodType.h"
|
| +#import "CDSymbolReferences.h"
|
| +#import "CDType.h"
|
| +#import "CDTypeLexer.h"
|
| +#import "CDTypeParser.h"
|
| +#import "CDTypeController.h"
|
| +
|
| +static BOOL debug = NO;
|
| +
|
| +@implementation CDTypeFormatter
|
| +
|
| +- (id)init;
|
| +{
|
| + if ([super init] == nil)
|
| + return nil;
|
| +
|
| + nonretained_typeController = nil;
|
| +
|
| + flags.shouldExpand = NO;
|
| + flags.shouldAutoExpand = NO;
|
| + flags.shouldShowLexing = debug;
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (CDTypeController *)typeController;
|
| +{
|
| + return nonretained_typeController;
|
| +}
|
| +
|
| +- (void)setTypeController:(CDTypeController *)newTypeController;
|
| +{
|
| + nonretained_typeController = newTypeController;
|
| +}
|
| +
|
| +@synthesize baseLevel;
|
| +
|
| +- (BOOL)shouldExpand;
|
| +{
|
| + return flags.shouldExpand;
|
| +}
|
| +
|
| +- (void)setShouldExpand:(BOOL)newFlag;
|
| +{
|
| + flags.shouldExpand = newFlag;
|
| +}
|
| +
|
| +- (BOOL)shouldAutoExpand;
|
| +{
|
| + return flags.shouldAutoExpand;
|
| +}
|
| +
|
| +- (void)setShouldAutoExpand:(BOOL)newFlag;
|
| +{
|
| + flags.shouldAutoExpand = newFlag;
|
| +}
|
| +
|
| +- (BOOL)shouldShowLexing;
|
| +{
|
| + return flags.shouldShowLexing;
|
| +}
|
| +
|
| +- (void)setShouldShowLexing:(BOOL)newFlag;
|
| +{
|
| + flags.shouldShowLexing = newFlag;
|
| +}
|
| +
|
| +- (NSString *)_specialCaseVariable:(NSString *)name type:(NSString *)type;
|
| +{
|
| + if ([type isEqual:@"c"]) {
|
| + if (name == nil)
|
| + return @"BOOL";
|
| + else
|
| + return [NSString stringWithFormat:@"BOOL %@", name];
|
| +#if 0
|
| + } else if ([type isEqual:@"b1"]) {
|
| + if (name == nil)
|
| + return @"BOOL :1";
|
| + else
|
| + return [NSString stringWithFormat:@"BOOL %@:1", name];
|
| +#endif
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (NSString *)_specialCaseVariable:(NSString *)name parsedType:(CDType *)type;
|
| +{
|
| + if ([type type] == 'c') {
|
| + if (name == nil)
|
| + return @"BOOL";
|
| + else
|
| + return [NSString stringWithFormat:@"BOOL %@", name];
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +// TODO (2004-01-28): See if we can pass in the actual CDType.
|
| +// TODO (2009-07-09): Now that we have the other method, see if we can use it instead.
|
| +- (NSString *)formatVariable:(NSString *)name type:(NSString *)type symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + NSString *specialCase;
|
| + CDTypeParser *aParser;
|
| + CDType *resultType;
|
| + NSError *error;
|
| +
|
| + // Special cases: char -> BOOLs, 1 bit ints -> BOOL too?
|
| + specialCase = [self _specialCaseVariable:name type:type];
|
| + if (specialCase != nil) {
|
| + NSMutableString *resultString;
|
| +
|
| + resultString = [NSMutableString string];
|
| + [resultString appendString:[NSString spacesIndentedToLevel:baseLevel spacesPerLevel:4]];
|
| + [resultString appendString:specialCase];
|
| +
|
| + return resultString;
|
| + }
|
| +
|
| + aParser = [[CDTypeParser alloc] initWithType:type];
|
| + [[aParser lexer] setShouldShowLexing:flags.shouldShowLexing];
|
| + resultType = [aParser parseType:&error];
|
| + //NSLog(@"resultType: %p", resultType);
|
| +
|
| + if (resultType == nil) {
|
| + NSLog(@"Couldn't parse type: %@", [error myExplanation]);
|
| + [aParser release];
|
| + //NSLog(@"< %s", _cmd);
|
| + return nil;
|
| + }
|
| +
|
| + [aParser release];
|
| +
|
| + return [self formatVariable:name parsedType:resultType symbolReferences:symbolReferences];
|
| +}
|
| +
|
| +- (NSString *)formatVariable:(NSString *)name parsedType:(CDType *)type symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + NSString *specialCase;
|
| + NSMutableString *resultString;
|
| +
|
| + resultString = [NSMutableString string];
|
| +
|
| + specialCase = [self _specialCaseVariable:name parsedType:type];
|
| + [resultString appendSpacesIndentedToLevel:baseLevel spacesPerLevel:4];
|
| + if (specialCase != nil) {
|
| + [resultString appendString:specialCase];
|
| + } else {
|
| + // TODO (2009-08-26): Ideally, just formatting a type shouldn't change it. These changes should be done before, but this is handy.
|
| + [type setVariableName:name];
|
| + [type phase0RecursivelyFixStructureNames:NO]; // Nuke the $_ names
|
| + [type phase3MergeWithTypeController:[self typeController]];
|
| + [resultString appendString:[type formattedString:nil formatter:self level:0 symbolReferences:symbolReferences]];
|
| + }
|
| +
|
| + return resultString;
|
| +}
|
| +
|
| +- (NSDictionary *)formattedTypesForMethodName:(NSString *)methodName type:(NSString *)type symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + CDTypeParser *aParser;
|
| + NSArray *methodTypes;
|
| + NSError *error;
|
| + NSMutableDictionary *typeDict;
|
| + NSMutableArray *parameterTypes;
|
| +
|
| + aParser = [[CDTypeParser alloc] initWithType:type];
|
| + methodTypes = [aParser parseMethodType:&error];
|
| + if (methodTypes == nil)
|
| + NSLog(@"Warning: Parsing method types failed, %@", methodName);
|
| + [aParser release];
|
| +
|
| + if (methodTypes == nil || [methodTypes count] == 0) {
|
| + return nil;
|
| + }
|
| +
|
| + typeDict = [NSMutableDictionary dictionary];
|
| + {
|
| + NSUInteger count, index;
|
| + BOOL noMoreTypes;
|
| + CDMethodType *aMethodType;
|
| + NSScanner *scanner;
|
| + NSString *specialCase;
|
| +
|
| + count = [methodTypes count];
|
| + index = 0;
|
| + noMoreTypes = NO;
|
| +
|
| + aMethodType = [methodTypes objectAtIndex:index];
|
| + specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] bareTypeString]];
|
| + if (specialCase != nil) {
|
| + [typeDict setValue:specialCase forKey:@"return-type"];
|
| + } else {
|
| + NSString *str;
|
| +
|
| + str = [[aMethodType type] formattedString:nil formatter:self level:0 symbolReferences:symbolReferences];
|
| + if (str != nil)
|
| + [typeDict setValue:str forKey:@"return-type"];
|
| + }
|
| +
|
| + index += 3;
|
| +
|
| + parameterTypes = [NSMutableArray array];
|
| + [typeDict setValue:parameterTypes forKey:@"parametertypes"];
|
| +
|
| + scanner = [[NSScanner alloc] initWithString:methodName];
|
| + while ([scanner isAtEnd] == NO) {
|
| + NSString *str;
|
| +
|
| + // We can have unnamed parameters, :::
|
| + if ([scanner scanUpToString:@":" intoString:&str]) {
|
| + //NSLog(@"str += '%@'", str);
|
| +// int unnamedCount, unnamedIndex;
|
| +// unnamedCount = [str length];
|
| +// for (unnamedIndex = 0; unnamedIndex < unnamedCount; unnamedIndex++)
|
| +// [parameterTypes addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"", @"type", @"", @"name", nil]];
|
| + }
|
| + if ([scanner scanString:@":" intoString:NULL]) {
|
| + NSString *typeString;
|
| +
|
| + if (index >= count) {
|
| + noMoreTypes = YES;
|
| + } else {
|
| + NSMutableDictionary *parameter = [NSMutableDictionary dictionary];
|
| +
|
| + aMethodType = [methodTypes objectAtIndex:index];
|
| + specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] bareTypeString]];
|
| + if (specialCase != nil) {
|
| + [parameter setValue:specialCase forKey:@"type"];
|
| + } else {
|
| + typeString = [[aMethodType type] formattedString:nil formatter:self level:0 symbolReferences:symbolReferences];
|
| + [parameter setValue:typeString forKey:@"type"];
|
| + }
|
| + //[parameter setValue:[NSString stringWithFormat:@"fp%@", [aMethodType offset]] forKey:@"name"];
|
| + [parameter setValue:[NSString stringWithFormat:@"arg%u", index-2] forKey:@"name"];
|
| + [parameterTypes addObject:parameter];
|
| + index++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + [scanner release];
|
| +
|
| + if (noMoreTypes) {
|
| + NSLog(@" /* Error: Ran out of types for this method. */");
|
| + }
|
| + }
|
| +
|
| + return typeDict;
|
| +}
|
| +
|
| +- (NSString *)formatMethodName:(NSString *)methodName type:(NSString *)type symbolReferences:(CDSymbolReferences *)symbolReferences;
|
| +{
|
| + CDTypeParser *aParser;
|
| + NSArray *methodTypes;
|
| + NSMutableString *resultString;
|
| + NSError *error;
|
| +
|
| + aParser = [[CDTypeParser alloc] initWithType:type];
|
| + methodTypes = [aParser parseMethodType:&error];
|
| + if (methodTypes == nil)
|
| + NSLog(@"Warning: Parsing method types failed, %@", methodName);
|
| + [aParser release];
|
| +
|
| + if (methodTypes == nil || [methodTypes count] == 0) {
|
| + return nil;
|
| + }
|
| +
|
| + resultString = [NSMutableString string];
|
| + {
|
| + NSUInteger count, index;
|
| + BOOL noMoreTypes;
|
| + CDMethodType *aMethodType;
|
| + NSScanner *scanner;
|
| + NSString *specialCase;
|
| +
|
| + count = [methodTypes count];
|
| + index = 0;
|
| + noMoreTypes = NO;
|
| +
|
| + aMethodType = [methodTypes objectAtIndex:index];
|
| + [resultString appendString:@"("];
|
| + specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] bareTypeString]];
|
| + if (specialCase != nil) {
|
| + [resultString appendString:specialCase];
|
| + } else {
|
| + NSString *str;
|
| +
|
| + str = [[aMethodType type] formattedString:nil formatter:self level:0 symbolReferences:symbolReferences];
|
| + if (str != nil)
|
| + [resultString appendFormat:@"%@", str];
|
| + }
|
| + [resultString appendString:@")"];
|
| +
|
| + index += 3;
|
| +
|
| + scanner = [[NSScanner alloc] initWithString:methodName];
|
| + while ([scanner isAtEnd] == NO) {
|
| + NSString *str;
|
| +
|
| + // We can have unnamed paramenters, :::
|
| + if ([scanner scanUpToString:@":" intoString:&str]) {
|
| + //NSLog(@"str += '%@'", str);
|
| + [resultString appendString:str];
|
| + }
|
| + if ([scanner scanString:@":" intoString:NULL]) {
|
| + NSString *typeString;
|
| +
|
| + [resultString appendString:@":"];
|
| + if (index >= count) {
|
| + noMoreTypes = YES;
|
| + } else {
|
| + NSString *ch;
|
| +
|
| + aMethodType = [methodTypes objectAtIndex:index];
|
| + specialCase = [self _specialCaseVariable:nil type:[[aMethodType type] bareTypeString]];
|
| + if (specialCase != nil) {
|
| + [resultString appendFormat:@"(%@)", specialCase];
|
| + } else {
|
| + typeString = [[aMethodType type] formattedString:nil formatter:self level:0 symbolReferences:symbolReferences];
|
| + //if ([[aMethodType type] isIDType] == NO)
|
| + [resultString appendFormat:@"(%@)", typeString];
|
| + }
|
| + //[resultString appendFormat:@"fp%@", [aMethodType offset]];
|
| + [resultString appendFormat:@"arg%u", index-2];
|
| +
|
| + ch = [scanner peekCharacter];
|
| + // if next character is not ':' nor EOS then add space
|
| + if (ch != nil && [ch isEqual:@":"] == NO)
|
| + [resultString appendString:@" "];
|
| + index++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + [scanner release];
|
| +
|
| + if (noMoreTypes) {
|
| + [resultString appendString:@" /* Error: Ran out of types for this method. */"];
|
| + }
|
| + }
|
| +
|
| + return resultString;
|
| +}
|
| +
|
| +// Called from CDType, which gets a formatter but not a type controller.
|
| +- (CDType *)replacementForType:(CDType *)aType;
|
| +{
|
| + return [nonretained_typeController typeFormatter:self replacementForType:aType];
|
| +}
|
| +
|
| +// Called from CDType, which gets a formatter but not a type controller.
|
| +- (NSString *)typedefNameForStruct:(CDType *)structType level:(NSUInteger)level;
|
| +{
|
| + return [nonretained_typeController typeFormatter:self typedefNameForStruct:structType level:level];
|
| +}
|
| +
|
| +- (NSString *)description;
|
| +{
|
| + return [NSString stringWithFormat:@"<%@:%p> baseLevel: %u, shouldExpand: %u, shouldAutoExpand: %u, shouldShowLexing: %u, tc: %p",
|
| + NSStringFromClass([self class]), self,
|
| + baseLevel, flags.shouldExpand, flags.shouldAutoExpand, flags.shouldShowLexing, nonretained_typeController];
|
| +}
|
| +
|
| +@end
|
|
|
| Property changes on: class-dump/src/CDTypeFormatter.m
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|