Now that we use NSData, it doesn't make sense to print out the received packet
[macgdbp.git] / Source / DebuggerConnection.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2002 - 2007, 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 "DebuggerConnection.h"
18
19 @implementation DebuggerConnection
20
21 /**
22 * Creates a new DebuggerConnection and initializes the socket from the given connection
23 * paramters.
24 */
25 - (id)initWithPort: (int)port session: (NSString *)session
26 {
27 if (self = [super init])
28 {
29 _port = port;
30 _session = [session retain];
31 _connected = NO;
32
33 _windowController = [[DebuggerWindowController alloc] initWithConnection: self];
34 [[_windowController window] makeKeyAndOrderFront: self];
35
36 // now that we have our host information, open the socket
37 _socket = [[SocketWrapper alloc] initWithPort: port];
38 [_socket setDelegate: self];
39 [_windowController setStatus: @"Connecting"];
40 [_socket connect];
41
42 // clean up after ourselves
43 [[NSNotificationCenter defaultCenter] addObserver: self
44 selector: @selector(applicationWillTerminate:)
45 name: NSApplicationWillTerminateNotification
46 object: NSApp];
47 }
48 return self;
49 }
50
51 /**
52 * Release ourselves when we're about to die
53 */
54 - (void)applicationWillTerminate: (NSNotification *)notif
55 {
56 [self release];
57 }
58
59 /**
60 * Releases all of the object's data members and closes the streams
61 */
62 - (void)dealloc
63 {
64 [_session release];
65 [_socket release];
66
67 [super dealloc];
68 }
69
70 /**
71 * Gets the port number
72 */
73 - (int)port
74 {
75 return _port;
76 }
77
78 /**
79 * Gets the session name
80 */
81 - (NSString *)session
82 {
83 return _session;
84 }
85
86 /**
87 * Returns the name of the remote host
88 */
89 - (NSString *)remoteHost
90 {
91 if (!_connected)
92 {
93 return @"(DISCONNECTED)";
94 }
95 return [_socket remoteHost];
96 }
97
98 /**
99 * SocketWrapper delegate method that is called whenever new data is received
100 */
101 - (void)dataReceived: (NSString *)response deliverTo: (SEL)selector
102 {
103 // if the caller of [_socket receive:] specified a deliverTo, just forward the message to them
104 if (selector != nil)
105 {
106 [self performSelector: selector withObject: response];
107 }
108 }
109
110 /**
111 * SocketWrapper delegate method that is called after data is sent. This really
112 * isn't useful for much.
113 */
114 - (void)dataSent: (NSString *)data
115 {
116 NSLog(@"send = %@", data);
117 }
118
119 /**
120 * Called by SocketWrapper after the connection is successful. This immediately calls
121 * -[SocketWrapper receive] to clear the way for communication
122 */
123 - (void)socketDidAccept
124 {
125 _connected = YES;
126 [_socket receive: @selector(_handshake:)];
127 }
128
129 /**
130 * Receives errors from the SocketWrapper and updates the display
131 */
132 - (void)errorEncountered: (NSError *)error
133 {
134 [_windowController setError: [error domain]];
135 }
136
137 /**
138 * The initial packet handshake. This allows us to set things like the title of the window
139 * and glean information about hte server we are debugging
140 */
141 - (void)_handshake: (NSData *)packet
142 {
143 [self refreshStatus];
144 }
145
146 /**
147 * Handler used by dataReceived:deliverTo: for anytime the status command is issued. It sets
148 * the window controller's status text
149 */
150 - (void)_updateStatus: (NSData *)packet
151 {
152 NSXMLDocument *doc = [[NSXMLDocument alloc] initWithData: packet options: NSXMLDocumentTidyXML error: nil];
153 [_windowController setStatus: [[[[doc rootElement] attributeForName: @"status"] stringValue] capitalizedString]];
154 [doc release];
155 }
156
157 /**
158 * Tells the debugger to continue running the script
159 */
160 - (void)run
161 {
162 [_socket send: [self _createCommand: @"run"]];
163 [self refreshStatus];
164 }
165
166 /**
167 * Method that runs tells the debugger to give us its status. This will call _updateStatus
168 * and will update the status text on the window
169 */
170 - (void)refreshStatus
171 {
172 [_socket send: [self _createCommand: @"status"]];
173 [_socket receive: @selector(_updateStatus:)];
174 }
175
176 /**
177 * Tells the debugger to step into the current command.
178 */
179 // TODO: populate the stack trace and registers list
180 - (void)stepIn
181 {
182 [_socket send: [self _createCommand: @"step_into"]];
183 [_socket receive: nil];
184 [self refreshStatus];
185 [self updateStackTraceAndRegisters];
186 }
187
188 /**
189 * This function queries the debug server for the current stacktrace and all the registers on
190 * level one. If a user then tries to expand past level one... TOOD: HOLY CRAP WHAT DO WE DO PAST LEVEL 1?
191 */
192 - (void)updateStackTraceAndRegisters
193 {
194 [_socket send: [self _createCommand: @"stack_get"]];
195 [_socket receive: @selector(_stackReceived:)];
196 }
197
198 /**
199 * Called by the dataReceived delivery delegate. This updates the window controller's data
200 * for the stack trace
201 */
202 - (void)_stackReceived: (NSData *)packet
203 {
204 NSXMLDocument *doc = [[NSXMLDocument alloc] initWithData: packet options: NSXMLDocumentTidyXML error: nil];
205 NSArray *children = [[doc rootElement] children];
206 NSMutableArray *stack = [NSMutableArray array];
207 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
208 for (int i = 0; i < [children count]; i++)
209 {
210 NSArray *attrs = [[children objectAtIndex: i] attributes];
211 for (int j = 0; j < [attrs count]; j++)
212 {
213 [dict setValue: [[attrs objectAtIndex: j] stringValue] forKey: [[attrs objectAtIndex: j] name]];
214 }
215 [stack addObject: dict];
216 dict = [NSMutableDictionary dictionary];
217 }
218 [_windowController setStack: stack];
219 }
220
221 /**
222 * Helper method to create a string command with the -i <session> automatically tacked on
223 */
224 - (NSString *)_createCommand: (NSString *)cmd
225 {
226 return [NSString stringWithFormat: @"%@ -i %@", cmd, _session];
227 }
228
229 @end