-
Notifications
You must be signed in to change notification settings - Fork 28
/
CDBalanceFormatter.m
97 lines (75 loc) · 2.96 KB
/
CDBalanceFormatter.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// -*- mode: ObjC -*-
// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
// Copyright (C) 1997-2019 Steve Nygard.
#import "CDBalanceFormatter.h"
static BOOL debug = NO;
@implementation CDBalanceFormatter
{
NSScanner *_scanner;
NSCharacterSet *_openCloseSet;
NSMutableString *_result;
}
- (id)initWithString:(NSString *)str;
{
if ((self = [super init])) {
_scanner = [[NSScanner alloc] initWithString:str];
_openCloseSet = [NSCharacterSet characterSetWithCharactersInString:@"{}<>()"];
_result = [[NSMutableString alloc] init];
}
return self;
}
#pragma mark -
- (void)parse:(NSString *)open index:(NSUInteger)openIndex level:(NSUInteger)level;
{
NSString *opens[] = { @"{", @"<", @"(", nil};
NSString *closes[] = { @"}", @">", @")", nil};
BOOL foundOpen = NO;
BOOL foundClose = NO;
while ([_scanner isAtEnd] == NO) {
NSString *pre;
if ([_scanner scanUpToCharactersFromSet:_openCloseSet intoString:&pre]) {
if (debug) NSLog(@"pre = '%@'", pre);
[_result appendFormat:@"%@%@\n", [NSString spacesIndentedToLevel:level], pre];
}
if (debug) NSLog(@"remaining: '%@'", [[_scanner string] substringFromIndex:[_scanner scanLocation]]);
foundOpen = foundClose = NO;
for (NSUInteger index = 0; index < 3; index++) {
if (debug) NSLog(@"Checking open %lu: '%@'", index, opens[index]);
if ([_scanner scanString:opens[index] intoString:NULL]) {
if (debug) NSLog(@"Start %@", opens[index]);
[_result appendSpacesIndentedToLevel:level];
[_result appendString:opens[index]];
[_result appendString:@"\n"];
[self parse:opens[index] index:[_scanner scanLocation] - 1 level:level + 1];
[_result appendSpacesIndentedToLevel:level];
[_result appendString:closes[index]];
[_result appendString:@"\n"];
foundOpen = YES;
break;
}
if (debug) NSLog(@"Checking close %lu: '%@'", index, closes[index]);
if ([_scanner scanString:closes[index] intoString:NULL]) {
if ([open isEqualToString:opens[index]]) {
if (debug) NSLog(@"End %@", closes[index]);
} else {
NSLog(@"ERROR: Unmatched end %@", closes[index]);
}
foundClose = YES;
break;
}
}
if (foundOpen == NO && foundClose == NO) {
if (debug) NSLog(@"Unknown @ %lu: %@", [_scanner scanLocation], [[_scanner string] substringFromIndex:[_scanner scanLocation]]);
break;
}
if (foundClose)
break;
}
}
- (NSString *)format;
{
[self parse:nil index:0 level:0];
if (debug) NSLog(@"result:\n%@", _result);
return [NSString stringWithString:_result];
}
@end