summaryrefslogtreecommitdiffstats
path: root/languages/ruby/debugger/rdbcontroller.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/ruby/debugger/rdbcontroller.cpp')
-rw-r--r--languages/ruby/debugger/rdbcontroller.cpp1414
1 files changed, 1414 insertions, 0 deletions
diff --git a/languages/ruby/debugger/rdbcontroller.cpp b/languages/ruby/debugger/rdbcontroller.cpp
new file mode 100644
index 00000000..160754a0
--- /dev/null
+++ b/languages/ruby/debugger/rdbcontroller.cpp
@@ -0,0 +1,1414 @@
+// *************************************************************************
+// rdbcontroller.cpp - description
+// -------------------
+// begin : Sun Aug 8 1999
+// copyright : (C) 1999 by John Birch
+// email : jbb@kdevelop.org
+//
+// Adapted for ruby debugging
+// --------------------------
+// begin : Mon Nov 1 2004
+// copyright : (C) 2004 by Richard Dale
+// email : Richard_Dale@tipitina.demon.co.uk
+// **************************************************************************
+//
+// **************************************************************************
+// * *
+// * 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. *
+// * *
+// **************************************************************************
+
+#include "rdbcontroller.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#include "breakpoint.h"
+#include "framestackwidget.h"
+#include "rdbcommand.h"
+#include "stty.h"
+#include "variablewidget.h"
+#include "domutil.h"
+#include "settings.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qtextstream.h>
+
+#include <iostream>
+#include <ctype.h>
+#include <stdlib.h>
+using namespace std;
+
+// **************************************************************************
+//
+// Does all the communication between rdb and the kdevelop's debugger code.
+// Significatant classes being used here are
+//
+// RDBParser - parses the "variable" data using the vartree and varitems
+// VarTree - where the variable data will end up
+// FrameStack - tracks the program frames and allows the user to switch between
+// and therefore view the calling funtions and their data
+// Breakpoint - Where and what to do with breakpoints.
+// STTY - the tty that the _application_ will run on.
+//
+// Significant variables
+// state_ - be very careful setting this. The controller is totally
+// dependent on this reflecting the correct state. For instance,
+// if the app is busy but we don't think so, then we lose control
+// of the app. The only way to get out of these situations is to
+// delete (stop) the controller.
+// currentFrame_
+// - Holds the frame number where and locals/variable information will
+// go to
+//
+//
+// **************************************************************************
+
+namespace RDBDebugger
+{
+
+// This is here so we can check for startup /shutdown problems
+int debug_controllerExists = false;
+
+// At the moment a Unix domain socket is used. It might be better to
+// change to tcp/ip and listen on a port instead
+QCString RDBController::unixSocketPath_;
+
+
+RDBController::RDBController(VariableTree *varTree, FramestackWidget *frameStack, QDomDocument &projectDom)
+ : DbgController(),
+ frameStack_(frameStack),
+ varTree_(varTree),
+ currentFrame_(1),
+ viewedThread_(-1),
+ stdoutOutputLen_(0),
+ stdoutOutput_(new char[4096]),
+ holdingZone_(),
+ rdbOutputLen_(0),
+ rdbOutput_(new char[49152]),
+ socketNotifier_(0),
+ currentCmd_(0),
+ currentPrompt_("(rdb:1) "),
+ tty_(0),
+ state_(s_dbgNotStarted|s_appNotStarted|s_silent),
+ programHasExited_(false),
+ dom(projectDom),
+ config_forceBPSet_(true),
+ config_dbgTerminal_(false)
+{
+ struct sockaddr_un sockaddr;
+ unixSocketPath_.sprintf("/tmp/.rubydebugger%d", getpid());
+ QFileInfo unixSocket(unixSocketPath_);
+
+ stdoutSizeofBuf_ = sizeof(stdoutOutput_);
+ rdbSizeofBuf_ = sizeof(rdbOutput_);
+
+ if (unixSocket.exists()) {
+ unlink(unixSocketPath_);
+ }
+
+ masterSocket_ = socket(AF_UNIX, SOCK_STREAM, 0);
+ sockaddr.sun_family = AF_UNIX;
+ strcpy(sockaddr.sun_path, unixSocketPath_);
+ bind(masterSocket_, (const struct sockaddr*) &sockaddr, sizeof(sockaddr));
+ listen(masterSocket_, 1);
+ acceptNotifier_ = new QSocketNotifier(masterSocket_, QSocketNotifier::Read, this);
+ QObject::connect( acceptNotifier_, SIGNAL(activated(int)),
+ this, SLOT(slotAcceptConnection(int)) );
+
+ configure();
+ cmdList_.setAutoDelete(true);
+
+ Q_ASSERT(! debug_controllerExists);
+ debug_controllerExists = true;
+}
+
+// **************************************************************************
+
+// Deleting the controller involves shutting down rdb nicely.
+// When were attached to a process, we must first detach so that the process
+// can continue running as it was before being attached. rdb is quite slow to
+// detach from a process, so we must process events within here to get a "clean"
+// shutdown.
+RDBController::~RDBController()
+{
+ delete[] stdoutOutput_;
+ delete[] rdbOutput_;
+ debug_controllerExists = false;
+
+ QFileInfo unixSocket(unixSocketPath_);
+ if (unixSocket.exists()) {
+ unlink(unixSocketPath_);
+ }
+}
+
+// **************************************************************************
+
+void RDBController::configure()
+{
+}
+
+// **************************************************************************
+
+// Fairly obvious that we'll add whatever command you give me to a queue
+// If you tell me to, I'll put it at the head of the queue so it'll run ASAP
+// Not quite so obvious though is that if we are going to run again. then any
+// information requests become redundent and must be removed.
+// We also try and run whatever command happens to be at the head of
+// the queue.
+void RDBController::queueCmd(DbgCommand *cmd, bool executeNext)
+{
+ // We remove any info command or _run_ command if we are about to
+ // add a run command.
+ if (cmd->isARunCmd())
+ removeInfoRequests();
+
+ if (executeNext)
+ cmdList_.insert(0, cmd);
+ else
+ cmdList_.append (cmd);
+}
+
+// **************************************************************************
+
+// If the appliction can accept a command and we've got one waiting
+// then send it.
+// Commands can be just request for data (or change rdbs state in someway)
+// or they can be "run" commands. If a command is sent to rdb our internal
+// state will get updated.
+void RDBController::executeCmd()
+{
+ if (stateIsOn(s_dbgNotStarted|s_waitForWrite|s_appBusy|s_shuttingDown) || !dbgProcess_)
+ return;
+
+ if (currentCmd_ == 0) {
+ if (cmdList_.isEmpty())
+ return;
+
+ currentCmd_ = cmdList_.take(0);
+ }
+
+ if (!currentCmd_->moreToSend()) {
+ delete currentCmd_;
+ if (cmdList_.isEmpty()) {
+ currentCmd_ = 0;
+ return;
+ }
+
+ currentCmd_ = cmdList_.take(0);
+ }
+
+ char * ptr = currentCmd_->cmdToSend().data();
+ int bytesToWrite = currentCmd_->cmdLength();
+ int bytesWritten = 0;
+
+ while (bytesToWrite > 0) {
+ bytesWritten = write(socket_, ptr, bytesToWrite);
+ bytesToWrite -= bytesWritten;
+ ptr += bytesWritten;
+ }
+
+ if (currentCmd_->isARunCmd()) {
+ setStateOn(s_appBusy);
+ kdDebug(9012) << "App is busy" << endl;
+ setStateOff(s_appNotStarted|s_programExited|s_silent);
+ }
+
+ QString prettyCmd = currentCmd_->cmdToSend();
+ prettyCmd = currentPrompt_ + prettyCmd;
+ emit rdbStdout( prettyCmd.latin1() );
+
+ if (!stateIsOn(s_silent))
+ emit dbgStatus("", state_);
+}
+
+// **************************************************************************
+
+void RDBController::destroyCmds()
+{
+ if (currentCmd_)
+ {
+ delete currentCmd_;
+ currentCmd_ = 0;
+ }
+
+ while (!cmdList_.isEmpty())
+ delete cmdList_.take(0);
+}
+
+// **********************************************************************
+
+void RDBController::removeInfoRequests()
+{
+ int i = cmdList_.count();
+ while (i)
+ {
+ i--;
+ DbgCommand *cmd = cmdList_.at(i);
+ if (cmd->isAnInfoCmd() || cmd->isARunCmd())
+ delete cmdList_.take(i);
+ }
+}
+
+// **********************************************************************
+
+// Pausing an app removes any pending run commands so that the app doesn't
+// start again. If we want to be silent then we remove any pending info
+// commands as well.
+void RDBController::pauseApp()
+{
+ int i = cmdList_.count();
+ while (i)
+ {
+ i--;
+ DbgCommand *cmd = cmdList_.at(i);
+ if ((stateIsOn(s_silent) && cmd->isAnInfoCmd()) || cmd->isARunCmd())
+ delete cmdList_.take(i);
+ }
+
+ if (dbgProcess_ && stateIsOn(s_appBusy))
+ dbgProcess_->kill(SIGINT);
+}
+
+// **********************************************************************
+
+// Whenever the program pauses we need to refresh the data visible to
+// the user. The reason we've stopped may be passed in to be emitted.
+void RDBController::actOnProgramPause(const QString &msg)
+{
+ // We're only stopping if we were running, of course.
+ if (stateIsOn(s_appBusy))
+ {
+ kdDebug(9012) << "App is paused" << endl;
+ setStateOff(s_appBusy);
+ if (stateIsOn(s_silent))
+ return;
+
+ emit dbgStatus (msg, state_);
+
+ // We're always at frame one when the program stops
+ // and we must reset the active flag
+ currentFrame_ = 1;
+ varTree_->nextActivationId();
+ setStateOn(s_fetchLocals);
+
+ queueCmd(new RDBCommand("where", NOTRUNCMD, INFOCMD), true);
+ queueCmd(new RDBCommand("thread list", NOTRUNCMD, INFOCMD), true);
+
+ if (stateIsOn(s_fetchGlobals)) {
+ queueCmd(new RDBCommand("var global", NOTRUNCMD, INFOCMD));
+ }
+
+ emit acceptPendingBPs();
+ }
+}
+
+// **************************************************************************
+
+// There is no app anymore. This can be caused by program exiting
+// an invalid program specified or ...
+// rdb is still running though, but only the run command (may) make sense
+// all other commands are disabled.
+void RDBController::programNoApp(const QString &msg, bool msgBox)
+{
+ state_ = (s_appNotStarted|s_programExited|(state_&(s_shuttingDown)));
+ destroyCmds();
+
+ // We're always at frame one when the program stops
+ // and we must reset the active flag
+ viewedThread_ = -1;
+ currentFrame_ = 1;
+ varTree_->nextActivationId();
+
+ // Now wipe the tree out
+ varTree_->viewport()->setUpdatesEnabled(false);
+ varTree_->prune();
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+
+ frameStack_->clear();
+
+ if (msgBox)
+ KMessageBox::error(0, i18n("rdb message:\n")+msg);
+
+ emit dbgStatus (msg, state_);
+}
+
+// **************************************************************************
+
+// The program location falls out of rdb. We treat
+// it as a wrapped command.
+// The data gets parsed here and emitted in its component parts.
+void RDBController::parseProgramLocation(char *buf)
+{
+ QString buffer(buf);
+ QString line;
+ QTextStream input(&buffer, IO_ReadOnly);
+ QString sourceFile;
+ int sourceLine = 0;
+
+ // "1: a = 1"
+ QRegExp display_re("^(\\d+):\\s(.*)$");
+
+ // "/opt/qt/src/widgets/qlistview.rb:1558:puts 'hello world'"
+ QRegExp sourcepos_re("^([^:]+):(\\d+):");
+
+ line = input.readLine();
+ while (! line.isNull()) {
+ if (sourcepos_re.search(line, 0) >= 0) {
+ sourceFile = sourcepos_re.cap(1);
+ sourceLine = sourcepos_re.cap(2).toInt();
+ } else if (display_re.search(line, 0) >= 0) {
+ varTree_->watchRoot()->updateWatchExpression(display_re.cap(1).toInt(), display_re.cap(2));
+ }
+
+ line = input.readLine();
+ }
+
+ if ( !sourceFile.isNull()
+ && ( traceIntoRuby_
+ || ( !sourceFile.endsWith("/qtruby.rb")
+ && !sourceFile.endsWith("/korundum.rb") ) )
+ && !sourceFile.endsWith("/debuggee.rb") )
+ {
+ actOnProgramPause(QString());
+ emit showStepInSource(sourceFile, sourceLine, "");
+ return;
+ }
+
+ if (stateIsOn(s_appBusy))
+ actOnProgramPause(i18n("No source: %1").arg(sourceFile));
+ else
+ emit dbgStatus (i18n("No source: %1").arg(sourceFile), state_);
+}
+
+// **************************************************************************
+
+// parsing the backtrace list will cause the vartree to be refreshed
+void RDBController::parseBacktraceList(char *buf)
+{
+ frameStack_->parseRDBBacktraceList(buf);
+}
+
+// **************************************************************************
+
+void RDBController::parseThreadList(char *buf)
+{
+ frameStack_->parseRDBThreadList(buf);
+ viewedThread_ = frameStack_->viewedThread();
+ varTree_->setCurrentThread(viewedThread_);
+}
+
+// **************************************************************************
+
+void RDBController::parseSwitchThread(char *buf)
+{
+ // Look for the thread number
+ // 2 #<Thread:0x30091998 sleep> /home/duke/play/testit/trykorundum/src/bar.rb:13
+ QRegExp thread_re("(\\d+)");
+ if (thread_re.search(buf) != -1) {
+ viewedThread_ = thread_re.cap(1).toInt();
+ currentFrame_ = 1;
+ }
+}
+
+// **************************************************************************
+
+// After an 'up nnn' or 'down nnn' command, get the new source file and line no.
+void RDBController::parseFrameMove(char *buf)
+{
+ QString sourceFile;
+ int sourceLine = 0;
+
+ if (stateIsOn(s_fetchLocals)) {
+ return;
+ }
+
+ // "#2 /home/duke/play/testit/trykorundum/src/main.rb:11"
+ QRegExp sourcepos_re("#\\d+\\s([^:]+):(\\d+)");
+ if (sourcepos_re.search(buf) != -1) {
+ sourceFile = sourcepos_re.cap(1);
+ sourceLine = sourcepos_re.cap(2).toInt();
+
+ if ( !sourceFile.isNull()
+ && ( traceIntoRuby_
+ || ( !sourceFile.endsWith("/qtruby.rb")
+ && !sourceFile.endsWith("/korundum.rb") ) )
+ && !sourceFile.endsWith("/debuggee.rb") )
+ {
+ emit showStepInSource(sourceFile, sourceLine, "");
+ return;
+ }
+ }
+
+ emit dbgStatus(i18n("No source: %1").arg(sourceFile), state_);
+}
+
+// **************************************************************************
+
+// When a breakpoint has been set, rdb responds with some data about the
+// new breakpoint. We just inform the breakpoint system about this.
+void RDBController::parseBreakpointSet(char *buf)
+{
+ if (RDBSetBreakpointCommand *BPCmd = dynamic_cast<RDBSetBreakpointCommand*>(currentCmd_))
+ {
+ // ... except in this case :-) A -1 key tells us that this is
+ // a special internal breakpoint, and we shouldn't do anything
+ // with it. Currently there are _no_ internal breakpoints.
+ if (BPCmd->getKey() != -1) {
+ emit rawRDBBreakpointSet(buf, BPCmd->getKey());
+ }
+ }
+}
+
+// **************************************************************************
+
+// Extra data needed by an item was requested. Here's the result.
+// If it's an ordinary 'p ' command then just echo the result on
+// the RDB console and don't bother parsing.
+void RDBController::parseRequestedData(char *buf)
+{
+ if (RDBItemCommand *rdbItemCommand = dynamic_cast<RDBItemCommand*> (currentCmd_))
+ {
+ // Fish out the item from the command and let it deal with the data
+ VarItem *item = rdbItemCommand->getItem();
+ varTree_->viewport()->setUpdatesEnabled(false);
+ item->expandValue(buf);
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+ }
+}
+
+
+// **************************************************************************
+
+// Select a different frame to view. We need to get and (maybe) display
+// where we are in the program source.
+void RDBController::parseFrameSelected(char *buf)
+{
+ if (!stateIsOn(s_silent)) {
+ emit showStepInSource("", -1, "");
+ emit dbgStatus (i18n("No source: %1").arg(QString(buf)), state_);
+ }
+}
+
+// **************************************************************************
+
+// Sets the id of the display in the VarTree and a current value.
+void RDBController::parseDisplay(char *buf, char * expr)
+{
+ varTree_->viewport()->setUpdatesEnabled(false);
+ varTree_->watchRoot()->setWatchExpression(buf, expr);
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+}
+
+// **************************************************************************
+
+// Updates the watch expressions with current values
+void RDBController::parseUpdateDisplay(char *buf)
+{
+ varTree_->viewport()->setUpdatesEnabled(false);
+
+ QRegExp display_re("(\\d+):\\s([^\n]*)\n");
+
+ int pos = display_re.search(buf);
+ while (pos != -1) {
+ varTree_->watchRoot()->updateWatchExpression(display_re.cap(1).toInt(), display_re.cap(2));
+
+ pos += display_re.matchedLength();
+ pos = display_re.search(buf, pos);
+ }
+
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+}
+
+// **************************************************************************
+
+// This is called on program stop to process the globals.
+void RDBController::parseGlobals(char *buf)
+{
+ varTree_->viewport()->setUpdatesEnabled(false);
+ varTree_->globalRoot()->setGlobals(buf);
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+}
+
+// **************************************************************************
+
+// This is called on program stop to process the locals.
+// Once the locals have been processed we prune the tree of items that are
+// inactive.
+void RDBController::parseLocals(char type, char *buf)
+{
+ varTree_->viewport()->setUpdatesEnabled(false);
+
+ // The locals are always attached to the currentFrame
+ VarFrameRoot *frame = varTree_->findFrame(currentFrame_, viewedThread_);
+ if (!frame)
+ {
+ frame = new VarFrameRoot(varTree_, currentFrame_, viewedThread_);
+ frame->setFrameName(
+ frameStack_->findFrame(currentFrame_, viewedThread_)->frameName());
+ }
+
+ Q_ASSERT(frame);
+
+ if (type == (char) CONSTANTS) {
+ frame->addLocals(buf);
+ } else if (type == (char) CVARS) {
+ frame->addLocals(buf);
+ } else if (type == (char) IVARS) {
+ frame->addLocals(buf);
+ } else {
+ frame->addLocals(buf);
+ frame->setLocals();
+ }
+
+ varTree_->viewport()->setUpdatesEnabled(true);
+ varTree_->repaint();
+}
+
+
+
+// **************************************************************************
+
+void RDBController::parse(char *buf)
+{
+ if (currentCmd_ == 0) {
+ return;
+ }
+
+ if (currentCmd_->isARunCmd()) {
+ parseProgramLocation(buf);
+ } else if (currentCmd_->rawDbgCommand() == "break") {
+ emit rawRDBBreakpointList(buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "break ", strlen("break ")) == 0) {
+ parseBreakpointSet(buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "watch ", strlen("watch ")) == 0) {
+ parseBreakpointSet(buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "display ", strlen("display ")) == 0) {
+ parseDisplay(buf, currentCmd_->rawDbgCommand().data() + strlen("display "));
+ } else if (currentCmd_->rawDbgCommand() == "display") {
+ parseUpdateDisplay(buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "undisplay ", strlen("undisplay ")) == 0) {
+ ;
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "method instance ", strlen("method instance ")) == 0) {
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "method ", strlen("method ")) == 0) {
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "pp ", strlen("pp ")) == 0) {
+ parseRequestedData(buf);
+ } else if (currentCmd_->rawDbgCommand() == "thread list") {
+ parseThreadList(buf);
+ } else if ( qstrncmp(currentCmd_->rawDbgCommand(), "up ", strlen("up ")) == 0
+ || qstrncmp(currentCmd_->rawDbgCommand(), "down ", strlen("down ")) == 0 )
+ {
+ parseFrameMove(buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "thread switch ", strlen("thread switch ")) == 0) {
+ parseSwitchThread(buf);
+ } else if (currentCmd_->rawDbgCommand() == "thread current") {
+ parseThreadList(buf);
+ } else if (currentCmd_->rawDbgCommand() == "where") {
+ parseBacktraceList(buf);
+ } else if (currentCmd_->rawDbgCommand() == "var global") {
+ parseGlobals(buf);
+ } else if (currentCmd_->rawDbgCommand() == "var local") {
+ parseLocals(LOCALS, buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "var instance ", strlen("var instance ")) == 0) {
+ parseLocals(IVARS, buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "var class ", strlen("var class ")) == 0) {
+ parseLocals(CVARS, buf);
+ } else if (qstrncmp(currentCmd_->rawDbgCommand(), "var const ", strlen("var const ")) == 0) {
+ parseLocals(CONSTANTS, buf);
+ }
+
+ return;
+}
+
+// **************************************************************************
+
+void RDBController::setBreakpoint(const QCString &BPSetCmd, int key)
+{
+ queueCmd(new RDBSetBreakpointCommand(BPSetCmd, key));
+}
+
+// **************************************************************************
+
+void RDBController::clearBreakpoint(const QCString &BPClearCmd)
+{
+ queueCmd(new RDBCommand(BPClearCmd, NOTRUNCMD, NOTINFOCMD));
+ // Note: this is NOT an info command, because rdb doesn't explictly tell
+ // us that the breakpoint has been deleted, so if we don't have it the
+ // BP list doesn't get updated.
+ queueCmd(new RDBCommand("break", NOTRUNCMD, NOTINFOCMD));
+}
+
+// **************************************************************************
+
+void RDBController::modifyBreakpoint( const Breakpoint& BP )
+{
+ Q_ASSERT(BP.isActionModify());
+ if (BP.dbgId() > 0)
+ {
+ if (BP.changedEnable())
+ queueCmd(new RDBCommand(QCString().sprintf("%s %d",
+ BP.isEnabled() ? "enable" : "disable",
+ BP.dbgId()), NOTRUNCMD, NOTINFOCMD));
+
+ // BP.setDbgProcessing(true);
+ // Note: this is NOT an info command, because rdb doesn't explictly tell
+ // us that the breakpoint has been deleted, so if we don't have it the
+ // BP list doesn't get updated.
+ queueCmd(new RDBCommand("break", NOTRUNCMD, NOTINFOCMD));
+ }
+}
+
+// **************************************************************************
+// SLOTS
+// *****
+// For most of these slots data can only be sent to rdb when it
+// isn't busy and it is running.
+
+// **************************************************************************
+
+void RDBController::slotStart(const QString& ruby_interpreter, const QString& character_coding, const QString& run_directory, const QString& debuggee_path, const QString &application, const QString& run_arguments, bool show_constants, bool trace_into_ruby)
+{
+ Q_ASSERT (!dbgProcess_ && !tty_);
+
+// tty_ = new STTY(config_dbgTerminal_, "konsole");
+ tty_ = new STTY(config_dbgTerminal_, Settings::terminalEmulatorName( *kapp->config() ));
+ if (!config_dbgTerminal_)
+ {
+ connect( tty_, SIGNAL(OutOutput(const char*)), SIGNAL(ttyStdout(const char*)) );
+ connect( tty_, SIGNAL(ErrOutput(const char*)), SIGNAL(ttyStderr(const char*)) );
+ }
+
+ QString tty(tty_->getSlave());
+ if (tty.isEmpty())
+ {
+ KMessageBox::error(0, i18n("The ruby debugger cannot use the tty* or pty* devices.\n"
+ "Check the settings on /dev/tty* and /dev/pty*\n"
+ "As root you may need to \"chmod ug+rw\" tty* and pty* devices "
+ "and/or add the user to the tty group using "
+ "\"usermod -G tty username\"."));
+
+ delete tty_;
+ tty_ = 0;
+ return;
+ }
+
+ dbgProcess_ = new KProcess;
+
+ connect( dbgProcess_, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ this, SLOT(slotDbgStdout(KProcess *, char *, int)) );
+
+ connect( dbgProcess_, SIGNAL(receivedStderr(KProcess *, char *, int)),
+ this, SLOT(slotDbgStderr(KProcess *, char *, int)) );
+
+ connect( dbgProcess_, SIGNAL(wroteStdin(KProcess *)),
+ this, SLOT(slotDbgWroteStdin(KProcess *)) );
+
+ connect( dbgProcess_, SIGNAL(processExited(KProcess*)),
+ this, SLOT(slotDbgProcessExited(KProcess*)) );
+
+ rubyInterpreter_ = ruby_interpreter;
+ characterCoding_ = character_coding;
+ runDirectory_ = run_directory;
+ debuggeePath_ = debuggee_path;
+ application_ = application;
+ runArguments_ = run_arguments;
+ showConstants_ = show_constants;
+ traceIntoRuby_ = trace_into_ruby;
+
+ *dbgProcess_ << ruby_interpreter;
+ *dbgProcess_ << character_coding;
+ *dbgProcess_ << "-C" << QString(QFile::encodeName( run_directory ));
+ *dbgProcess_ << "-r" << debuggee_path;
+ *dbgProcess_ << application;
+
+ if (!run_arguments.isNull() && !run_arguments.isEmpty()) {
+ *dbgProcess_ << run_arguments;
+ }
+
+ emit rdbStdout(QString( ruby_interpreter + " " + character_coding
+ + " -C " + QString(QFile::encodeName( run_directory ))
+ + " -r " + debuggee_path + " "
+ + application + " " + run_arguments ).latin1() );
+
+ if (!dbgProcess_->start( KProcess::NotifyOnExit,
+ KProcess::Communication(KProcess::All)) )
+ {
+ kdDebug(9012) << "Couldn't start ruby debugger" << endl;
+ }
+
+ // Initialise rdb. At this stage rdb is sitting wondering what to do,
+ // and to whom. Organise a few things, then set up the tty for the application,
+ // and the application itself
+
+ // Now the ruby debugger has been started and the application has been loaded,
+ // BUT the app hasn't been started yet! A run command is about to be issued
+ // by whoever is controlling us.
+
+ if (!dbgProcess_->writeStdin(QString("%1\n").arg(unixSocketPath_).latin1(), strlen(unixSocketPath_) + 1)) {
+ kdDebug(9012) << "failed to write Unix domain socket path to rdb "
+ << QString("%1\n").arg(unixSocketPath_).latin1() << endl;
+ }
+
+ setStateOff(s_programExited);
+ setStateOn(s_dbgNotStarted|s_appNotStarted|s_silent);
+}
+
+// **************************************************************************
+
+void RDBController::slotStopDebugger()
+{
+ if (stateIsOn(s_shuttingDown) || !dbgProcess_)
+ return;
+
+ setStateOn(s_shuttingDown|s_silent);
+ destroyCmds();
+
+ QTime start;
+ QTime now;
+
+ // Get rdb's attention if it's busy. We need rdb to be at the
+ // command line so we can stop it.
+ if (stateIsOn(s_appBusy))
+ {
+ kdDebug(9012) << "ruby debugger busy on shutdown - stopping rdb (SIGINT)" << endl;
+ dbgProcess_->kill(SIGINT);
+ start = QTime::currentTime();
+ while (-1)
+ {
+ kapp->processEvents(20);
+ now = QTime::currentTime();
+ if (!stateIsOn(s_appBusy) || start.msecsTo( now ) > 2000)
+ break;
+ }
+ }
+
+
+ // Now try to stop the ruby debugger running.
+ kdDebug(9012) << "App is busy" << endl;
+ setStateOn(s_appBusy);
+ const char *quit="quit\n";
+ if (!dbgProcess_->writeStdin(quit, strlen(quit)))
+ kdDebug(9012) << "failed to write 'quit' to ruby debugger" << endl;
+
+ emit rdbStdout("(rdb:1) quit");
+ start = QTime::currentTime();
+ while (-1)
+ {
+ kapp->processEvents(20);
+ now = QTime::currentTime();
+ if (stateIsOn(s_programExited) || start.msecsTo( now ) > 2000)
+ break;
+ }
+
+ // We cannot wait forever.
+ if (!stateIsOn(s_programExited))
+ {
+ kdDebug(9012) << "rdb not shutdown - killing" << endl;
+ dbgProcess_->kill(SIGKILL);
+ }
+
+ delete dbgProcess_; dbgProcess_ = 0;
+ delete tty_; tty_ = 0;
+
+ state_ = s_dbgNotStarted | s_appNotStarted | s_silent;
+ emit dbgStatus (i18n("Debugger stopped"), state_);
+}
+
+
+
+// **************************************************************************
+
+void RDBController::slotRun()
+{
+ if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown))
+ return;
+
+ if (stateIsOn(s_programExited)) {
+ slotStart(rubyInterpreter_, characterCoding_, runDirectory_, debuggeePath_, application_, runArguments_, showConstants_, traceIntoRuby_);
+ return;
+ }
+
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+// **************************************************************************
+
+void RDBController::slotRunUntil(const QString &fileName, int lineNum)
+{
+ if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown))
+ return;
+
+ if (fileName.isEmpty())
+ queueCmd(new RDBCommand( QCString().sprintf("break %d", lineNum),
+ RUNCMD, NOTINFOCMD));
+ else
+ queueCmd(new RDBCommand(
+ QCString().sprintf("break %s:%d", fileName.latin1(), lineNum),
+ RUNCMD, NOTINFOCMD));
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+// **************************************************************************
+
+void RDBController::slotStepInto()
+{
+ if (stateIsOn(s_appBusy|s_appNotStarted|s_shuttingDown))
+ return;
+
+ queueCmd(new RDBCommand("step", RUNCMD, NOTINFOCMD));
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+
+// **************************************************************************
+
+void RDBController::slotStepOver()
+{
+ if (stateIsOn(s_appBusy|s_appNotStarted|s_shuttingDown))
+ return;
+
+ queueCmd(new RDBCommand("next", RUNCMD, NOTINFOCMD));
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+
+// **************************************************************************
+
+void RDBController::slotStepOutOff()
+{
+ if (stateIsOn(s_appBusy|s_appNotStarted|s_shuttingDown))
+ return;
+
+ queueCmd(new RDBCommand("finish", RUNCMD, NOTINFOCMD));
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+// **************************************************************************
+
+// Only interrupt a running program.
+void RDBController::slotBreakInto()
+{
+ pauseApp();
+}
+
+// **************************************************************************
+
+// See what, if anything needs doing to this breakpoint.
+void RDBController::slotBPState( const Breakpoint& BP )
+{
+ // Are we in a position to do anything to this breakpoint?
+ if (stateIsOn(s_dbgNotStarted|s_shuttingDown) || !BP.isPending() ||
+ BP.isActionDie())
+ return;
+
+ // We need this flag so that we can continue execution. I did use
+ // the s_silent state flag but it can be set prior to this method being
+ // called, hence is invalid.
+ bool restart = false;
+ if (stateIsOn(s_appBusy))
+ {
+ if (!config_forceBPSet_)
+ return;
+
+ // When forcing breakpoints to be set/unset, interrupt a running app
+ // and change the state.
+ setStateOn(s_silent);
+ pauseApp();
+ restart = true;
+ }
+
+ if (BP.isActionAdd())
+ {
+ setBreakpoint(BP.dbgSetCommand().latin1(), BP.key());
+ // BP.setDbgProcessing(true);
+ }
+ else
+ {
+ if (BP.isActionClear())
+ {
+ clearBreakpoint(BP.dbgRemoveCommand().latin1());
+ // BP.setDbgProcessing(true);
+ }
+ else
+ {
+ if (BP.isActionModify())
+ {
+ modifyBreakpoint(BP); // Note: DbgProcessing gets set in modify fn
+ }
+ }
+ }
+
+ if (restart)
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+}
+
+// **************************************************************************
+
+void RDBController::slotClearAllBreakpoints()
+{
+ // Are we in a position to do anything to this breakpoint?
+ if (stateIsOn(s_dbgNotStarted|s_shuttingDown))
+ return;
+
+ bool restart = false;
+ if (stateIsOn(s_appBusy))
+ {
+ if (!config_forceBPSet_)
+ return;
+
+ // When forcing breakpoints to be set/unset, interrupt a running app
+ // and change the state.
+ setStateOn(s_silent);
+ pauseApp();
+ restart = true;
+ }
+
+ queueCmd(new RDBCommand("delete", NOTRUNCMD, NOTINFOCMD));
+ // Note: this is NOT an info command, because rdb doesn't explictly tell
+ // us that the breakpoint has been deleted, so if we don't have it the
+ // BP list doesn't get updated.
+ queueCmd(new RDBCommand("break", NOTRUNCMD, NOTINFOCMD));
+
+ if (restart)
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+
+ executeCmd();
+}
+
+
+
+// **************************************************************************
+
+void RDBController::slotSelectFrame(int frameNo, int threadNo, const QString& frameName)
+{
+ if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown)) {
+ kdDebug(9012) << "RDBController::slotSelectFrame wrong state" << endl;
+ return;
+ }
+
+ if (viewedThread_ != threadNo) {
+ // Note that 'thread switch nnn' is a run command
+ queueCmd(new RDBCommand(QCString().sprintf("thread switch %d",
+ threadNo), RUNCMD, INFOCMD));
+ executeCmd();
+ return;
+ }
+
+ if (frameNo > currentFrame_) {
+ queueCmd(new RDBCommand(QCString().sprintf("up %d", frameNo - currentFrame_), NOTRUNCMD, INFOCMD));
+ if (!stateIsOn(s_fetchLocals)) {
+ queueCmd(new RDBCommand("display", NOTRUNCMD, INFOCMD));
+ }
+ } else if (frameNo < currentFrame_) {
+ queueCmd(new RDBCommand(QCString().sprintf("down %d", currentFrame_ - frameNo), NOTRUNCMD, INFOCMD));
+ if (!stateIsOn(s_fetchLocals)) {
+ queueCmd(new RDBCommand("display", NOTRUNCMD, INFOCMD));
+ }
+ }
+
+ // Hold on to this thread/frame so that we know where to put the local
+ // variables if generated.
+ viewedThread_ = threadNo;
+ currentFrame_ = frameNo;
+
+ VarFrameRoot *frame = varTree_->findFrame(frameNo, viewedThread_);
+ if (frame == 0) {
+ frame = new VarFrameRoot(varTree_, currentFrame_, viewedThread_);
+ }
+
+ frame->setFrameName(frameName);
+ varTree_->setSelected(frame, true);
+
+ // Have we already got these details?
+ if (frame->needsVariables()) {
+ // Ask for the locals
+
+ if (showConstants_) {
+ queueCmd(new RDBCommand("var const self.class", NOTRUNCMD, INFOCMD));
+ }
+
+ queueCmd(new RDBCommand("var instance self", NOTRUNCMD, INFOCMD));
+ queueCmd(new RDBCommand("var class self.class", NOTRUNCMD, INFOCMD));
+ queueCmd(new RDBCommand("var local", NOTRUNCMD, INFOCMD));
+ frame->startWaitingForData();
+ }
+
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+
+ return;
+}
+
+
+
+// **************************************************************************
+
+// This is called when an item needs special processing to show a value.
+void RDBController::slotExpandItem(VarItem *item, const QCString &userRequest)
+{
+ if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown))
+ return;
+
+ Q_ASSERT(item != 0);
+
+ // Bad user data!!
+ if (userRequest.isEmpty())
+ return;
+
+ queueCmd(new RDBItemCommand(item, QCString("pp ") + userRequest.data(), false));
+
+ if (currentCmd_ == 0) {
+ executeCmd();
+ }
+}
+
+// **************************************************************************
+
+// This method evaluates text selected with the 'Inspect:' context menu
+void RDBController::slotRubyInspect(const QString &inspectText)
+{
+ queueCmd(new RDBCommand( QCString().sprintf("p %s", inspectText.latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ executeCmd();
+}
+
+
+// **************************************************************************
+
+// Add a new expression to be displayed in the Watch variable tree
+void RDBController::slotAddWatchExpression(const QString& expr, bool execute)
+{
+ queueCmd(new RDBCommand( QCString().sprintf("display %s", expr.latin1()),
+ NOTRUNCMD,
+ NOTINFOCMD ) );
+ if (execute) {
+ executeCmd();
+ }
+}
+
+// **************************************************************************
+
+// Add a new expression to be displayed in the Watch variable tree
+void RDBController::slotRemoveWatchExpression(int displayId)
+{
+ queueCmd(new RDBCommand( QCString().sprintf("undisplay %d", displayId),
+ NOTRUNCMD,
+ INFOCMD ) );
+ executeCmd();
+}
+
+
+// **************************************************************************
+
+// The user will only get globals if the Global frame is open
+void RDBController::slotFetchGlobals(bool fetch)
+{
+ if (fetch) {
+ setStateOn(s_fetchGlobals);
+ queueCmd(new RDBCommand("var global", NOTRUNCMD, INFOCMD));
+ executeCmd();
+ } else {
+ setStateOff(s_fetchGlobals);
+ }
+
+ kdDebug(9012) << (fetch ? "<Globals ON>": "<Globals OFF>") << endl;
+}
+
+// **************************************************************************
+
+// Data from the ruby program's stdout gets processed here.
+void RDBController::slotDbgStdout(KProcess *, char *buf, int buflen)
+{
+ QCString msg(buf, buflen+1);
+ emit ttyStdout(msg);
+}
+
+// **************************************************************************
+
+// Data from the ruby program's stderr gets processed here.
+void RDBController::slotDbgStderr(KProcess *, char *buf, int buflen)
+{
+ QCString msg(buf, buflen+1);
+ emit ttyStderr(msg);
+}
+
+// **************************************************************************
+
+void RDBController::slotDbgWroteStdin(KProcess *)
+{
+// setStateOff(s_waitForWrite);
+ // if (!stateIsOn(s_silent))
+ // emit dbgStatus ("", state_);
+// executeCmd();
+}
+
+// **************************************************************************
+
+void RDBController::slotAcceptConnection(int masterSocket)
+{
+ Q_ASSERT(masterSocket == masterSocket_);
+
+ struct sockaddr sockaddr;
+ socklen_t fromlen;
+
+ if (socketNotifier_ != 0) {
+ close(socket_);
+ delete socketNotifier_;
+ }
+
+ socket_ = accept(masterSocket, &sockaddr, &fromlen);
+ if (fcntl(socket_, F_SETFL, O_NONBLOCK) == -1) {
+ kdDebug(9012) << "RDBController::slotAcceptConnection can't set nonblocking socket " << errno << endl;
+ }
+
+ socketNotifier_ = new QSocketNotifier(socket_, QSocketNotifier::Read, 0);
+ QObject::connect( socketNotifier_, SIGNAL(activated(int)),
+ this, SLOT(slotReadFromSocket(int)) );
+
+ setStateOff(s_dbgNotStarted);
+ emit dbgStatus ("", state_);
+
+ cmdList_.clear();
+ rdbOutputLen_ = 0;
+
+ // Organise any breakpoints.
+ emit acceptPendingBPs();
+
+ if (traceIntoRuby_) {
+ queueCmd(new RDBCommand("trace_ruby on", NOTRUNCMD, NOTINFOCMD));
+ }
+
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+
+ // Reset the display id for any watch expressions already in the variable tree
+ varTree_->resetWatchVars();
+}
+
+// **************************************************************************
+
+// Output from rdb via the Unix socket gets processed here.
+void RDBController::slotReadFromSocket(int socket)
+{
+ Q_ASSERT(socket == socket_);
+
+ static bool parsing = false;
+
+ int bytesRead = read(socket, rdbOutput_ + rdbOutputLen_, rdbSizeofBuf_);
+
+ rdbOutputLen_ += bytesRead;
+ *(rdbOutput_ + rdbOutputLen_) = 0;
+
+
+ // Already parsing? then get out quick.
+ if (parsing)
+ {
+ kdDebug(9012) << "Already parsing" << endl;
+ return;
+ }
+
+// kdDebug(9012) << "RDBController::slotReadFromSocket length: " << rdbOutputLen_ << " input: " << rdbOutput_ << endl;
+
+ QRegExp prompt_re("(\\(rdb:(\\d+)\\) )$");
+ int promptPos = prompt_re.search(rdbOutput_, 0);
+
+ // Keep appending output to the rbdOutput_ buffer until the
+ // ruby debugger writes the next prompt
+ if (promptPos == -1) {
+ return;
+ }
+
+// kdDebug(9012) << "RDBController::slotReadFromSocket length: " << rdbOutputLen_ << " input: " << rdbOutput_ << endl;
+
+ // Save the prompt, and remove it from the buffer
+ currentPrompt_ = prompt_re.cap(1).latin1();
+ rdbOutputLen_ -= prompt_re.matchedLength();
+ *(rdbOutput_ + rdbOutputLen_) = 0;
+
+ emit rdbStdout(rdbOutput_);
+
+ parsing = true;
+ parse(rdbOutput_);
+ parsing = false;
+ rdbOutputLen_ = 0;
+
+ executeCmd();
+
+ if (currentCmd_ == 0 && stateIsOn(s_fetchLocals)) {
+ if (!varTree_->schedule()) {
+ setStateOff(s_fetchLocals);
+ }
+ }
+}
+
+// **************************************************************************
+
+void RDBController::slotDbgProcessExited(KProcess*)
+{
+ destroyCmds();
+ state_ = s_appNotStarted|s_programExited|(state_&(s_shuttingDown));
+ emit dbgStatus (i18n("Process exited"), state_);
+ emit rdbStdout("(rdb:1) Process exited\n");
+ frameStack_->clear();
+ varTree_->clear();
+
+ if (socketNotifier_ != 0) {
+ delete socketNotifier_;
+ socketNotifier_ = 0;
+ close(socket_);
+ }
+
+ delete dbgProcess_; dbgProcess_ = 0;
+ delete tty_; tty_ = 0;
+}
+
+
+// **************************************************************************
+
+// Takes abbreviated commands and expands them, before passing them on to rdb
+//
+void RDBController::slotUserRDBCmd(const QString& cmd)
+{
+ kdDebug(9012) << "Requested user cmd: " << cmd << endl;
+ QRegExp break_re("^b(reak)?(\\s.*)?");
+ QRegExp watch_re("^wat(ch)?\\s+(.*)");
+ QRegExp delete_re("^del(ete)?(\\s.*)?");
+ QRegExp display_re("^disp(lay)?(\\s.*)?");
+ QRegExp undisplay_re("^undisp(lay)?(\\s.*)?");
+ QRegExp step_re("^s(tep)?(\\s[\\d]+)?$");
+ QRegExp next_re("^n(ext)?(\\s[\\d]+)?$");
+ QRegExp varlocal_re("^v(ar)?\\s+l(ocal)?");
+ QRegExp varglobal_re("^v(ar)?\\s+g(lobal)?");
+ QRegExp varinstance_re("^v(ar)?\\s+i(nstance)?\\s(.*)");
+ QRegExp varconst_re("^v(ar)?\\s+c(onst)?\\s(.*)");
+ QRegExp threadlist_re("^th(read)?\\s+l(ist)?");
+ QRegExp threadcurrent_re("^th(read)?(\\sc(ur(rent)?)?)?$");
+ QRegExp threadswitch_re("^th(read)?(\\ssw(itch)?)?(\\s.*)");
+ QRegExp thread_re("^th(read)?(\\s+.*)?");
+ QRegExp methodinstance_re("^m(ethod)?\\s+i(nstance)?\\s+(.*)");
+ QRegExp method_re("^m(ethod)?\\s+(.*)");
+ QRegExp list_re("^l(ist)?(\\s+\\d+-\\d+)?$");
+
+ if ( break_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("break%s", break_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( watch_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("watch %s", watch_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( delete_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("delete%s", delete_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( display_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("display%s", display_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( undisplay_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("undisplay%s", undisplay_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( step_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("step%s", step_re.cap(2).latin1()),
+ RUNCMD,
+ INFOCMD ), true );
+ } else if ( next_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("next%s", next_re.cap(2).latin1()),
+ RUNCMD,
+ INFOCMD ), true );
+ } else if ( varlocal_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand("var local", NOTRUNCMD, INFOCMD));
+ } else if ( varglobal_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand("var global", NOTRUNCMD, INFOCMD));
+ } else if ( varinstance_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("var instance %s", varinstance_re.cap(3).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( varconst_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("var const %s", varconst_re.cap(3).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( methodinstance_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("method instance %s", methodinstance_re.cap(3).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( method_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("method %s", method_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if ( list_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("list%s", list_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if (cmd == "c" || cmd == "cont") {
+ queueCmd(new RDBCommand("cont", RUNCMD, NOTINFOCMD));
+ } else if (cmd == "fi" || cmd == "finish") {
+ queueCmd(new RDBCommand("finish", RUNCMD, NOTINFOCMD));
+ } else if ( threadlist_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand("thread list", NOTRUNCMD, INFOCMD), true);
+ } else if ( threadcurrent_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand("thread current", NOTRUNCMD, INFOCMD), true );
+ } else if ( threadswitch_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("thread switch%s", threadswitch_re.cap(4).latin1()),
+ RUNCMD,
+ INFOCMD ), true );
+ } else if ( thread_re.search(cmd) >= 0 ) {
+ queueCmd(new RDBCommand( QCString().sprintf("thread%s", thread_re.cap(2).latin1()),
+ NOTRUNCMD,
+ INFOCMD ), true );
+ } else if (cmd == "frame" || cmd == "f" || cmd == "where" || cmd == "w") {
+ queueCmd(new RDBCommand("where", NOTRUNCMD, INFOCMD), true);
+ } else if (cmd == "q" || cmd == "quit") {
+ slotStopDebugger();
+ return;
+ } else {
+ kdDebug(9012) << "Passing directly to rdb: " << cmd << endl;
+ queueCmd(new RDBCommand(cmd.latin1(), NOTRUNCMD, INFOCMD));
+ }
+
+ executeCmd();
+}
+
+}
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+#include "rdbcontroller.moc"