1EEBFD090D3599E8008F835B /* BSSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEBFD070D3599E8008F835B /* BSSplitView.m */; };
1EEBFD120D359A9F008F835B /* dimple.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFD110D359A9F008F835B /* dimple.png */; };
1EEE875D0D9DE4B4009CBA7C /* MacGDBp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */; };
- 1EFBE63012C515C200F96D6E /* NetworkConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFBE62F12C515C200F96D6E /* NetworkConnection.m */; };
1EFF70C30DFDC018006B9D33 /* BreakpointController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF70C20DFDC018006B9D33 /* BreakpointController.m */; };
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
1E02C5700C610158006F1752 /* DebuggerBackEnd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebuggerBackEnd.m; path = Source/DebuggerBackEnd.m; sourceTree = "<group>"; };
1E02C5F40C610724006F1752 /* DebuggerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebuggerController.h; path = Source/DebuggerController.h; sourceTree = "<group>"; };
1E02C5F50C610724006F1752 /* DebuggerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebuggerController.m; path = Source/DebuggerController.m; sourceTree = "<group>"; };
- 1E0724E111B47BCC0017AD3C /* NetworkConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkConnection.h; path = Source/NetworkConnection.h; sourceTree = "<group>"; };
1E0AFBB80FC2518700C67031 /* HUDIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = HUDIcon.png; path = Icons/HUDIcon.png; sourceTree = "<group>"; };
1E108E3E136CC8B9002E34E0 /* EvalController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EvalController.h; path = Source/EvalController.h; sourceTree = "<group>"; };
1E108E3F136CC8B9002E34E0 /* EvalController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EvalController.m; path = Source/EvalController.m; sourceTree = "<group>"; };
1EEBFD080D3599E8008F835B /* BSSplitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSSplitView.h; path = Source/BSSplitView.h; sourceTree = "<group>"; };
1EEBFD110D359A9F008F835B /* dimple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dimple.png; sourceTree = "<group>"; };
1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = MacGDBp.icns; path = Icons/MacGDBp.icns; sourceTree = "<group>"; };
- 1EFBE62F12C515C200F96D6E /* NetworkConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NetworkConnection.m; path = Source/NetworkConnection.m; sourceTree = "<group>"; };
1EFF70C10DFDC018006B9D33 /* BreakpointController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointController.h; path = Source/BreakpointController.h; sourceTree = "<group>"; };
1EFF70C20DFDC018006B9D33 /* BreakpointController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BreakpointController.m; path = Source/BreakpointController.m; sourceTree = "<group>"; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
1E1E52C10DF9B1FB00D334F9 /* Connection */ = {
isa = PBXGroup;
children = (
- 1E0724E111B47BCC0017AD3C /* NetworkConnection.h */,
- 1EFBE62F12C515C200F96D6E /* NetworkConnection.m */,
1E02C56F0C610158006F1752 /* DebuggerBackEnd.h */,
1E02C5700C610158006F1752 /* DebuggerBackEnd.m */,
1E35FFB00C65A74C0030F527 /* NSXMLElementAdditions.h */,
/* Begin PBXProject section */
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MacGDBp" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
1E6B5947116106FE001189D2 /* LoggingController.m in Sources */,
1EC1337E127DBB00007946FC /* VariableNode.m in Sources */,
1EC6965812BBC6A700A8D984 /* modp_b64.cc in Sources */,
- 1EFBE63012C515C200F96D6E /* NetworkConnection.m in Sources */,
1EDA9CF812DD13B300596211 /* BSLineNumberRulerView.mm in Sources */,
1E11814A1319805E003BFEF1 /* BSSourceViewTextView.m in Sources */,
1E108E40136CC8B9002E34E0 /* EvalController.m in Sources */,
#import <Cocoa/Cocoa.h>
#import "Breakpoint.h"
-#import "NetworkConnection.h"
+#import "ProtocolClient.h"
#import "StackFrame.h"
@protocol DebuggerBackEndDelegate;
// primary unit that this class deals with is the StackFrame; clients should
// maintain a stack structure and the BackEnd will inform the delegate when
// a new frame is created or the stack should be destroyed.
-@interface DebuggerBackEnd : NSObject <NetworkConnectionDelegate>
+@interface DebuggerBackEnd : NSObject <ProtocolClientDelegate>
{
// The connection to the debugger engine.
- NetworkConnection* connection_;
+ NSUInteger port_;
+ ProtocolClient* client_;
// Human-readable status of the connection.
NSString* status;
callTable_ = [NSMutableDictionary new];
[[BreakpointManager sharedManager] setConnection:self];
- connection_ = [[NetworkConnection alloc] initWithPort:aPort];
- connection_.delegate = self;
+ port_ = aPort;
+ client_ = [[ProtocolClient alloc] initWithDelegate:self];
attached_ = [[NSUserDefaults standardUserDefaults] boolForKey:@"DebuggerAttached"];
if (self.attached)
- [connection_ connect];
+ [client_ connectOnPort:port_];
}
return self;
}
*/
- (void)dealloc
{
- [connection_ close];
+ [client_ release];
[stackFrames_ release];
[callTable_ release];
[callbackContext_ release];
*/
- (NSUInteger)port
{
- return [connection_ port];
+ return port_;
}
/**
*/
- (BOOL)isConnected
{
- return [connection_ connected] && active_;
+ return active_;
}
/**
- (void)setAttached:(BOOL)attached {
if (attached != attached_) {
if (!attached)
- [connection_ close];
+ [client_ connectOnPort:port_];
else
- [connection_ connect];
+ [client_ disconnect];
}
attached_ = attached;
}
*/
- (void)run
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"run"];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"run"];
[self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
*/
- (void)stepIn
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_into"];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"step_into"];
[self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
*/
- (void)stepOut
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_out"];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"step_out"];
[self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
*/
- (void)stepOver
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_over"];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"step_over"];
[self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
*/
- (void)stop
{
- [connection_ close];
+ [client_ disconnect];
active_ = NO;
self.status = @"Stopped";
}
*/
- (void)detach
{
- [connection_ sendCommandWithFormat:@"detach"];
+ [client_ sendCommandWithFormat:@"detach"];
active_ = NO;
self.status = @"Stopped";
}
*/
- (NSInteger)getChildrenOfProperty:(VariableNode*)property atDepth:(NSInteger)depth;
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"property_get -d %d -n %@", depth, [property fullName]];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"property_get -d %d -n %@", depth, [property fullName]];
[self recordCallback:@selector(propertiesReceived:) forTransaction:tx];
return [tx intValue];
}
// Get the source code of the file. Escape % in URL chars.
if ([frame.filename length]) {
NSString* escapedFilename = [frame.filename stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
- transaction = [connection_ sendCommandWithFormat:@"source -f %@", escapedFilename];
+ transaction = [client_ sendCommandWithFormat:@"source -f %@", escapedFilename];
[self recordCallback:@selector(setSource:) forTransaction:transaction];
[callbackContext_ setObject:routingNumber forKey:transaction];
}
// Get the names of all the contexts.
- transaction = [connection_ sendCommandWithFormat:@"context_names -d %d", frame.index];
+ transaction = [client_ sendCommandWithFormat:@"context_names -d %d", frame.index];
[self recordCallback:@selector(contextsReceived:) forTransaction:transaction];
[callbackContext_ setObject:routingNumber forKey:transaction];
*/
- (void)addBreakpoint:(Breakpoint*)bp
{
- if (![connection_ connected])
+ if (!active_)
return;
- NSString* file = [connection_ escapedURIPath:[bp transformedPath]];
- NSNumber* tx = [connection_ sendCommandWithFormat:@"breakpoint_set -t line -f %@ -n %i", file, [bp line]];
+ NSString* file = [ProtocolClient escapedFilePathURI:[bp transformedPath]];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"breakpoint_set -t line -f %@ -n %i", file, [bp line]];
[self recordCallback:@selector(breakpointReceived:) forTransaction:tx];
[callbackContext_ setObject:bp forKey:tx];
}
*/
- (void)removeBreakpoint:(Breakpoint*)bp
{
- if (![connection_ connected])
+ if (!active_)
return;
- [connection_ sendCommandWithFormat:@"breakpoint_remove -d %i", [bp debuggerId]];
+ [client_ sendCommandWithFormat:@"breakpoint_remove -d %i", [bp debuggerId]];
}
/**
*/
- (void)evalScript:(NSString*)str
{
- if (![connection_ connected])
+ if (!active_)
return;
char* encodedString = malloc(modp_b64_encode_len([str length]));
modp_b64_encode(encodedString, [str UTF8String], [str length]);
- NSNumber* tx = [connection_ sendCustomCommandWithFormat:@"eval -i {txn} -- %s", encodedString];
+ NSNumber* tx = [client_ sendCustomCommandWithFormat:@"eval -i {txn} -- %s", encodedString];
free(encodedString);
[self recordCallback:@selector(evalScriptReceived:) forTransaction:tx];
}
+// Protocol Client Delegate ////////////////////////////////////////////////////
+#pragma mark Protocol Client Delegate
+
+- (void)debuggerEngineConnected:(ProtocolClient*)client
+{
+ active_ = YES;
+}
+
+/**
+ * Called when the connection is finally closed. This will reopen the listening
+ * socket if the debugger remains attached.
+ */
+- (void)debuggerEngineDisconnected:(ProtocolClient*)client
+{
+ active_ = NO;
+
+ if ([delegate respondsToSelector:@selector(debuggerDisconnected)])
+ [delegate debuggerDisconnected];
+
+ if (self.attached)
+ [client_ connectOnPort:port_];
+}
+
+- (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message
+{
+ // Check and see if there's an error.
+ NSArray* error = [[message rootElement] elementsForName:@"error"];
+ if ([error count] > 0) {
+ NSLog(@"Xdebug error: %@", error);
+ NSString* errorMessage = [[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue];
+ [self errorEncountered:errorMessage];
+ }
+
+ if ([[[message rootElement] name] isEqualToString:@"init"]) {
+ [self handleInitialResponse:message];
+ return;
+ }
+
+ [self handleResponse:message];
+}
+
// Specific Response Handlers //////////////////////////////////////////////////
#pragma mark Response Handlers
- (void)handleInitialResponse:(NSXMLDocument*)response
{
if (!self.attached) {
- [connection_ sendCommandWithFormat:@"detach"];
+ [client_ sendCommandWithFormat:@"detach"];
return;
}
// TODO: update the status.
}
-/**
- * Called when the connection is finally closed. This will reopen the listening
- * socket if the debugger remains attached.
- */
-- (void)connectionDidClose:(NetworkConnection*)connection
-{
- if ([delegate respondsToSelector:@selector(debuggerDisconnected)])
- [delegate debuggerDisconnected];
-
- if (self.attached)
- [connection_ connect];
-}
-
- (void)handleResponse:(NSXMLDocument*)response
{
- NSInteger transactionID = [connection_ transactionIDFromResponse:response];
+ NSInteger transactionID = [client_ transactionIDFromResponse:response];
NSNumber* key = [NSNumber numberWithInt:transactionID];
NSString* callbackStr = [callTable_ objectForKey:key];
if (callbackStr)
[delegate debuggerDisconnected];
active_ = NO;
} else if ([status isEqualToString:@"Stopping"]) {
- [connection_ sendCommandWithFormat:@"stop"];
+ [client_ sendCommandWithFormat:@"stop"];
active_ = NO;
}
}
if ([delegate respondsToSelector:@selector(clobberStack)])
[delegate clobberStack];
[stackFrames_ removeAllObjects];
- NSNumber* tx = [connection_ sendCommandWithFormat:@"stack_depth"];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"stack_depth"];
[self recordCallback:@selector(rebuildStack:) forTransaction:tx];
stackFirstTransactionID_ = [tx intValue];
}
{
NSInteger depth = [[[[response rootElement] attributeForName:@"depth"] stringValue] intValue];
- if (stackFirstTransactionID_ == [connection_ transactionIDFromResponse:response])
+ if (stackFirstTransactionID_ == [client_ 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 = [connection_ sendCommandWithFormat:@"stack_get -d %d", i];
+ NSNumber* routingID = [client_ sendCommandWithFormat:@"stack_get -d %d", i];
[self recordCallback:@selector(getStackFrame:) forTransaction:routingID];
[stackFrames_ setObject:[[StackFrame new] autorelease] forKey:routingID];
}
- (void)getStackFrame:(NSXMLDocument*)response
{
// Get the routing information.
- NSInteger routingID = [connection_ transactionIDFromResponse:response];
+ NSInteger routingID = [client_ transactionIDFromResponse:response];
if (routingID < stackFirstTransactionID_)
return;
NSNumber* routingNumber = [NSNumber numberWithInt:routingID];
*/
- (void)setSource:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
+ NSNumber* transaction = [NSNumber numberWithInt:[client_ 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:[connection_ transactionIDFromResponse:response]];
+ NSNumber* receivedTransaction = [NSNumber numberWithInt:[client_ 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* tx = [connection_ sendCommandWithFormat:@"context_get -d %d -c %d", frame.index, cid];
+ NSNumber* tx = [client_ sendCommandWithFormat:@"context_get -d %d -c %d", frame.index, cid];
[self recordCallback:@selector(variablesReceived:) forTransaction:tx];
[callbackContext_ setObject:routingID forKey:tx];
}
- (void)variablesReceived:(NSXMLDocument*)response
{
// Get the stack frame's routing ID and use it again.
- NSInteger transaction = [connection_ transactionIDFromResponse:response];
+ NSInteger transaction = [client_ transactionIDFromResponse:response];
if (transaction < stackFirstTransactionID_)
return;
NSNumber* receivedTransaction = [NSNumber numberWithInt:transaction];
*/
- (void)propertiesReceived:(NSXMLDocument*)response
{
- NSInteger transaction = [connection_ transactionIDFromResponse:response];
+ NSInteger transaction = [client_ transactionIDFromResponse:response];
/*
<response>
*/
- (void)breakpointReceived:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
+ NSNumber* transaction = [NSNumber numberWithInt:[client_ transactionIDFromResponse:response]];
Breakpoint* bp = [callbackContext_ objectForKey:transaction];
if (!bp)
return;
+++ /dev/null
-/*
- * MacGDBp
- * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
- *
- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
- * General Public License as published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#import <Cocoa/Cocoa.h>
-
-#import "ProtocolClient.h"
-
-@protocol NetworkConnectionDelegate;
-@class LoggingController;
-
-// This class is the lowest level component to the network. It deals with all
-// the intricacies of network and stream programming. Almost all the work this
-// class does is on a background thread, which is created when the connection is
-// asked to connect and shutdown when asked to close.
-@interface NetworkConnection : ProtocolClient<ProtocolClientDelegate>
-{
- // The port to connect on.
- NSUInteger port_;
-
- ProtocolClient* _ideClient;
-
- // If the connection to the debugger engine is currently active.
- BOOL connected_;
-
- // The delegate. All methods are executed on the main thread.
- NSObject<NetworkConnectionDelegate>* delegate_;
-}
-
-@property (readonly) NSUInteger port;
-@property (readonly) BOOL connected;
-@property (assign) id <NetworkConnectionDelegate> delegate;
-
-- (id)initWithPort:(NSUInteger)aPort;
-
-- (void)connect;
-- (void)close;
-
-- (NSString*)escapedURIPath:(NSString*)path;
-
-@end
-
-// Delegate ////////////////////////////////////////////////////////////////////
-
-@protocol NetworkConnectionDelegate <NSObject>
-
-@optional
-
-- (void)connectionDidAccept:(NetworkConnection*)cx;
-- (void)connectionDidClose:(NetworkConnection*)cx;
-
-- (void)handleInitialResponse:(NSXMLDocument*)response;
-
-- (void)handleResponse:(NSXMLDocument*)response;
-
-- (void)errorEncountered:(NSString*)error;
-
-@end
+++ /dev/null
-/*
- * MacGDBp
- * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
- *
- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
- * General Public License as published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#import "NetworkConnection.h"
-
-// This is the private interface for the NetworkConnection class. This is shared
-// by the C++ NetworkCallbackController to communicate.
-@interface NetworkConnection (Private)
-
-- (void)handleResponse:(NSXMLDocument*)response;
-
-// Threadsafe wrappers for the delegate's methods.
-- (void)errorEncountered:(NSString*)error;
-
-@end
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-@implementation NetworkConnection
-
-@synthesize port = port_;
-@synthesize connected = connected_;
-@synthesize delegate = delegate_;
-
-- (id)initWithPort:(NSUInteger)aPort
-{
- if (self = [super initWithDelegate:self]) {
- port_ = aPort;
- _ideClient = self;
- }
- return self;
-}
-
-/**
- * Kicks off the socket on another thread.
- */
-- (void)connect
-{
- [_ideClient connectOnPort:port_];
-}
-
-- (void)close
-{
- [_ideClient disconnect];
-}
-
-- (void)debuggerEngineConnected:(ProtocolClient*)client
-{
- if ([delegate_ respondsToSelector:@selector(connectionDidAccept:)])
- [delegate_ connectionDidAccept:self];
-}
-
-- (void)debuggerEngineDisconnected:(ProtocolClient*)client
-{
- if ([delegate_ respondsToSelector:@selector(connectionDidClose:)])
- [delegate_ connectionDidClose:self];
-}
-
-- (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message
-{
- [self handleResponse:message];
-}
-
-- (void)dealloc
-{
- [_ideClient release];
- [super dealloc];
-}
-
-/**
- * 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;
-}
-
-// Private /////////////////////////////////////////////////////////////////////
-#pragma mark Private
-
-// Delegate Thread-Safe Wrappers ///////////////////////////////////////////////
-
-/**
- * Receives errors from the SocketWrapper and updates the display
- */
-- (void)errorEncountered:(NSString*)error
-{
- if (![delegate_ respondsToSelector:@selector(errorEncountered:)])
- return;
- [delegate_ performSelectorOnMainThread:@selector(errorEncountered:)
- withObject:error
- waitUntilDone:NO];
-}
-
-- (void)handleResponse:(NSXMLDocument*)response
-{
- // Check and see if there's an error.
- NSArray* error = [[response rootElement] elementsForName:@"error"];
- if ([error count] > 0) {
- NSLog(@"Xdebug error: %@", error);
- NSString* errorMessage = [[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue];
- [self errorEncountered:errorMessage];
- }
-
- if ([[[response rootElement] name] isEqualToString:@"init"]) {
- connected_ = YES;
- [delegate_ handleInitialResponse:response];
- return;
- }
-
- if ([delegate_ respondsToSelector:@selector(handleResponse:)])
- [delegate_ handleResponse:response];
-}
-
-@end
- (NSInteger)transactionIDFromResponse:(NSXMLDocument*)response;
- (NSInteger)transactionIDFromCommand:(NSString*)command;
+// Given a path to a file, creates a URI for it that is suitable for sending to
+// the debugger engine.
++ (NSString*)escapedFilePathURI:(NSString*)path;
+
@end
// Delegate ////////////////////////////////////////////////////////////////////
return [transaction intValue];
}
++ (NSString*)escapedFilePathURI:(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;
+}
+
// MessageQueueDelegate ////////////////////////////////////////////////////////
- (void)messageQueue:(MessageQueue*)queue error:(NSError*)error {