Add support for function return breakpoints.
[macgdbp.git] / Source / Breakpoint.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "Breakpoint.h"
18
19 #import "PreferenceNames.h"
20
21 NSString* const kBreakpointTypeFile = @"line";
22 NSString* const kBreakpointTypeFunctionEntry = @"call";
23 NSString* const kBreakpointTypeFunctionReturn = @"return";
24
25 @implementation Breakpoint {
26 NSString* _type; // weak
27 unsigned long _debuggerId;
28
29 NSString* _file;
30
31 NSString* _functionName;
32 }
33
34 + (instancetype)breakpointAtLine:(unsigned long)line inFile:(NSString*)file
35 {
36 Breakpoint* breakpoint = [[[Breakpoint alloc] init] autorelease];
37 breakpoint->_type = kBreakpointTypeFile;
38 breakpoint->_file = [file copy];
39 breakpoint->_line = line;
40 return breakpoint;
41 }
42
43 + (instancetype)breakpointOnFunctionNamed:(NSString*)name type:(NSString*)type
44 {
45 Breakpoint* breakpoint = [[[Breakpoint alloc] init] autorelease];
46 NSAssert1(type == kBreakpointTypeFunctionEntry || type == kBreakpointTypeFunctionReturn, @"Unexpected breakpoint type: %@", type);
47 breakpoint->_type = type;
48 breakpoint->_functionName = [name copy];
49 return breakpoint;
50 }
51
52 - (instancetype)initWithDictionary:(NSDictionary*)dict
53 {
54 if ((self = [super init])) {
55 NSString* type = [dict valueForKey:@"type"];
56 if (!type || [type isEqualToString:kBreakpointTypeFile]) {
57 _type = kBreakpointTypeFile;
58 _file = [[dict valueForKey:@"file"] copy];
59 _line = [[dict valueForKey:@"line"] intValue];
60 } else if ([type isEqualToString:kBreakpointTypeFunctionEntry]) {
61 _type = kBreakpointTypeFunctionEntry;
62 _functionName = [[dict valueForKey:@"function"] copy];
63 } else if ([type isEqualToString:kBreakpointTypeFunctionReturn]) {
64 _type = kBreakpointTypeFunctionReturn;
65 _functionName = [[dict valueForKey:@"function"] copy];
66 } else {
67 [NSException raise:NSInvalidArgumentException
68 format:@"Unknown Breakpoint type: %@", type];
69 }
70 }
71 return self;
72 }
73
74 - (void)dealloc
75 {
76 [_file release];
77 [_functionName release];
78 [super dealloc];
79 }
80
81 /**
82 * Returns the string to display in the breakpoints list.
83 */
84 - (NSString*)displayValue
85 {
86 if (self.type == kBreakpointTypeFile) {
87 return [NSString stringWithFormat:@"%@:%ld", self.file, self.line];
88 } else if (self.type == kBreakpointTypeFunctionEntry ||
89 self.type == kBreakpointTypeFunctionReturn) {
90 return [NSString stringWithFormat:@"%@()", self.functionName];
91 }
92 return nil;
93 }
94
95 /**
96 * Returns the transformed path for the breakpoint, as Xdebug needs it
97 */
98 - (NSString*)transformedPath
99 {
100 NSString* path = self.file;
101
102 NSMutableArray* transforms = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:kPrefPathReplacements];
103 if (!transforms || [transforms count] < 1)
104 return path;
105
106 for (NSDictionary* replacement in transforms)
107 {
108 path = [path
109 stringByReplacingOccurrencesOfString:[replacement valueForKey:@"local"]
110 withString:[replacement valueForKey:@"remote"]
111 ];
112 }
113
114 return path;
115 }
116
117 - (BOOL)isEqual:(id)obj
118 {
119 if (![obj isKindOfClass:[self class]]) {
120 return NO;
121 }
122
123 Breakpoint* other = obj;
124 if (self.type != other.type) {
125 return NO;
126 }
127
128 if (self.type == kBreakpointTypeFile) {
129 return [self.file isEqualToString:other.file] && self.line == other.line;
130 } else if (self.type == kBreakpointTypeFunctionEntry ||
131 self.type == kBreakpointTypeFunctionReturn) {
132 return [self.functionName isEqualToString:other.functionName];
133 }
134
135 return NO;
136 }
137
138 - (NSDictionary*)dictionary
139 {
140 if (self.type == kBreakpointTypeFile) {
141 return @{
142 @"type" : self.type,
143 @"file" : self.file,
144 @"line" : @(self.line)
145 };
146 } else if (self.type == kBreakpointTypeFunctionEntry ||
147 self.type == kBreakpointTypeFunctionReturn) {
148 return @{
149 @"type" : self.type,
150 @"function" : self.functionName
151 };
152 }
153 return nil;
154 }
155
156 - (NSString*)description
157 {
158 return [NSString stringWithFormat:@"Breakpoint %@", [[self dictionary] description]];
159 }
160
161 @end