diff --git a/class/Mono.XsltDebugger/Mono.XsltDebugger/ChangeLog b/class/Mono.XsltDebugger/Mono.XsltDebugger/ChangeLog index 5c6a00f9..54ca8af5 100644 --- a/class/Mono.XsltDebugger/Mono.XsltDebugger/ChangeLog +++ b/class/Mono.XsltDebugger/Mono.XsltDebugger/ChangeLog @@ -1,3 +1,8 @@ +2007-07-02 Atsushi Enomoto + + * XsltDebugger.cs XsltDebuggerSession.cs : + some renaming. Added thread manager and got break commands working. + 2007-06-29 Atsushi Enomoto * XsltExecuteEventArgs.cs XsltExecuteEventHandler.cs diff --git a/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebugger.cs b/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebugger.cs index 04522222..1be9c415 100644 --- a/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebugger.cs +++ b/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebugger.cs @@ -2,13 +2,14 @@ using System.Collections; using System.IO; using System.Security.Policy; +using System.Threading; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; namespace Mono.XsltDebugger { - public class XsltDebugger + public class XsltDebuggerService { XPathDocument style; XPathDocument input; @@ -17,11 +18,16 @@ public class XsltDebugger ArrayList breakpoints = new ArrayList (); XsltDebuggerSession current_run; XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ()); + ThreadManager thread_manager; - public XsltDebugger () + public XsltDebuggerService () { } + public event EventHandler BreakpointMatched; + + public event EventHandler TransformCompleted; + public XmlNamespaceManager NamespaceManager { get { return nsmgr; } } @@ -90,21 +96,26 @@ public void Run () Abort (); } current_run = new XsltDebuggerSession (this); + thread_manager = new ThreadManager (current_run); // set breakpoints current_run.Executed += OnExecute; - current_run.Run (); + thread_manager.StartTransform (); } public virtual void Interrupt () { - throw new NotImplementedException (); + if (thread_manager == null) + throw new XsltDebuggerException ("No active transformation to interrupt"); + thread_manager.InterruptTransform (); } public virtual void Resume () { - throw new NotImplementedException (); + if (thread_manager == null) + throw new XsltDebuggerException ("No active transformation to interrupt"); + thread_manager.ResumeTransform (); } public virtual void Abort () @@ -140,13 +151,30 @@ protected internal virtual void Transform (XslTransform transform, XmlWriter wri if (input == null) throw new XsltDebuggerException ("Input document is not specified"); transform.Transform (input, null, writer, xml_resolver); + + OnTransformCompleted (); } + // invoked inside transformation thread. void OnExecute (object o, XsltExecuteEventArgs args) { if (!Break (args.Context)) return; -Console.WriteLine ("Match"); + thread_manager.DispatchBreakpointMatch (o, args); + } + + // invoked from ThreadManager notification thread + void OnBreakpointMatch (object o, XsltExecuteEventArgs args) + { + if (BreakpointMatched != null) + BreakpointMatched (o, args); + } + + void OnTransformCompleted () + { + if (TransformCompleted != null) + TransformCompleted (null, null); + thread_manager.Dispose (); } bool Break (XsltDebuggerContext ctx) @@ -158,5 +186,80 @@ bool Break (XsltDebuggerContext ctx) return true; return false; } + + class ThreadManager : IDisposable + { + XsltDebuggerSession session; + Thread run_thread, notify_thread; + ManualResetEvent notify_handle, trans_handle; + + // used between notification thread and transformation thread + object event_sender; + XsltExecuteEventArgs event_args; + + public ThreadManager (XsltDebuggerSession session) + { + this.session = session; + } + + public void Dispose () + { + if (notify_thread != null) { + notify_thread.Abort (); + notify_thread = null; + } + if (run_thread != null) { + run_thread.Abort (); + run_thread = null; + } + } + + // It kicks the transform thread and returns. + public void StartTransform () + { + notify_handle = new ManualResetEvent (false); + trans_handle = new ManualResetEvent (false); + + run_thread = new Thread (delegate () { + try { + session.Run (); + } catch (ThreadAbortException) { + Thread.ResetAbort (); + } + }); + notify_thread = new Thread (delegate () { + try { + while (true) { + notify_handle.Reset (); + notify_handle.WaitOne (); + session.Debugger.OnBreakpointMatch (event_sender, event_args); + } + } catch (ThreadAbortException) { + Thread.ResetAbort (); + } + }); + + notify_thread.Start (); + run_thread.Start (); + } + + public void InterruptTransform () + { + trans_handle.WaitOne (); + } + + public void ResumeTransform () + { + trans_handle.Set (); + } + + public void DispatchBreakpointMatch (object o, XsltExecuteEventArgs args) + { + this.event_sender = o; + this.event_args = args; + notify_handle.Set (); + trans_handle.WaitOne (); + } + } } } diff --git a/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebuggerSession.cs b/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebuggerSession.cs index e10add67..b35a2ea5 100644 --- a/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebuggerSession.cs +++ b/class/Mono.XsltDebugger/Mono.XsltDebugger/XsltDebuggerSession.cs @@ -11,19 +11,19 @@ namespace Mono.XsltDebugger { public class XsltDebuggerSession : IDisposable { - XsltDebugger debugger; + XsltDebuggerService debugger; XsltInjector injector; XslTransform transform; XmlNodeWriter output; Hashtable custom_cache; - public XsltDebuggerSession (XsltDebugger debugger) + public XsltDebuggerSession (XsltDebuggerService debugger) { this.debugger = debugger; Init (); } - public XsltDebugger Debugger { + public XsltDebuggerService Debugger { get { return debugger; } } @@ -46,6 +46,7 @@ public void Dispose () output = null; } + // It is indicated by ThreadManager.StartDebug(). internal void Run () { custom_cache = new Hashtable (); diff --git a/tools/xslt-debugger/ChangeLog b/tools/xslt-debugger/ChangeLog index 704598a9..f48896cf 100644 --- a/tools/xslt-debugger/ChangeLog +++ b/tools/xslt-debugger/ChangeLog @@ -1,3 +1,7 @@ +2007-07-02 Atsushi Enomoto + + * xslt-debugger.cs : added couple of commands. + 2007-06-29 Atsushi Enomoto * Makefile diff --git a/tools/xslt-debugger/xslt-debugger.cs b/tools/xslt-debugger/xslt-debugger.cs index 41f0c44b..41a78dd4 100755 --- a/tools/xslt-debugger/xslt-debugger.cs +++ b/tools/xslt-debugger/xslt-debugger.cs @@ -1,13 +1,15 @@ using System; using System.Collections; +using System.Globalization; using System.IO; using System.Text; +using System.Threading; using System.Xml; using System.Xml.XPath; namespace Mono.XsltDebugger { - public class XsltDebuggerConsole + public class XsltDebuggerConsole : XsltDebuggerService { static readonly char [] wsChars = new char [] {' ', '\n', '\r', '\t'}; @@ -16,24 +18,39 @@ public static void Main (string [] args) new XsltDebuggerConsole ().Run (args); } + protected override bool WarnAndQueryExistingRun () + { + Console.WriteLine ("There already is a running debug session. Do you want to stop it? [Y/n]"); + string s = Console.ReadLine (); + return (s.Length == 0 || String.Compare (s, "yes", true) == 0); + } + int verbose; // 1: report exception details - XsltDebugger debugger = new XsltDebugger (); + XsltDebuggerService debugger = new XsltDebuggerService (); bool completed, debugger_exit; ArrayList commands = new ArrayList (); + ManualResetEvent wait_handle; public XsltDebuggerConsole () { commands.Add (new HelpCommand ()); commands.Add (new QuitCommand ()); commands.Add (new RunCommand ()); + commands.Add (new ContinueCommand ()); commands.Add (new AddXPathBreakCommand ()); commands.Add (new AddStylesheetBreakCommand ()); commands.Add (new ListBreakpointCommand ()); + commands.Add (new RemoveBreakpointCommand ()); + commands.Add (new ClearBreakpointCommand ()); commands.Add (new AddXmlnsCommand ()); commands.Add (new RemoveXmlnsCommand ()); commands.Add (new ListXmlnsCommand ()); commands.Add (new ShowOutputCommand ()); commands.Add (new BatchProcessCommand ()); + commands.Add (new LoadStylesheetCommand ()); + commands.Add (new LoadInputCommand ()); + + wait_handle = new ManualResetEvent (false); } void ShowUsage () @@ -43,20 +60,13 @@ void ShowUsage () public void SignalQuitDebugger () { + debugger.Abort (); debugger_exit = true; } public void Run (string [] args) { try { -/* - // FIXME: CurrentRun does not exist yet - debugger.CurrentRun.Completed += delegate (object o, XsltCompleteEventArgs e) { - Console.WriteLine ("XSL Transformation completed."); - completed = true; - }; -*/ - foreach (string arg in args) { if (arg == "--verbose" || arg == "-v") verbose++; @@ -65,6 +75,14 @@ public void Run (string [] args) else debugger.Input = new XPathDocument (arg); } + debugger.BreakpointMatched += delegate (object o, EventArgs e) { + Console.WriteLine ("Breakpoint matched"); + wait_handle.Set (); + }; + debugger.TransformCompleted += delegate (object o, EventArgs e) { + wait_handle.Set (); + Console.WriteLine ("Transform finished"); + }; ProcessUserInteraction (); @@ -203,6 +221,30 @@ public override bool Match (string cmd, string [] args) public override void Process (XsltDebuggerConsole owner, string [] args) { owner.debugger.Run (); + owner.wait_handle.Reset (); + owner.wait_handle.WaitOne (); + } + } + + public class ContinueCommand : XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + return cmd == "continue" || cmd == "cont"; + } + + public override string UsageSummary { + get { return "continue (cont)"; } + } + + public override string UsageDetails { + get { return "Continues an interrupted transform."; } + } + + public override void Process (XsltDebuggerConsole owner, string [] args) + { + owner.debugger.Resume (); + owner.wait_handle.WaitOne (); } } @@ -220,8 +262,8 @@ public class AddXPathBreakCommand : AddBreakpointCommand { public override bool Match (string cmd, string [] args) { - // FIXME: remove this extra "list" check hack. - return cmd == "break" && args.Length == 2 && args [1] != "list"; + // FIXME: remove this extra check hack for "list" and "clear". + return cmd == "break" && args.Length == 2 && args [1] != "list" && args [1] != "clear"; } public override string UsageSummary { @@ -242,7 +284,8 @@ public class AddStylesheetBreakCommand : AddBreakpointCommand { public override bool Match (string cmd, string [] args) { - return cmd == "break" && (args.Length == 3 || args.Length == 4); + int dummy; + return cmd == "break" && (args.Length == 3 || args.Length == 4) && !int.TryParse (args [2], out dummy); } public override string UsageSummary { @@ -285,6 +328,52 @@ public override void Process (XsltDebuggerConsole run, string [] args) } } + public class RemoveBreakpointCommand : XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + int dummy; + return cmd == "break" && args.Length == 3 && args [1] == "remove" && int.TryParse (args [2], out dummy); + } + + public override string UsageSummary { + get { return "break remove "; } + } + + public override string UsageDetails { + get { return "Removes specified breakpoints."; } + } + + public override void Process (XsltDebuggerConsole run, string [] args) + { + int n = int.Parse (args [2]); + if (run.debugger.Breakpoints.Count <= n) + throw new XsltDebuggerException (String.Format ("No breakpoint was found at index {0}", n)); + run.debugger.Breakpoints.RemoveAt (n); + } + } + + public class ClearBreakpointCommand : XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + return cmd == "break" && args.Length > 1 && args [1] == "clear"; + } + + public override string UsageSummary { + get { return "break clear"; } + } + + public override string UsageDetails { + get { return "Removes all of the registered breakpoints."; } + } + + public override void Process (XsltDebuggerConsole run, string [] args) + { + run.debugger.Breakpoints.Clear (); + } + } + public class AddXmlnsCommand : XsltDebuggerConsoleCommand { public override bool Match (string cmd, string [] args) @@ -363,6 +452,29 @@ public override void Process (XsltDebuggerConsole run, string [] args) } } + /* + public class PrintVariableCommand : XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + return cmd == "print" && args.Length == 3 && args [1] == "variable"; + } + + public override string UsageSummary { + get { return "print variable "; } + } + + public override string UsageDetails { + get { return "Shows specified variable."; } + } + + public override void Process (XsltDebuggerConsole run, string [] args) + { + IXsltContextVariable v = run.debugger. + } + } + */ + public class ShowOutputCommand : XsltDebuggerConsoleCommand { public override bool Match (string cmd, string [] args) @@ -391,6 +503,10 @@ public override void Process (XsltDebuggerConsole run, string [] args) void PrintLastLines (string s, int lines) { + if (s.Length == 0) { + Console.WriteLine ("No output yet"); + return; + } ArrayList al = new ArrayList (); int start = s.Length - 1, pos; while ((pos = s.LastIndexOf ('\n', start)) >= 0) { @@ -440,5 +556,53 @@ public override void Process (XsltDebuggerConsole run, string [] args) } } } + + public class LoadStylesheetCommand : XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + return cmd == "load" && args.Length == 3 && args [1] == "stylesheet"; + } + + public override string UsageSummary { + get { return "load stylesheet "; } + } + + public override string UsageDetails { + get { return "Loads a stylesheet ."; } + } + + public override void Process (XsltDebuggerConsole run, string [] args) + { + if (!File.Exists (args [1])) + throw new XsltDebuggerException (String.Format ("File {0} does not exist", args [1])); + run.debugger.Stylesheet = new XPathDocument (args [1]); + Console.WriteLine ("Loaded stylesheet {0}", args [1]); + } + } + + public class LoadInputCommand: XsltDebuggerConsoleCommand + { + public override bool Match (string cmd, string [] args) + { + return cmd == "load" && args.Length == 3 && args [1] == "input"; + } + + public override string UsageSummary { + get { return "load input "; } + } + + public override string UsageDetails { + get { return "Loads an input document ."; } + } + + public override void Process (XsltDebuggerConsole run, string [] args) + { + if (!File.Exists (args [1])) + throw new XsltDebuggerException (String.Format ("File {0} does not exist", args [1])); + run.debugger.Input = new XPathDocument (args [1]); + Console.WriteLine ("Loaded input document {0}", args [1]); + } + } } }