@implementation DebuggerConnection
+@synthesize port = port_;
+@synthesize connected = connected_;
+@synthesize delegate = delegate_;
+
@synthesize socket = socket_;
@synthesize readStream = readStream_;
@synthesize lastReadTransaction = lastReadTransaction_;
@synthesize lastWrittenTransaction = lastWrittenTransaction_;
@synthesize queuedWrites = queuedWrites_;
+- (id)initWithPort:(NSUInteger)aPort
+{
+ if (self = [super init])
+ {
+ port_ = aPort;
+ }
+ return self;
+}
+
- (void)dealloc
{
self.currentPacket = nil;
*/
- (void)socketDidAccept
{
- connected = YES;
+ connected_ = YES;
transactionID = 1;
self.queuedWrites = [NSMutableArray array];
writeQueueLock_ = [NSRecursiveLock new];
memset(&address, 0, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
- address.sin_port = htons(port);
+ address.sin_port = htons(port_);
address.sin_addr.s_addr = htonl(INADDR_ANY);
// Create the socket signature.
- (void)socketDisconnected
{
[self close];
- [delegate_ debuggerDisconnected];
+ [delegate_ connectionDidCose:self];
}
/**
if ([[[response rootElement] name] isEqualToString:@"init"])
{
- [self initReceived:response];
+ [delegate_ handleInitialResponse:response];
return;
}
if (callbackStr)
{
SEL callback = NSSelectorFromString(callbackStr);
- [self performSelector:callback withObject:response];
+ [delegate_ performSelector:callback withObject:response];
}
[self sendQueuedWrites];
*/
- (void)sendQueuedWrites
{
- if (!connected)
+ if (!connected_)
return;
[writeQueueLock_ lock];
return [transaction intValue];
}
+/**
+ * Given a file path, this returns a file:// URI and escapes any spaces for the
+ * debugger engine.
+ */
+- (NSString*)escapedURIPath:(NSString*)path
+{
+ // Custon GDBp paths are fine.
+ if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
+ return path;
+
+ // Create a temporary URL that will escape all the nasty characters.
+ NSURL* url = [NSURL fileURLWithPath:path];
+ NSString* urlString = [url absoluteString];
+
+ // Remove the host because this is a file:// URL;
+ urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
+
+ // Escape % for use in printf-style NSString formatters.
+ urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
+ return urlString;
+}
+
@end
@interface DebuggerProcessor ()
@property (readwrite, copy) NSString* status;
-- (void)initReceived:(NSXMLDocument*)response;
- (void)updateStatus:(NSXMLDocument*)response;
- (void)debuggerStep:(NSXMLDocument*)response;
- (void)rebuildStack:(NSXMLDocument*)response;
{
if (self = [super init])
{
- port = aPort;
- connected = NO;
-
stackFrames_ = [[NSMutableDictionary alloc] init];
callbackContext_ = [NSMutableDictionary new];
[[BreakpointManager sharedManager] setConnection:self];
- [self connect];
+ connection_ = [[DebuggerConnection alloc] initWithPort:aPort];
+ connection_.delegate = self;
+ [connection_ connect];
}
return self;
}
*/
- (void)dealloc
{
- [self close];
+ [connection_ close];
[stackFrames_ release];
[callbackContext_ release];
[super dealloc];
*/
- (NSUInteger)port
{
- return port;
+ return [connection_ port];
}
/**
*/
- (NSString*)remoteHost
{
- if (!connected)
- {
+ if (![connection_ connected])
return @"(DISCONNECTED)";
- }
+
// TODO: Either impl or remove.
return @"";
}
*/
- (BOOL)isConnected
{
- return connected;
+ return [connection_ connected];
}
// Commands ////////////////////////////////////////////////////////////////////
*/
- (void)reconnect
{
- [self close];
+ [connection_ close];
self.status = @"Connecting";
- [self connect];
+ [connection_ connect];
}
/**
*/
- (void)run
{
- [self sendCommandWithCallback:@selector(debuggerStep:) format:@"run"];
+ [connection_ sendCommandWithCallback:@selector(debuggerStep:) format:@"run"];
}
/**
*/
- (void)stepIn
{
- [self sendCommandWithCallback:@selector(debuggerStep:) format:@"step_into"];
+ [connection_ sendCommandWithCallback:@selector(debuggerStep:) format:@"step_into"];
}
/**
*/
- (void)stepOut
{
- [self sendCommandWithCallback:@selector(debuggerStep:) format:@"step_out"];
+ [connection_ sendCommandWithCallback:@selector(debuggerStep:) format:@"step_out"];
}
/**
*/
- (void)stepOver
{
- [self sendCommandWithCallback:@selector(debuggerStep:) format:@"step_over"];
+ [connection_ sendCommandWithCallback:@selector(debuggerStep:) format:@"step_over"];
}
/**
*/
- (NSInteger)getProperty:(NSString*)property
{
- [self sendCommandWithCallback:@selector(propertiesReceived:) format:@"property_get -n \"%@\"", property];
+ [connection_ sendCommandWithCallback:@selector(propertiesReceived:) format:@"property_get -n \"%@\"", property];
}
// Breakpoint Management ///////////////////////////////////////////////////////
*/
- (void)addBreakpoint:(Breakpoint*)bp
{
- if (!connected)
+ if (![connection_ connected])
return;
- NSString* file = [self escapedURIPath:[bp transformedPath]];
- NSNumber* transaction = [self sendCommandWithCallback:@selector(breakpointReceived:)
+ NSString* file = [connection_ escapedURIPath:[bp transformedPath]];
+ NSNumber* transaction = [connection_ sendCommandWithCallback:@selector(breakpointReceived:)
format:@"breakpoint_set -t line -f %@ -n %i", file, [bp line]];
[callbackContext_ setObject:bp forKey:transaction];
}
*/
- (void)removeBreakpoint:(Breakpoint*)bp
{
- if (!connected)
- {
+ if (![connection_ connected])
return;
- }
- [self sendCommandWithCallback:nil format:@"breakpoint_remove -d %i", [bp debuggerId]];
+ [connection_ sendCommandWithCallback:nil format:@"breakpoint_remove -d %i", [bp debuggerId]];
}
// Specific Response Handlers //////////////////////////////////////////////////
/**
* Initial packet received. We've started a brand-new connection to the engine.
*/
-- (void)initReceived:(NSXMLDocument*)response
+- (void)handleInitialResponse:(NSXMLDocument*)response
{
// Register any breakpoints that exist offline.
for (Breakpoint* bp in [[BreakpointManager sharedManager] breakpoints])
self.status = [[[[response rootElement] attributeForName:@"status"] stringValue] capitalizedString];
if (status == nil || [status isEqualToString:@"Stopped"] || [status isEqualToString:@"Stopping"])
{
- connected = NO;
- [self close];
+ [connection_ close];
[delegate debuggerDisconnected];
self.status = @"Stopped";
- (void)debuggerStep:(NSXMLDocument*)response
{
[self updateStatus:response];
- if (!connected)
+ if (![connection_ connected])
return;
// If this is the run command, tell the delegate that a bunch of updates
if ([delegate respondsToSelector:@selector(clobberStack)])
[delegate clobberStack];
[stackFrames_ removeAllObjects];
- stackFirstTransactionID_ = [[self sendCommandWithCallback:@selector(rebuildStack:) format:@"stack_depth"] intValue];
+ stackFirstTransactionID_ = [[connection_ sendCommandWithCallback:@selector(rebuildStack:) format:@"stack_depth"] intValue];
}
}
{
NSInteger depth = [[[[response rootElement] attributeForName:@"depth"] stringValue] intValue];
- if (stackFirstTransactionID_ == [self transactionIDFromResponse:response])
+ if (stackFirstTransactionID_ == [connection_ transactionIDFromResponse:response])
stackDepth_ = depth;
// We now need to alloc a bunch of stack frames and get the basic information
for (NSInteger i = 0; i < depth; i++)
{
// Use the transaction ID to create a routing path.
- NSNumber* routingID = [self sendCommandWithCallback:@selector(getStackFrame:) format:@"stack_get -d %d", i];
+ NSNumber* routingID = [connection_ sendCommandWithCallback:@selector(getStackFrame:) format:@"stack_get -d %d", i];
[stackFrames_ setObject:[StackFrame alloc] forKey:routingID];
}
}
- (void)getStackFrame:(NSXMLDocument*)response
{
// Get the routing information.
- NSInteger routingID = [self transactionIDFromResponse:response];
+ NSInteger routingID = [connection_ transactionIDFromResponse:response];
if (routingID < stackFirstTransactionID_)
return;
NSNumber* routingNumber = [NSNumber numberWithInt:routingID];
// Get the source code of the file. Escape % in URL chars.
NSString* escapedFilename = [frame.filename stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
- NSNumber* transaction = [self sendCommandWithCallback:@selector(setSource:) format:@"source -f %@", escapedFilename];
+ NSNumber* transaction = [connection_ sendCommandWithCallback:@selector(setSource:) format:@"source -f %@", escapedFilename];
[callbackContext_ setObject:routingNumber forKey:transaction];
// Get the names of all the contexts.
- transaction = [self sendCommandWithCallback:@selector(contextsReceived:) format:@"context_names -d %d", frame.index];
+ transaction = [connection_ sendCommandWithCallback:@selector(contextsReceived:) format:@"context_names -d %d", frame.index];
[callbackContext_ setObject:routingNumber forKey:transaction];
if ([delegate respondsToSelector:@selector(newStackFrame:)])
*/
- (void)setSource:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[self transactionIDFromResponse:response]];
+ NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
if ([transaction intValue] < stackFirstTransactionID_)
return;
NSNumber* routingNumber = [callbackContext_ objectForKey:transaction];
- (void)contextsReceived:(NSXMLDocument*)response
{
// Get the stack frame's routing ID and use it again.
- NSNumber* receivedTransaction = [NSNumber numberWithInt:[self transactionIDFromResponse:response]];
+ NSNumber* receivedTransaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
if ([receivedTransaction intValue] < stackFirstTransactionID_)
return;
NSNumber* routingID = [callbackContext_ objectForKey:receivedTransaction];
NSInteger cid = [[[context attributeForName:@"id"] stringValue] intValue];
// Fetch each context's variables.
- NSNumber* transaction = [self sendCommandWithCallback:@selector(variablesReceived:)
+ NSNumber* transaction = [connection_ sendCommandWithCallback:@selector(variablesReceived:)
format:@"context_get -d %d -c %d", frame.index, cid];
[callbackContext_ setObject:routingID forKey:transaction];
}
- (void)variablesReceived:(NSXMLDocument*)response
{
// Get the stack frame's routing ID and use it again.
- NSInteger transaction = [self transactionIDFromResponse:response];
+ NSInteger transaction = [connection_ transactionIDFromResponse:response];
if (transaction < stackFirstTransactionID_)
return;
NSNumber* receivedTransaction = [NSNumber numberWithInt:transaction];
*/
- (void)propertiesReceived:(NSXMLDocument*)response
{
- NSInteger transaction = [self transactionIDFromResponse:response];
+ NSInteger transaction = [connection_ transactionIDFromResponse:response];
/*
<response>
*/
- (void)breakpointReceived:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[self transactionIDFromResponse:response]];
+ NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
Breakpoint* bp = [callbackContext_ objectForKey:transaction];
if (!bp)
return;
[bp setDebuggerId:[[[[response rootElement] attributeForName:@"id"] stringValue] intValue]];
}
-/**
- * Given a file path, this returns a file:// URI and escapes any spaces for the
- * debugger engine.
- */
-- (NSString*)escapedURIPath:(NSString*)path
-{
- // Custon GDBp paths are fine.
- if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
- return path;
-
- // Create a temporary URL that will escape all the nasty characters.
- NSURL* url = [NSURL fileURLWithPath:path];
- NSString* urlString = [url absoluteString];
-
- // Remove the host because this is a file:// URL;
- urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
-
- // Escape % for use in printf-style NSString formatters.
- urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
- return urlString;
-}
-
@end