From 98820f9c7e17e871eede142a9cf96311f09515e6 Mon Sep 17 00:00:00 2001
From: Robert Sesek <rsesek@bluestatic.org>
Date: Sun, 1 May 2011 12:25:35 -0400
Subject: [PATCH] Add -[DebuggerBackEnd evalScript:] to send the command.

But the command format is atypical and has the transaction ID before the last
parameter, so also add -[NetworkConnection sendCustomCommandWithFormat:] to
support placing the transaction ID in an arbitrary place using a string
placeholder.
---
 Source/DebuggerBackEnd.h    |  3 +++
 Source/DebuggerBackEnd.m    | 15 +++++++++++++++
 Source/EvalController.m     |  5 ++++-
 Source/NetworkConnection.h  |  5 +++++
 Source/NetworkConnection.mm | 25 +++++++++++++++++++++++++
 5 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/Source/DebuggerBackEnd.h b/Source/DebuggerBackEnd.h
index 8de4c2e..21b5580 100644
--- a/Source/DebuggerBackEnd.h
+++ b/Source/DebuggerBackEnd.h
@@ -87,6 +87,9 @@
 - (void)addBreakpoint:(Breakpoint*)bp;
 - (void)removeBreakpoint:(Breakpoint*)bp;
 
+// Evaluates a given string in the current execution context.
+- (void)evalScript:(NSString*)str;
+
 // Gets a property by name from the debugger engine. Returns a transaction ID
 // which used in the delegate callback. Properties must be retrieved at a
 // certain stack depth.
diff --git a/Source/DebuggerBackEnd.m b/Source/DebuggerBackEnd.m
index a739b21..7de4ce0 100644
--- a/Source/DebuggerBackEnd.m
+++ b/Source/DebuggerBackEnd.m
@@ -17,6 +17,7 @@
 #import "DebuggerBackEnd.h"
 
 #import "AppDelegate.h"
+#import "modp_b64.h"
 #import "NSXMLElementAdditions.h"
 
 // GDBpConnection (Private) ////////////////////////////////////////////////////
@@ -242,6 +243,20 @@
   [connection_ sendCommandWithFormat:@"breakpoint_remove -d %i", [bp debuggerId]];
 }
 
+/**
+ * Sends a string to be evaluated by the engine.
+ */
+- (void)evalScript:(NSString*)str
+{
+  if (![connection_ connected])
+    return;
+
+  char* encodedString = malloc(modp_b64_encode_len([str length]));
+  modp_b64_encode(encodedString, [str UTF8String], [str length]);
+  [connection_ sendCustomCommandWithFormat:@"eval -i {txn} -- %s", encodedString];
+  free(encodedString);
+}
+
 // Specific Response Handlers //////////////////////////////////////////////////
 #pragma mark Response Handlers
 
diff --git a/Source/EvalController.m b/Source/EvalController.m
index ced1559..7e1cb52 100644
--- a/Source/EvalController.m
+++ b/Source/EvalController.m
@@ -16,6 +16,8 @@
 
 #import "EvalController.h"
 
+#import "DebuggerBackEnd.h"
+
 @implementation EvalController
 
 @synthesize dataField = dataField_;
@@ -54,7 +56,8 @@
 
 - (IBAction)evaluateScript:(id)sender
 {
-  NSLog(@"will evluate: %@", [self.dataField stringValue]);
+  NSString* code = [self.dataField stringValue];
+  [backEnd_ evalScript:code];
 }
 
 - (IBAction)closeWindow:(id)sender
diff --git a/Source/NetworkConnection.h b/Source/NetworkConnection.h
index 99301e1..9286714 100644
--- a/Source/NetworkConnection.h
+++ b/Source/NetworkConnection.h
@@ -98,6 +98,11 @@ class NetworkCallbackController;
 // safe and schedules the request on the |runLoop_|.
 - (NSNumber*)sendCommandWithFormat:(NSString*)format, ...;
 
+// Sends a command to the debugger. The command must have a substring |{txn}|
+// within it, which will be replaced with the transaction ID. Use this if
+// |-sendCommandWithFormat:|'s insertion of the transaction ID is incorrect.
+- (NSNumber*)sendCustomCommandWithFormat:(NSString*)format, ...;
+
 - (NSString*)escapedURIPath:(NSString*)path;
 - (NSInteger)transactionIDFromResponse:(NSXMLDocument*)response;
 - (NSInteger)transactionIDFromCommand:(NSString*)command;
diff --git a/Source/NetworkConnection.mm b/Source/NetworkConnection.mm
index 5fede2c..63370a8 100644
--- a/Source/NetworkConnection.mm
+++ b/Source/NetworkConnection.mm
@@ -205,6 +205,31 @@ void PerformQuitSignal(void* info)
   return callbackKey;
 }
 
+/**
+ * Certain commands expect encoded data to be the the last, unnamed parameter
+ * of the command. In these cases, inserting the transaction ID at the end is
+ * incorrect, so clients use this method to have |{txn}| replaced with the
+ * transaction ID.
+ */
+- (NSNumber*)sendCustomCommandWithFormat:(NSString*)format, ...
+{
+  // Collect varargs and format command.
+  va_list args;
+  va_start(args, format);
+  NSString* command = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
+  va_end(args);  
+
+  NSNumber* callbackKey = [NSNumber numberWithInt:transactionID++];
+  NSString* taggedCommand = [command stringByReplacingOccurrencesOfString:@"{txn}"
+                                                               withString:[callbackKey stringValue]];
+  [self performSelector:@selector(send:)
+               onThread:thread_
+             withObject:taggedCommand
+          waitUntilDone:connected_];
+  
+  return callbackKey;
+}
+
 /**
  * Given a file path, this returns a file:// URI and escapes any spaces for the
  * debugger engine.
-- 
2.43.5