Major change: Discovered the vte.Terminal class and moved to that one!
authorStefan Huber <shuber2@gmail.com>
Sat, 7 Jun 2008 21:21:36 +0000 (23:21 +0200)
committerStefan Huber <shuber2@gmail.com>
Sat, 7 Jun 2008 21:21:36 +0000 (23:21 +0200)
  - Client I/O Window
  - Debugger I/O Window
  - Basic commands to debugger

ClientIOWindow.py [new file with mode: 0755]
DbgTerminal.py [deleted file]
DbgWindow.py [new file with mode: 0755]
GdbWindow.py [new file with mode: 0755]

diff --git a/ClientIOWindow.py b/ClientIOWindow.py
new file mode 100755 (executable)
index 0000000..87f045e
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+#shuber, 2008-06-04
+
+__author__ = "shuber"
+
+
+import gtk
+import vte
+
+
+class ClientIOWindow (gtk.Window):
+
+
+       def __init__(self, parent, pty_master):
+
+               #Set up GTK stuff
+               gtk.Window.__init__(self)
+               self.set_screen(parent.get_screen())
+               self.connect("destroy", lambda *w: gtk.main_quit())
+
+
+               #Set title and add terminal
+               self.set_title("Client I/O")
+               self.terminal = vte.Terminal()
+               self.add(self.terminal)
+
+               #Set the pty to client
+               self.terminal.set_pty(pty_master)
+
+               #Show the window
+               self.show_all()
+
diff --git a/DbgTerminal.py b/DbgTerminal.py
deleted file mode 100755 (executable)
index 88064db..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/python
-
-
-import select
-import string
-import sys
-import thread
-import threading
-import time
-import os
-import pty
-import Queue
-
-
-class DbgTerminal:
-
-       #Reply cache from debugger
-       dbgreplyqueue = Queue.Queue()
-
-
-       def __init__ (self, binary, gdbReadCallback, childReadCallback):
-
-               #Set some members
-               self.gdbReadCallback = gdbReadCallback
-               self.childReadCallback = childReadCallback
-               self.binary = binary
-               self.stopped = False
-
-               #Connect to sub-process
-               self.__connect()
-
-       def __connect( self ):
-
-               #This function handles readings from the debugger
-               def gdbCb(str):
-                       self.gdbReadCallback(str)
-                       self.dbgreplyqueue.put(str)
-
-               #Open pseudo-terminal where to-be-debugged process reads/writes to
-               self.ptymaster, self.ptyslave = pty.openpty()
-               self.childout = os.fdopen(self.ptymaster, "r", 0)
-               self.childin = os.fdopen(self.ptymaster, "w", 0)
-
-               #Call gdb and get in- and out-streams to/from gdb
-               cmd = self.getCommand(self.binary)
-               self.gdbin, self.gdbout = os.popen4( cmd, bufsize=0)
-
-               #Set up a reading thread to gdb output
-               self.gdbReadThread =  self.ReadThread(self.gdbout, gdbCb)
-               self.gdbReadThread.start()
-
-               #Set up a reading thread to childs output
-               self.childReadThread =  self.ReadThread(self.childout, self.childReadCallback)
-               self.childReadThread.start()
-
-               #Set up tty gdb-childs process
-               self.sendSetTTY(os.ttyname(self.ptyslave))
-
-       
-
-       def getDbgReply(self):
-               raise NotImplementedError()
-
-
-       def iseof( self ):
-               """Check if terminal is closed already"""
-               return self.gdbReadThread.eventFin.isSet()
-
-       def stop( self ):
-
-               if not self.stopped:
-
-                       self.stopped = True
-
-                       #Finish the reading-thread
-                       self.gdbReadThread.fin = True
-                       self.childReadThread.fin = True
-                       self.gdbReadThread.eventFin.wait(1)
-                       self.childReadThread.eventFin.wait(1)
-
-
-       def getCommand( self, binary ):
-               """Get the command to execute"""
-               raise NotImplementedError()
-
-       def sendBreak(self, file, lineno):
-               raise NotImplementedError()
-
-       def sendContinue(self):
-               raise NotImplementedError()
-       
-       def sendRun(self):
-               raise NotImplementedError()
-
-       def sendInspectVar(self, var):
-               raise NotImplementedError()
-
-       def sendInspectExpr(self, expr):
-               raise NotImplementedError()
-
-       def sendSetTTY(self, ttyname):
-               raise NotImplementedError()
-       
-       def sendQuit(self):
-               raise NotImplementedError()
-
-
-       class ReadThread (threading.Thread):
-               """Thread which reads from sub-process output"""
-
-               def __init__( self, stream, callback, sleep=0.1):
-                       self.stream = stream
-                       self.fin = False
-                       self.callback = callback
-                       self.sleep = sleep
-                       self.eventFin = threading.Event()
-                       threading.Thread.__init__(self)
-
-               def run(self):
-
-                       try:
-                               while True:
-                                       #Wait until data is available
-                                       rlist, wlist, xlist = select.select([self.stream], [], [], self.sleep)
-
-                                       #If we should finish, finish
-                                       if self.fin:
-                                               break
-
-                                       #Got new data
-                                       if len(rlist) > 0:
-                                               fd = rlist[0]
-                                               str = fd.read(1)
-                                               #Call callbacks
-                                               self.callback(str)
-                       except:
-                               pass
-
-                       #Set the finished event
-                       self.eventFin.set()
-
-
-
-
-class GdbTerminal (DbgTerminal):
-
-       gdbreply = ""
-
-
-       def getCommand( self, binary ):
-               return "gdb --fullname %s" % (binary,)
-
-       def sendBreak(self, file, lineno):
-               self.gdbin.write("break %s:%d\n" % (file, lineno))
-
-       def sendContinue(self):
-               self.gdbin.write("cont\n") 
-
-       def sendRun(self):
-               self.gdbin.write("run\n") 
-
-       def sendInspectVar(self, var):
-               self.sendInspectExpr(var)
-
-       def sendInspectExpr(self, expr):
-               self.gdbin.write("print %s\n" % (expr,))
-
-       def sendSetTTY(self, ttyname):
-               self.gdbin.write("set inferior-tty %s\n" % (ttyname,))
-
-       def sendQuit(self):
-               self.gdbin.write("quit\n")
-               DbgTerminal.stop(self)
-
-       def getDbgReply(self, timeout=None):
-
-               while True:
-                       splits = self.gdbreply.split("\n")
-
-                       #Need more data: If there is a single (gdb) entry, then
-                       #there are at least two splits
-                       if len(splits) <= 1:
-                               try:
-                                       self.gdbreply += self.dbgreplyqueue.get(True, timeout)
-                               except Queue.Empty:
-                                       return None
-                       #Yeah there is data!
-                       else:
-                               self.gdbreply = string.join(splits[1:], "(gdb)")
-                               return string.strip(splits[0])
-
-       def flushDbgReply(self):
-
-               try:
-                       self.gdbreply = ""
-                       #Remove all elements from queue
-                       while True:
-                               self.dbgreplyqueue.get(False)
-               except Queue.Empty:
-                       pass
-
-if __name__ == "__main__":
-
-       def tostdout(str):
-               sys.stdout.write(str)
-               sys.stdout.flush()
-
-       try:
-
-               term = GdbTerminal( "./main", tostdout, tostdout)
-               term.sendBreak("main.cpp", 13)
-               term.sendBreak("main.cpp", 14)
-               term.sendRun()
-               term.childin.write("1\n");
-               term.childin.write("2\n");
-
-               time.sleep(0.2)
-               term.flushDbgReply()
-               term.sendInspectVar("a+b")
-
-               term.sendContinue()
-               term.sendInspectVar("a+b")
-               term.sendContinue()
-
-
-               time.sleep(1)
-
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-               print "reply >>>", term.getDbgReply(1)
-
-
-               while not term.iseof():
-
-                       cmd = sys.stdin.readline()
-
-                       if term.iseof():
-                               break
-
-                       if cmd == "quit\n":
-                               term.sendQuit()
-                       else:
-                               term.gdbin.write(cmd)
-
-       except Exception, e:
-               print e
-       except:
-               pass
-
-
-       print "stopping..."
-       term.stop()
-
-               
-
diff --git a/DbgWindow.py b/DbgWindow.py
new file mode 100755 (executable)
index 0000000..6f46c6c
--- /dev/null
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+#shuber, 2008-06-04
+
+__author__ = "shuber"
+
+
+import gtk
+import pty
+import string
+import time
+import threading
+import vte
+
+import ClientIOWindow
+
+
+class DbgWindow (gtk.Window):
+
+       clientIOWnd = None
+       lastrow = 0
+       history = []
+
+       
+
+       def __init__(self, clientCmd):
+
+               #Set up some members
+               self.clientCmd = clientCmd
+
+               #Set up GTK stuff
+               gtk.Window.__init__(self)
+               self.connect("destroy", lambda *w: gtk.main_quit())
+
+               #Set title and add terminal
+               self.set_title("Debugger I/O")
+               self.terminal = vte.Terminal()
+               self.terminal.history = []
+               self.terminal.history_length = 5
+               self.add(self.terminal)
+
+               #Set up terminal window and initialize debugger
+               self.terminal.connect("child-exited", lambda *w: gtk.main_quit())
+               self.terminal.connect("cursor-moved", self.contents_changed)
+               self._initializeDbg()
+
+               #Show the window
+               self.show_all()
+
+
+       def _initializeDbg(self):
+
+               #Start debugger
+               self.terminal.fork_command( self.getDbgCommand(), self.getDbgArgv())
+
+               #Open pseudo-terminal where to-be-debugged process reads/writes to
+               self.client_ptymaster, self.client_ptyslave = pty.openpty()
+               self.setDbgPty(self.client_ptyslave)
+
+
+       def contents_changed(self, term):
+               c,r = term.get_cursor_position()
+
+               if self.lastrow < r:
+                       text = self.terminal.get_text_range(self.lastrow,0,r-1,-1,lambda *w:True)
+                       self.history += string.split(text, "\n")
+                       self.lastrow = r
+
+       def waitForDbgNewline(self):
+               r = self.lastrow
+               while not self.lastrow > r:
+                       gtk.main_iteration()
+
+       def waitForDbgRx(self, rx):             
+               while True:
+                       start = len(self.history)
+                       gtk.main_iteration()
+
+                       for line in self.history[start:]:
+                               if rx.search(line):
+                                       return line
+
+
+       def getDbgCommand(self):
+               return self.getDbgArgv()[0];
+
+       def getDbgArgv(self):
+               raise NotImplementedError()
+
+       def setDbgPty(self, pty):
+               raise NotImplementedError()
+
+       def setDbgRun(self):
+               raise NotImplementedError()
+
+       def setDbgQuit(self):
+               raise NotImplementedError()
+
+       def setDbgContinue(self):
+               raise NotImplementedError()
+
+       def setDbgBreakpoint(self, file, lineno):
+               raise NotImplementedError()
+
+       def getDbgExpression(self, expr):
+               raise NotImplementedError()
+
+       def getDbgLastLine(self):
+               if len(self.history) == 0:
+                       return None
+
+               return self.history[-1]
+
+       def feed_dbg(self, text):
+               self.terminal.feed_child(text)
+
+
+       def showClientIOWindow(self):
+               if not self.clientIOWnd:
+                       self.clientIOWnd = ClientIOWindow.ClientIOWindow(self, self.client_ptymaster)
+       
+
+
+
+def launchDebugger(wnd):
+
+       wnd.showClientIOWindow()
+
+       wnd.setDbgBreakpoint("main.cpp", 15)
+       wnd.setDbgRun()
+       res = wnd.getDbgExpression("a")
+       print "Result = ", res
+
+       wnd.setDbgQuit()
+
+       gtk.main()
+
+
+
+
+
diff --git a/GdbWindow.py b/GdbWindow.py
new file mode 100755 (executable)
index 0000000..a5baaa8
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+#shuber, 2008-06-04
+
+__author__ = "shuber"
+
+
+import gtk
+import os
+import re
+import string
+import sys
+import time
+
+import DbgWindow
+
+
+class GdbWindow (DbgWindow.DbgWindow):
+
+
+       def __init__(self, clientCmd):
+               DbgWindow.DbgWindow.__init__(self, clientCmd)
+
+       def getDbgArgv(self):
+               return ["gdb", "--fullname", string.split(self.clientCmd)[0]]
+
+       def setDbgPty(self, pty):
+               ttyname = os.ttyname(pty)
+               self.feed_dbg("set inferior-tty %s\n" % (ttyname,))
+
+       def setDbgRun(self):
+               argv = string.join(string.split(self.clientCmd)[1:])
+               self.feed_dbg("run " + argv + "\n")
+
+       def setDbgQuit(self):
+               self.feed_dbg("quit\n")
+               self.waitForDbgNewline()
+               self.feed_dbg("y\n");
+
+       def setDbgContinue(self):
+               self.feed_dbg("cont\n");
+
+       def setDbgBreakpoint(self, file, lineno):
+               self.feed_dbg("break %s:%d\n" % (file, lineno))
+
+       def getDbgExpression(self, expr):
+
+               self.waitForDbgNewline()
+               self.feed_dbg("print " + expr + "\n")
+
+               rx = re.compile("^\$[1-9][0-9]* = .*$")
+               response = self.waitForDbgRx(rx)
+
+               split = string.split(response, "=")
+               return string.join(split[1:], "=").strip()
+
+
+
+if __name__ == "__main__":
+
+
+       gdbwnd = GdbWindow(string.join(sys.argv[1:]))
+       DbgWindow.launchDebugger(gdbwnd)
+
+
+
+