Remove unnecessary ivars from ProtocolClient.
[macgdbp.git] / Source / ProtocolClient.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2013, 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 "ProtocolClient.h"
18
19 #import "AppDelegate.h"
20 #import "LoggingController.h"
21
22 @implementation ProtocolClient {
23 // The object responsible for the actual communication with the debug server.
24 MessageQueue* _messageQueue;
25
26 // The delegate of this class, which receives high-level messages about the
27 // state of the debugger.
28 id<ProtocolClientDelegate> _delegate; // weak
29
30 // The next transaction ID to assign.
31 NSInteger _nextID;
32
33 // Records the last read and written transaction IDs. These are only used in
34 // creating LogEntry objects.
35 NSInteger _lastReadID;
36 NSInteger _lastWrittenID;
37 }
38
39 - (id)initWithDelegate:(id<ProtocolClientDelegate>)delegate {
40 if ((self = [super init])) {
41 _delegate = delegate;
42 }
43 return self;
44 }
45
46 - (void)dealloc {
47 [super dealloc];
48 }
49
50 - (BOOL)isConnected {
51 return [_messageQueue isConnected];
52 }
53
54 - (void)connectOnPort:(NSUInteger)port {
55 assert(!_messageQueue);
56 _messageQueue = [[MessageQueue alloc] initWithPort:port delegate:self];
57 [_messageQueue connect];
58 }
59
60 - (void)disconnect {
61 [_messageQueue disconnect];
62 }
63
64 - (NSNumber*)sendCommandWithFormat:(NSString*)format, ... {
65 // Collect varargs and format command.
66 va_list args;
67 va_start(args, format);
68 NSString* command = [[NSString alloc] initWithFormat:format arguments:args];
69 va_end(args);
70
71 NSNumber* callbackKey = [NSNumber numberWithInt:_nextID++];
72 NSString* taggedCommand = [NSString stringWithFormat:@"%@ -i %@", [command autorelease], callbackKey];
73
74 assert(_messageQueue);
75 [_messageQueue sendMessage:taggedCommand];
76 return callbackKey;
77 }
78
79 - (NSNumber*)sendCustomCommandWithFormat:(NSString*)format, ... {
80 // Collect varargs and format command.
81 va_list args;
82 va_start(args, format);
83 NSString* command = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
84 va_end(args);
85
86 NSNumber* callbackKey = [NSNumber numberWithInt:_nextID++];
87 NSString* taggedCommand = [command stringByReplacingOccurrencesOfString:@"{txn}"
88 withString:[callbackKey stringValue]];
89
90 [_messageQueue sendMessage:taggedCommand];
91 return callbackKey;
92 }
93
94 - (NSInteger)transactionIDFromResponse:(NSXMLDocument*)response {
95 return [[[[response rootElement] attributeForName:@"transaction_id"] stringValue] intValue];
96 }
97
98 - (NSInteger)transactionIDFromCommand:(NSString*)command {
99 NSRange occurrence = [command rangeOfString:@"-i "];
100 if (occurrence.location == NSNotFound)
101 return NSNotFound;
102 NSString* transaction = [command substringFromIndex:occurrence.location + occurrence.length];
103 return [transaction intValue];
104 }
105
106 + (NSString*)escapedFilePathURI:(NSString*)path {
107 // Custon GDBp paths are fine.
108 if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
109 return path;
110
111 // Create a temporary URL that will escape all the nasty characters.
112 NSURL* url = [NSURL fileURLWithPath:path];
113 NSString* urlString = [url absoluteString];
114
115 // Remove the host because this is a file:// URL;
116 NSString* host = [url host];
117 if (host)
118 urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
119
120 // Escape % for use in printf-style NSString formatters.
121 urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
122 return urlString;
123 }
124
125 // MessageQueueDelegate ////////////////////////////////////////////////////////
126
127 - (void)messageQueue:(MessageQueue*)queue error:(NSError*)error {
128 NSLog(@"error = %@", error);
129 }
130
131 - (void)messageQueueDidConnect:(MessageQueue*)queue {
132 _nextID = 0;
133 _lastReadID = 0;
134 _lastWrittenID = 0;
135
136 [_delegate debuggerEngineConnected:self];
137 }
138
139 - (void)messageQueueDidDisconnect:(MessageQueue*)queue {
140 [_messageQueue release];
141 _messageQueue = nil;
142 [_delegate debuggerEngineDisconnected:self];
143 }
144
145 // Callback for when a message has been sent.
146 - (void)messageQueue:(MessageQueue*)queue didSendMessage:(NSString*)message
147 {
148 NSInteger tag = [self transactionIDFromCommand:message];
149 _lastWrittenID = tag;
150
151 LoggingController* logger = [[AppDelegate instance] loggingController];
152 LogEntry* entry = [LogEntry newSendEntry:message];
153 entry.lastReadTransactionID = _lastReadID;
154 entry.lastWrittenTransactionID = _lastWrittenID;
155 [logger recordEntry:entry];
156 }
157
158 // Callback with the message content when one has been receieved.
159 - (void)messageQueue:(MessageQueue*)queue didReceiveMessage:(NSString*)message
160 {
161 LoggingController* logger = [[AppDelegate instance] loggingController];
162 LogEntry* entry = [LogEntry newReceiveEntry:message];
163 entry.lastReadTransactionID = _lastReadID;
164 entry.lastWrittenTransactionID = _lastWrittenID;
165 [logger recordEntry:entry];
166
167 // Test if we can convert it into an NSXMLDocument.
168 NSError* error = nil;
169 NSXMLDocument* xml = [[NSXMLDocument alloc] initWithXMLString:message
170 options:NSXMLDocumentTidyXML
171 error:&error];
172 if (error) {
173 [self messageQueue:queue error:error];
174 return;
175 }
176
177 _lastReadID = [self transactionIDFromResponse:xml];
178 entry.lastReadTransactionID = _lastReadID;
179
180 [_delegate debuggerEngine:self receivedMessage:xml];
181 }
182
183 @end