KDevelop API Documentation

jdbcontroller.cpp

Go to the documentation of this file.
00001 // **************************************************************************
00002 //                          jdbcontroller.cpp  -  description
00003 //                             -------------------
00004 //    begin                : Mon Apr 16 2001
00005 //    copyright            : (C) 2001 by Oliver Strutynski
00006 //    email                : olistrut@gmx.net
00007 //    This code is heavily based on John Birch's original JDB Controller.
00008 // **************************************************************************
00009 // *                                                                        *
00010 // *   This program is free software; you can redistribute it and/or modify *
00011 // *   it under the terms of the GNU General Public License as published by *
00012 // *   the Free Software Foundation; either version 2 of the License, or    *
00013 // *   (at your option) any later version.                                  *
00014 // *                                                                        *
00015 // **************************************************************************
00016 
00017 
00018 #include "jdbcontroller.h"
00019 
00020 #include "javadebuggerpart.h"
00021 #include "breakpoint.h"
00022 #include "framestackwidget.h"
00023 #include "variablewidget.h"
00024 #include "jdbcommand.h"
00025 #include "stty.h"
00026 
00027 #include <kapplication.h>
00028 #include <kconfig.h>
00029 #include <kmessagebox.h>
00030 
00031 #include <kglobal.h>
00032 #include <klocale.h>
00033 
00034 #include <kprocess.h>
00035 #include <kdebug.h>
00036 
00037 #include <qregexp.h>
00038 #include <qstring.h>
00039 #include <qtimer.h>
00040 #include <qurl.h>
00041 
00042 #include <iostream>
00043 #include <ctype.h>
00044 #include <stdlib.h>
00045 
00046 using namespace std;
00047 
00048 #define BREAKPOINT_HIT 1
00049 #define MARK_FOUND 2
00050 #define JDB_MONITOR 1
00051 
00052 
00053 
00054 #if defined(DBG_MONITOR)
00055   #define JDB_MONITOR
00056   #define DBG_DISPLAY(X)          {kdDebug() << QString(X) << endl;}
00057 #else
00058   #define DBG_DISPLAY(X)          {kdDebug() << QString(X) << endl;}
00059 #endif
00060 
00061 #if defined(JDB_MONITOR)
00062   #define JDB_DISPLAY(X)          {kdDebug() << QString(X) << endl;}
00063 #else
00064   #define JDB_DISPLAY(X)          {kdDebug() << QString(X) << endl;}
00065 #endif
00066 
00067 
00068 namespace JAVADebugger
00069 {
00070 
00094 JDBController::JDBController(VariableTree *varTree, FramestackWidget *frameStack, QString projectDirectory, QString mainProgram)
00095     : DbgController(),
00096 
00097       classpath_(projectDirectory + "/src:" + (getenv("CLASSPATH") == 0 ? "." : getenv("CLASSPATH"))),
00098       mainclass_(mainProgram),
00099       projectDirectory_(projectDirectory + "/src"),
00100       frameStack_(frameStack),
00101       varTree_(varTree),
00102       currentFrame_(0),
00103       state_(s_dbgNotStarted|s_appNotStarted|s_silent),
00104       jdbSizeofBuf_(2048),
00105       jdbOutputLen_(0),
00106       jdbOutput_(new char[2048]),
00107       currentCmd_(0),
00108       tty_(0),
00109       programHasExited_(false),
00110       config_forceBPSet_(true),
00111       config_displayStaticMembers_(false),
00112       config_dbgTerminal_(false),
00113       config_jdbPath_()
00114 {
00115     KConfig *config = JavaDebuggerFactory::instance()->config();
00116     config->setGroup("Debug");
00117     Q_ASSERT(!config->readBoolEntry("Use external debugger", false));
00118 
00119     config_displayStaticMembers_  = config->readBoolEntry("Display static members", false);
00120     config_forceBPSet_            = config->readBoolEntry("Allow forced BP set", true);
00121     config_jdbPath_               = config->readPathEntry("JDB path");
00122     config_dbgTerminal_           = config->readBoolEntry("Debug on separate tty console", false);
00123 
00124 #if defined (JDB_MONITOR)
00125     kdDebug() << "Connect\n";
00126     connect(  this,   SIGNAL(dbgStatus(const QString&, int)),
00127               SLOT(slotDbgStatus(const QString&, int)));
00128 #endif
00129 
00130 #if defined (DBG_MONITOR)
00131     connect(  this,   SIGNAL(showStepInSource(const QString&, int, const QString&)),
00132               SLOT(slotStepInSource(const QString&,int)));
00133 #endif
00134 
00135     cmdList_.setAutoDelete(true);
00136 }
00137 
00138 // **************************************************************************
00139 
00140 // Deleting the controller involves shutting down jdb nicely.
00141 // When were attached to a process, we must first detach so that the process
00142 // can continue running as it was before being attached. jdb is quite slow to
00143 // detach from a process, so we must process events within here to get a "clean"
00144 // shutdown.
00145 JDBController::~JDBController()
00146 {
00147     setStateOn(s_shuttingDown);
00148     destroyCmds();
00149 
00150     if (dbgProcess_) {
00151         setStateOn(s_silent);
00152         pauseApp();
00153         setStateOn(s_waitTimer);
00154 
00155         QTimer *timer;
00156 
00157         timer = new QTimer(this);
00158         connect(timer, SIGNAL(timeout()), this, SLOT(slotAbortTimedEvent()) );
00159 
00160 
00161         setStateOn(s_waitTimer|s_appBusy);
00162         const char *quit="quit\n";
00163         dbgProcess_->writeStdin(quit, strlen(quit));
00164         JDB_DISPLAY(quit);
00165             timer->start(3000, TRUE);
00166         DBG_DISPLAY("<quit wait>\n");
00167             while (stateIsOn(s_waitTimer)) {
00168                 if (stateIsOn(s_programExited))
00169                     break;
00170                 kapp->processEvents(20);
00171             }
00172 
00173         // We cannot wait forever.
00174         if (stateIsOn(s_shuttingDown))
00175             dbgProcess_->kill(SIGKILL);
00176     }
00177 
00178     delete tty_; tty_ = 0;
00179     delete[] jdbOutput_;
00180 
00181     emit dbgStatus (i18n("Debugger stopped"), state_);
00182 }
00183 
00184 // **************************************************************************
00185 
00186 void JDBController::reConfig()
00187 {
00188     KConfig *config = JavaDebuggerFactory::instance()->config();
00189     config->setGroup("Debug");
00190     Q_ASSERT(!config->readBoolEntry("Use external debugger", false));
00191 
00192     bool old_displayStatic        = config_displayStaticMembers_;
00193     config_displayStaticMembers_  = config->readBoolEntry("Display static members", false);
00194 
00195 
00196     if (( old_displayStatic != config_displayStaticMembers_)&&
00197         dbgProcess_) {
00198         bool restart = false;
00199         if (stateIsOn(s_appBusy)) {
00200             setStateOn(s_silent);
00201             pauseApp();
00202             restart = true;
00203         }
00204 
00205 
00206         if (restart)
00207             queueCmd(new JDBCommand("cont", RUNCMD, NOTINFOCMD, 0));
00208     }
00209 }
00210 
00211 // **************************************************************************
00212 
00213 // Fairly obvious that we'll add whatever command you give me to a queue
00214 // If you tell me to, I'll put it at the head of the queue so it'll run ASAP
00215 // Not quite so obvious though is that if we are going to run again. then any
00216 // information requests become redundent and must be removed.
00217 // We also try and run whatever command happens to be at the head of
00218 // the queue.
00219 void JDBController::queueCmd(DbgCommand *cmd, bool executeNext)
00220 {
00221     // Output command info for debugging purposes
00222     // DBG_DISPLAY("Queue: " + cmd->command_);
00223 
00224     // We remove any info command or _run_ command if we are about to
00225     // add a run command.
00226     if (cmd->isARunCmd())
00227         removeInfoRequests();
00228 
00229     if (executeNext)
00230         cmdList_.insert(0, cmd);
00231     else
00232         cmdList_.append (cmd);
00233 
00234     executeCmd();
00235 }
00236 
00237 // **************************************************************************
00238 // If the appliction can accept a command and we've got one waiting
00239 // then send it.
00240 // Commands can be just request for data (or change jdbs state in someway)
00241 // or they can be "run" commands. If a command is sent to jdb our internal
00242 // state will get updated.
00243 void JDBController::executeCmd()
00244 {
00245 
00246     if (stateIsOn(s_dbgNotStarted|s_waitForWrite|s_appBusy)) {
00247         return;
00248    }
00249 
00250 
00251     if (!currentCmd_) {
00252         if (cmdList_.isEmpty()) {
00253             DBG_DISPLAY("Commandlist empty...\n");
00254             return;
00255         }
00256 
00257         currentCmd_ = cmdList_.take(0);
00258     } else {
00259 
00260       if (!currentCmd_->moreToSend()) {
00261           if (currentCmd_->expectReply()) {
00262               return;
00263           }
00264 
00265           delete currentCmd_;
00266           if (cmdList_.isEmpty()) {
00267               currentCmd_ = 0;
00268 
00269               return;
00270           }
00271 
00272           currentCmd_ = cmdList_.take(0);
00273       }
00274     }
00275 
00276     Q_ASSERT(currentCmd_ && currentCmd_->moreToSend());
00277 
00278     // Output command info for debugging purposes
00279     dbgProcess_->writeStdin(currentCmd_->cmdToSend().data(), currentCmd_->cmdLength());
00280     setStateOn(s_waitForWrite);
00281 
00282     if (currentCmd_->isARunCmd()) {
00283         setStateOn(s_appBusy);
00284         setStateOff(s_appNotStarted|s_programExited|s_silent);
00285     }
00286 
00287     JDB_DISPLAY("Written command: " + currentCmd_->cmdToSend());
00288     if (!stateIsOn(s_silent))
00289         emit dbgStatus ("", state_);
00290 }
00291 
00292 // **************************************************************************
00293 
00294 void JDBController::destroyCmds()
00295 {
00296     if (currentCmd_) {
00297         delete currentCmd_;
00298         currentCmd_ = 0;
00299     }
00300 
00301     while (!cmdList_.isEmpty())
00302         delete cmdList_.take(0);
00303 }
00304 
00305 // **********************************************************************
00306 
00307 void JDBController::removeInfoRequests()
00308 {
00309     int i = cmdList_.count();
00310     while (i) {
00311         i--;
00312         DbgCommand *cmd = cmdList_.at(i);
00313         if (cmd->isAnInfoCmd() || cmd->isARunCmd())
00314             delete cmdList_.take(i);
00315     }
00316 }
00317 
00318 // **********************************************************************
00319 
00320 // Pausing an app removes any pending run commands so that the app doesn't
00321 // start again. If we want to be silent then we remove any pending info
00322 // commands as well.
00323 void JDBController::pauseApp()
00324 {
00325 }
00326 
00327 // **********************************************************************
00328 
00329 // Whenever the program pauses we need to refresh the data visible to
00330 // the user. The reason we've stooped may be passed in to be emitted.
00331 void JDBController::actOnProgramPause(const QString &msg)
00332 {
00333     // We're only stopping if we were running, of course.
00334     if (stateIsOn(s_appBusy)) {
00335        DBG_DISPLAY("Acting on program paused: " + msg);
00336        setStateOff(s_appBusy);
00337        // We're always at frame zero when the program stops
00338        // and we must reset the active flag
00339        currentFrame_ = 0;
00340        varTree_->setActiveFlag(); //               ????????????????????????????????????
00341        // These two need to be actioned immediately. The order _is_ important
00342        emit dbgStatus("", state_);
00343 
00344        stackLineCount = 0;
00345 
00346        frameStack_->clearList();
00347 
00348        setStateOn(s_parsingOutput);
00349        queueCmd(new JDBCommand("where", NOTRUNCMD, NOTINFOCMD, BACKTRACE), TRUE);
00350 
00351        executeCmd();
00352 
00353        varLineCount = 0;
00354        // delete localData
00355        localData.clear();
00356        nameQueue.clear(); // should actually be empty already
00357 
00358 
00359        setStateOn(s_parsingOutput);
00360        parsedThis = FALSE;
00361        queueCmd(new JDBCommand("locals", NOTRUNCMD, INFOCMD, LOCALS), FALSE);
00362        executeCmd();
00363 
00364     } else { kdDebug() << "Not running\n";}
00365 }
00366 
00367 // **************************************************************************
00368 
00369 // There is no app anymore. This can be caused by program exiting
00370 // an invalid program specified or ...
00371 // jdb is still running though, but only the run command (may) make sense
00372 // all other commands are disabled.
00373 void JDBController::programNoApp(const QString &, bool)
00374 {
00375 }
00376 
00377 // **************************************************************************
00378 
00379 enum lineStarts
00380     {
00381 // Note that these values will differ according to the endianess of the architecture.
00382 // A bad idea surely?
00383 // On Intel:
00384 //      START_Brea  = 0x61657242,
00385 // On PowerPC:
00386         START_Brea  = 0x42726561,
00387 
00388         START_Step  = 0x70657453
00389     };
00390 
00391 
00392 // Any data that isn't "wrapped", arrives here. Rather than do multiple
00393 // string searches until we find (or don't find!) the data,
00394 // we break the data up, depending on the first 4 four bytes, treated as an
00395 // int. Hence those big numbers you see above.
00396 char* JDBController::parseLine(char *buf)
00397 {
00398 
00400 
00401 
00402     // Doing this copy should remove any alignment problems that
00403     // some systems have (eg Solaris).
00404     // - jbb?
00405 
00406     // I don't believe this will work on SPARC as the bytes are round the other way, it
00407     // certainly doesn't work on a PowerPC machine.
00408     //  - Richard Dale
00409 
00410 //    int sw;
00411 //    memcpy (&sw, buf, sizeof(int));
00412 
00413     if (memcmp(buf, "Brea", 4) == 0) {
00414             kdDebug() << "Checking for breakpoint\n";
00415             if ((strncmp(buf, "Breakpoint hit: thread", 22) == 0)) {
00416                 QRegExp ex( "Breakpoint hit: thread=\\\"(.*)\\\", (.*\\)), line=([0-9]*), bci\\=[0-9]*.*\\n[^\\[]*\\[[0-9]*\\] ");
00417                 if (ex.search( buf) != -1 ) {
00418                     DBG_DISPLAY(QString("Breakpoint hit in line ") + ex.cap(3));
00419                     if (stateIsOn(s_appStarting)) {
00420                         setStateOff(s_appStarting);
00421                     }
00422                     curMethod = ex.cap(2),
00423                     curLine = ex.cap(3);
00424 
00425 
00426                     if (currentCmd_ && currentCmd_->isARunCmd()) {
00427                         delete currentCmd_;
00428                         currentCmd_ = 0;
00429                         kdDebug() << "Deleting step command\n";
00430                     }
00431 
00432 
00433                     emit showStepInSource(QString(classpath_ + "/" + mainclass_ + ".java").latin1(),
00434                                           atoi(ex.cap(3).latin1()), "");
00435                     actOnProgramPause(QString("Reached Breakpoint in line ")+ex.cap(3));
00436 
00437                     char *retStr;
00438             QString retQString =  QString( buf + ex.cap(ex.numCaptures()) );
00439             memcpy( retStr, retQString.latin1(), retQString.length() );
00440                     return retStr;
00441                 }
00442 
00443             }
00444     } else if (memcmp(buf, "Step", 4) == 0) {
00445             if ((strncmp(buf, "Step completed:", 15) == 0)) {
00446                 kdDebug() << "STEP: " << buf << endl;
00447                 QRegExp ex( " thread=\\\"(.*)\\\", (.*\\)), line=([0-9]*)");
00448                 if (ex.search( buf) != -1 ) {
00449                     kdDebug() << "MATCH\n";
00450                     curMethod = ex.cap(2),
00451                     curLine = ex.cap(3);
00452 
00453 
00454                     if (currentCmd_ && currentCmd_->typeMatch(STEP)) {
00455                         delete currentCmd_;
00456                         currentCmd_ = 0;
00457                         DBG_DISPLAY("Deleting step command");
00458                     }
00459 
00460                     QString curClass = QString(ex.cap(2)).left(QString(ex.cap(2)).findRev("."));
00461                     QString curFile = getFile(curClass);
00462                     kdDebug() << "Filename: " << curFile <<endl;
00463                     emit showStepInSource(curFile, atoi(ex.cap(3).latin1() ), "");
00464 
00465                     actOnProgramPause(QString("step completed, stopped in ") + ex.cap(2));
00466 
00467                     return buf + QString(buf).length();
00468                 }
00469 
00470             }
00471 
00472     }
00473 
00474     return 0;
00475 }
00476 
00477 // **********************************************************************
00478 
00479 char* JDBController::parseInfo(char *buf)
00480 {
00481 
00482     // Every string we are looking for has to match at the
00483     // beginning of buf!
00484     if (currentCmd_ && currentCmd_->typeMatch(BACKTRACE)) {
00485         return parseBacktrace(buf);
00486     } else if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) {
00487         setStateOn(s_parsingLocals);
00488         return parseLocalVars(buf);
00489     } else if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) {
00490         setStateOn(s_parsingLocals);
00491         if (char* tmp = parseDump(buf)) { return tmp; }
00492     }
00493 
00494     return 0;
00495 }
00496 
00497 
00498 // **********************************************************************
00499 
00500 char* JDBController::parseBacktrace(char* buf) {
00501     QRegExp* exp = 0;
00502     // Check for a new line of stacktrace output first
00503     exp = new QRegExp( "^ \\[[0-9]+\\][^\\)]+\\)");
00504     if (exp->search( buf) != -1) {
00505         DBG_DISPLAY(QString("Found some stacktrace output"));
00506         frameStack_->addItem(exp->cap(0).latin1() );
00507         stackLineCount++;
00508        
00509     QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00510         memcpy( buf, retQString.latin1(), retQString.length() );
00511 
00512         delete exp;
00513         return buf;
00514     }
00515 
00516     // If that fails we check if the standard prompt is displayed
00517     if (stackLineCount > 0) {
00518     kdDebug() << ">" << *buf<<endl;
00519     exp->setPattern("^[^ ]+\\[[0-9]+\\]");
00520     if (exp->search( buf) != -1) {
00521         DBG_DISPLAY(QString("Found end of stacktrace (prompt)"));
00522 
00523         if (currentCmd_ && currentCmd_->typeMatch(BACKTRACE)) {
00524             delete currentCmd_;
00525             currentCmd_ = 0;
00526         }
00527 
00528         setStateOff(s_parsingOutput);
00529 
00530         frameStack_->updateDone();
00531 
00532         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00533         memcpy( buf, retQString.latin1(), retQString.length() );
00534 
00535         delete exp;
00536         return buf;
00537 
00538     }
00539     }
00540 
00541     // we know there will be a stack trace, so we just need to wait for
00542     // more data flowing in
00543     delete exp;
00544     return 0;
00545 }
00546 
00547 // **********************************************************************
00548 
00549 
00550 char* JDBController::parseLocalVars(char* buf) {
00551     QRegExp* exp = 0;
00552     exp = new QRegExp( "^Local variable information not available. Compile with -g to generate variable information\n");
00553     if (exp->search( buf) != -1) {
00554         DBG_DISPLAY(QString("No var info available"));
00555         if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) {
00556             delete currentCmd_;
00557             currentCmd_ = 0;
00558         }
00559         varUpdateDone();
00560 
00561         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00562         memcpy( buf, retQString.latin1(), retQString.length() );
00563 
00564         delete exp;
00565         return buf;
00566     }
00567 
00568     exp->setPattern( "^No local variables");
00569     if (exp->search( buf) != -1) {
00570         DBG_DISPLAY(QString("No locals"));
00571 
00572         // wait for prompt
00573         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00574         memcpy( buf, retQString.latin1(), retQString.length() );
00575 
00576         delete exp;
00577         return buf;
00578     }
00579 
00580     // Seems as if Java outputs some very strange spaces sometimes
00581     // or \s is partly broken in QRegExp
00582     exp->setPattern( "^  ([^ ]+) \\= ([^\\(\n]+)\\s*\\(id\\=[0-9]*\\)");
00583     if (exp->search( buf) != -1 ) {
00584         DBG_DISPLAY(QString("Var info:"));
00585         varLineCount++;
00586         kdDebug() << "Name: " << exp->cap(1) << endl;
00587         kdDebug() << "Type: " << exp->cap(2) << endl; // Remove possible trailing whitespace
00588 
00589         // Queue current var for processing.
00590         // kdDebug() << "APPENDING: " << exp->cap(1) << endl;
00591         nameQueue.append(exp->cap(1));
00592 
00593         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00594         memcpy( buf, retQString.latin1(), retQString.length() );
00595 
00596         delete exp;
00597         return buf;
00598 
00599     }
00600 
00601     exp->setPattern("^  ([^ ]+) \\= ([^\n]+)");
00602     if (exp->search( buf) != -1) {
00603         DBG_DISPLAY(QString("Local Var info:"));
00604 
00605         varLineCount++;
00606         kdDebug() << "Name: " << exp->cap(1) << endl;
00607         kdDebug() << "Type: " << exp->cap(2) << endl; // Remove possible trailing whitespace
00608 
00609         // primitive type, add directly
00610         analyzeDump(exp->cap(0));
00611 
00612         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00613         memcpy( buf, retQString.latin1(), retQString.length() );
00614 
00615         delete exp;
00616         return buf;
00617 
00618     }
00619 
00620 
00621     exp->setPattern("^([^ ]+)\\[[0-9]+\\] ");
00622     if (exp->search(buf) != -1 ) {
00623         DBG_DISPLAY(QString("Found end of var dump (prompt)"));
00624         kdDebug() << ">" << exp->cap(0) << "<\n";
00625         if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) {
00626             delete currentCmd_;
00627             currentCmd_ = 0;
00628         }
00629 
00630         if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) {
00631             delete currentCmd_;
00632             currentCmd_ = 0;
00633         }
00634         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00635         memcpy( buf, retQString.latin1(), retQString.length() );
00636 
00637         delete exp;
00638         return buf;
00639 
00640 
00641     }
00642     delete exp;
00643 
00644     return 0;
00645 }
00646 
00647 // **********************************************************************
00648 
00649 
00650 char* JDBController::parseDump(char* buf) {
00651     // Looking for dump output
00652     QRegExp *exp;
00653 
00654     // compound object
00655     exp = new QRegExp( "^([^ ]+) \\= ([^\\(]+)\\s*\\(id\\=[0-9]*\\) \\{([^\\}]+)\\}");
00656     if (exp->search( buf) != -1 ) {
00657         DBG_DISPLAY(QString("Found dump info"));
00658 
00659         analyzeDump(exp->cap(0));
00660 
00661         if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) {
00662             delete currentCmd_;
00663             currentCmd_ = 0;
00664         }
00665 
00666         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00667         memcpy( buf, retQString.latin1(), retQString.length() );
00668         delete exp;
00669         return buf;
00670     }
00671 
00672     // Array element
00673     exp->setPattern("^ ([^\\[]+\\[[0-9]+\\]) \\= ([^\n]+)");
00674     if (exp->search( buf) != -1 ) {
00675         DBG_DISPLAY(QString("Found dump info"));
00676         kdDebug() << "Array element: " << exp->cap(1) << " - " << exp->cap(2) << endl;
00677         analyzeDump(exp->cap(0));
00678 
00679         if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) {
00680             delete currentCmd_;
00681             currentCmd_ = 0;
00682         }
00683 
00684         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00685         memcpy( buf, retQString.latin1(), retQString.length() );
00686 
00687         delete exp;
00688         return buf;
00689     }
00690 
00691     exp->setPattern("^No 'this'.  In native or static method\n");
00692     if (exp->search( buf) != -1) {
00693 
00694         if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) {
00695             delete currentCmd_;
00696             currentCmd_ = 0;
00697         }
00698 
00699         QString retQString =  QString( buf + exp->cap(exp->numCaptures()) );
00700         memcpy( buf, retQString.latin1(), retQString.length() );
00701 
00702         delete exp;
00703         return buf;
00704     }
00705 
00706     delete exp;
00707     return 0;
00708 }
00709 
00710 
00711 
00712 
00713 // **************************************************************************
00714 
00715 /*
00716  * There aren't too many possibilities here:
00717  *  a) Object is of primitive type: data should match something like name: value(id=xxx)
00718  *  b) Object is an array element of primitive type: name[index] = value
00719  *  b) Object is of compound type: name: instance of package.classname(id=xxx) { properties }
00720  *     where properties can be variables of primitive type (a) or are in the form
00721  *     name: instance of type name or are arrays of either primitive or non primitive types
00722  *  c) Object is an array of primitive type objects: name: instance of type[dimension] (id=xxx)
00723  *  d) Object is an array of compound objects:
00724 */
00725 void JDBController::analyzeDump(QString data)
00726 {
00727 
00728   kdDebug() << "Parsing dump: " << data << endl;
00729 
00730   // case a
00731   // if we have a primitive type we add it to the list of locals directly
00732   QRegExp *exp = new QRegExp( "^  ([^ \\[]+) \\= ([^\n]+)"); // dup if it's really a var of primitive type
00733   if (exp->search(data.latin1()) != -1 ) {
00734       QString name = exp->cap(1);
00735       QString value = exp->cap(2);
00736       JDBVarItem *item = new JDBVarItem();
00737       item->value = value;
00738       item->name = name;
00739       if (!localData[name]) {
00740           kdDebug() << "inserting local var" << endl;
00741           localData.insert(name, item);
00742       } else { /* The object is already being referred to as a property */ }
00743       delete exp;
00744       return;
00745 
00746   }
00747 
00748   exp->setPattern( " ([^ \\[]+)\\[([0-9]+)\\] \\= ([^\n]+)");
00749   if (exp->search(data.latin1()) != -1) {
00750       kdDebug() << "Array element: " << exp->cap(1) << "[" << exp->cap(2)<< "] = " << exp->cap(3) << endl;
00751 
00752       QString name = exp->cap(1);
00753 
00754       JDBVarItem *item;
00755       JDBVarItem *subItem = new JDBVarItem();
00756       subItem->name = QString(exp->cap(1)) + "[" + QString(exp->cap(2)) + "]";
00757       subItem->value = exp->cap(3);
00758       item = localData[name];
00759       Q_ASSERT((name != 0));
00760 
00761       //kdDebug() << "->Appending to: " << name << endl;
00762       //kdDebug() << "Which is at: " << (int)item << endl;
00763 
00764       // item.insertSibling(subItem);
00765       item->siblings.append(subItem);
00766 
00767       delete exp;
00768       return;
00769   }
00770 
00771 
00772 
00773   exp->setPattern( "^([^ ]+) \\= instance of ([^[]+)\\[([0-9])+] \\(id\\=[0-9]+\\) {");
00774   if (exp->search(data.latin1()) != -1 ) {
00775       kdDebug() << "Array...\n";
00776       kdDebug() << "Name: " << exp->cap(1) << endl;
00777       kdDebug() << "Type: " << exp->cap(2) << endl;
00778       kdDebug() << "Dimension: " << exp->cap(3) << endl;
00779 
00780       kdDebug() << "Adding array to var tree... \n";
00781       JDBVarItem *item = new JDBVarItem();
00782       item->name = exp->cap(1);
00783       QString name = exp->cap(1);
00784       if (atoi(exp->cap(3).latin1()) == 0) {
00785           item->value="null";
00786       }
00787       if (!localData[name]) {
00788           kdDebug() << "inserting local var " << name << " at " << (int)item << endl;
00789           localData.insert(name, item);
00790       } else { /* The object is already being referred to as a property */ }
00791 
00792       for (int i=0; i<atoi(exp->cap(3).latin1()); i++) {
00793           kdDebug() <<  QString(exp->cap(1)) + QString("[") + QString::number((i)) + QString("]") << endl;
00794           nameQueue.append(QString(exp->cap(1)) + QString("[") + QString::number((i)) + QString("]"));
00795       }
00796 
00797       delete exp;
00798       return;
00799   }
00800 
00801   // case b
00802   // otherwise we need to extract all properties and add the name of the current var
00803   // and link it with its properties
00804   exp->setPattern( "^([^ ]+) \\= ([^\\(]+)\\s*\\(id\\=[0-9]*\\) \\{([^\\}]+)\\}");
00805   if (exp->search(data.latin1()) != -1) {
00806       kdDebug() << "COMPOUND DATA" << endl;
00807       // create a new jdbvaritem for the name of the object and for each property it
00808       // contains. the object's jdbvaritem has siblings then
00809       QString name = exp->cap(1);
00810       JDBVarItem *item;
00811       if (!localData[name]) {
00813           item = new JDBVarItem();
00814           kdDebug() << "NAME: " << name << " - " << (int)item << endl;
00815           item->name = name;
00816           localData.insert(name, item);
00817       } else {
00818           /* The object is already being referred to as a property */
00819           item = localData[name];
00820       }
00821 
00822 
00823 
00824       unsigned int i = data.find("{")+1;
00825       exp = new QRegExp("^([^ \\:]+): ([^\n]+)");
00826       QString tmp;
00827       while (i<data.length()) {
00828          // I guess this is really slow. Using a char* would be better here
00829          if (exp->search(data.mid(i).latin1()) != -1) {
00830              if (strncmp(exp->cap(2).latin1(), "instance of", 11) != 0) {
00831                  // property of primitive type
00832                  kdDebug() << "Primitive type..." << endl;
00833                  QString fullName = name + QString(".") + QString(exp->cap(1));
00834 
00835                  // create new item
00836                  JDBVarItem *subItem = new JDBVarItem();
00837                  subItem->value = exp->cap(2);
00838                  subItem->name = fullName;
00839                  if (!localData[fullName]) {
00840                      localData.insert(fullName, subItem);
00841                  } else { /* Oops */ }  
00842 
00843                  // item.insertSibling(subItem);
00844                  item->siblings.append(subItem);
00845 
00846                  //DBG_DISPLAY(QString("Appending Name: ") + name + QString(".") + exp->cap(1));
00847                  //DBG_DISPLAY(QString("Value: ") + exp->cap(2));
00848              } else if (QString(exp->cap(2)).contains("[")) {
00849                  // Array property
00850                  // not parsed yet. just insert some dummy data
00851 
00852                  QString fullName = name + QString(".") + QString(exp->cap(1));
00853 
00854                  JDBVarItem *subItem = new JDBVarItem();
00855                  subItem->name = fullName;
00856                  if (!localData[fullName]) {
00857                      localData.insert(fullName, subItem);
00858                  } else { /* Oops */ }  
00859 
00860                  //kdDebug() << "->Appending Name: " << name << "." << exp->cap(1) << endl;
00861                  //kdDebug() << "Value: " << exp->cap(2) << " as " << (int)subItem << endl;
00862 
00863                  // get array dimension andn queue elements for parsing
00864                  QRegExp *exp2 = new QRegExp("\\[([0-9]+)\\]");
00865                  if (exp2->search(exp->cap(2)) != -1 ) {
00866                      int dimension = atoi(exp2->cap(1).latin1());
00867                      kdDebug() << "Array dimension: " << dimension << endl;
00868                      for (int i=0; i<dimension; i++) {
00869                          nameQueue.append(fullName + "[" + QString::number((i)) + "]");
00870                      }
00871 
00872                      // item.insertSibling(subItem);
00873                      item->siblings.append(subItem);
00874                  }
00875 
00876              } else {
00877                  // property of non-primitive type, we will request additional
00878                  // information later
00879                  kdDebug() << "complex..." << endl;
00880                  QString fullName = name + QString(".") + QString(exp->cap(1));
00881                  nameQueue.append(fullName);
00882 
00883                  JDBVarItem *subItem = new JDBVarItem();
00884                  subItem->name = fullName;
00885                  if (!localData[fullName]) {
00886                      localData.insert(fullName, subItem);
00887                  } else { /* Oops */ }  
00888 
00889                  kdDebug() << "appending: " << fullName << " as " << (int)subItem << endl;
00890 
00891                  // item.insertSibling(subItem);
00892                  item->siblings.append(subItem);
00893 
00894 
00895              }
00896              i += atoi( exp->cap(exp->numCaptures()).latin1() );
00897          } else {
00898              i++;
00899          }
00900       }
00901 
00902   }
00903 
00904   delete exp; exp = 0;
00905 }
00906 
00907 
00908 // If there are elements left in the queue we remove the first one and issue
00909 // a dump command
00910 void JDBController::parseLocals()
00911 {
00912     if (!stateIsOn(s_parsingLocals)) { return; }
00913     if (currentCmd_) { return; }
00914     DBG_DISPLAY("Trying to continue with locals");
00915     if (!nameQueue.isEmpty()) {
00916         DBG_DISPLAY("Issueing newdump command");
00917         QString varName = nameQueue.first();
00918         nameQueue.remove(nameQueue.begin());
00919         // kdDebug() << nameQueue.count() << endl;
00920         queueCmd(new JDBCommand(QString("dump " + varName).latin1(), NOTRUNCMD, INFOCMD, DATAREQUEST), FALSE);
00921     } else if (!parsedThis) {
00922         parsedThis = TRUE;
00923         queueCmd(new JDBCommand(QCString("dump this"), NOTRUNCMD, INFOCMD, DATAREQUEST), FALSE);
00924 
00925     } else {
00926        parsedThis = FALSE;
00927        setStateOff(s_parsingLocals);
00928 
00929        varUpdateDone();
00930     }
00931 }
00932 
00933 // **************************************************************************
00934 
00935 // parsing the backtrace list will cause the vartree to be refreshed
00936 void JDBController::parseBacktraceList(char *)
00937 {
00938 }
00939 
00940 // **************************************************************************
00941 
00942 // If the user gives us a bad program, catch that here.
00943 //void JDBController::parseFileStart(char *buf)
00944 //{
00945 //  if (strstr(buf, "not in executable format:") ||
00946 //      strstr(buf, "No such file or directory."))
00947 //  {
00948 //    programNoApp(QString(buf), true);
00949 //    DBG_DISPLAY("Bad file start <" + QString(buf) + ">");
00950 //  }
00951 //}
00952 
00953 // **************************************************************************
00954 
00955 // Select a different frame to view. We need to get and (maybe) display
00956 // where we are in the program source.
00957 void JDBController::parseFrameSelected(char *)
00958 {
00959 }
00960 
00961 // **************************************************************************
00962 
00963 
00964 
00965 char *JDBController::parse(char *buf)
00966 {
00967 
00968     if (stateIsOn(s_dbgNotStarted)) {
00969         kdDebug() << "dbgnotstarted" << endl;
00970         // Check for first prompt
00971         kdDebug() << QString(buf).left(20) << endl;
00972         if (QString(buf).left(20) == "Initializing jdb...\n") { return buf+20; }
00973         if (QString(buf) == "> ") {
00974             setStateOff(s_dbgNotStarted);
00975             emit debuggerStarted();
00976             return buf + 2;
00977         }
00978         curLine = "";
00979         return buf++;
00980     }
00981 
00982 
00983     if (stateIsOn(s_appStarting)) {
00984         kdDebug() << "appstarting" << endl;
00985         char* unparsed = buf;
00986         char* orig = buf;
00987         while (*buf) {
00988             if ( (buf = parseLine(buf)) ) {
00989                 return buf;
00990             } else {
00991                 buf = ++unparsed;
00992             }
00993         }
00994         return orig;
00995     }
00996 
00997 
00998     // If the app is currently running eat all output
00999     // until we recognize something
01000     if (stateIsOn(s_appBusy)) {
01001         kdDebug() << "\nApp busy:" << endl;
01002         char* unparsed = buf;
01003         char* orig = buf;
01004         while (*buf) {
01005             if ( (buf = parseLine(unparsed)) ) {
01006                 return buf; // application is stopped now
01007                             // additional output will be ignored for
01008                             // now. we parse it later on
01009             } else {
01010                 buf = ++unparsed;
01011             }
01012         }
01013         return orig;
01014 
01015     } else {
01016         // assuming app is paused
01017         kdDebug() << "\nApp is paused:" << endl;
01018         char* unparsed = buf;
01019         char* orig = buf;
01020         while (*buf) {
01021             if ( (buf = parseInfo(buf)) ) {
01022                 unparsed = orig = buf;
01023             } else {
01024                 buf = ++unparsed;
01025             }
01026         }
01027         // Check if there are more vars to parse, otherwise update vartree widget
01028         parseLocals();
01029 
01030         return orig;
01031 
01032     }
01033 
01034     /*
01035     while (*unparsed) {
01036         char *parsed;
01037         if (*unparsed == (char)BLOCK_START)
01038             parsed = parseCmdBlock(unparsed);
01039         else
01040             parsed = parseOther(unparsed);
01041 
01042         if (!parsed)
01043             break;
01044 
01045         // Move one beyond the end of the parsed data
01046         unparsed = parsed+1;
01047     }
01048     */
01049 //    return (unparsed==buf) ? 0 : unparsed;
01050 }
01051 
01052 // **************************************************************************
01053 
01054 void JDBController::setBreakpoint(const QCString &/*BPSetCmd*/, int /*key*/)
01055 {
01056 //    queueCmd(new JDBSetBreakpointCommand("", key));
01057 }
01058 
01059 // **************************************************************************
01060 
01061 void JDBController::clearBreakpoint(const QCString &/*BPClearCmd*/)
01062 {
01063 //    queueCmd(new JDBCommand("info breakpoints", NOTRUNCMD, NOTINFOCMD, BPLIST));
01064 }
01065 
01066 // **************************************************************************
01067 
01068 void JDBController::modifyBreakpoint(Breakpoint *)
01069 {
01070 }
01071 
01072 // **************************************************************************
01073 //                                SLOTS
01074 //                                *****
01075 // For most of these slots data can only be sent to jdb when it
01076 // isn't busy and it is running.
01077 // **************************************************************************
01078 
01082 void JDBController::slotStart(const QString &/*application*/, const QString &args, const QString &sDbgShell)
01083 {
01084     Q_ASSERT (!dbgProcess_ && !tty_);
01085 
01086     // Remove .class suffix and leading path information from appname
01087     // (should not be there anyway)
01088 
01089     tty_ = new STTY(config_dbgTerminal_, "konsole");
01090     if (!config_dbgTerminal_) {
01091         connect( tty_, SIGNAL(OutOutput(const char*)), SIGNAL(ttyStdout(const char*)) );
01092         connect( tty_, SIGNAL(ErrOutput(const char*)), SIGNAL(ttyStderr(const char*)) );
01093     }
01094 
01095     QString tty(tty_->getSlave());
01096 
01097     if (tty.isEmpty()) {
01098         KMessageBox::error(0, i18n("JDB cannot use the tty* or pty* devices.\n"
01099                                    "Check the settings on /dev/tty* and /dev/pty*\n"
01100                                    "As root you may need to \"chmod ug+rw\" tty* and pty* devices "
01101                                    "and/or add the user to the tty group using "
01102                                    "\"usermod -G tty username\""));
01103 
01104         delete tty_;
01105         tty_ = 0;
01106         return;
01107     }
01108 
01109     JDB_DISPLAY("\nStarting JDB - app:["+mainclass_+"] classpath:["+classpath_+"] args:["+args+"] sDbgShell:["+sDbgShell+"]\n");
01110     dbgProcess_ = new KProcess;
01111 
01112     connect( dbgProcess_, SIGNAL(receivedStdout(KProcess *, char *, int)),
01113              this,        SLOT(slotDbgStdout(KProcess *, char *, int)) );
01114 
01115     connect( dbgProcess_, SIGNAL(receivedStderr(KProcess *, char *, int)),
01116              this,        SLOT(slotDbgStderr(KProcess *, char *, int)) );
01117 
01118     connect( dbgProcess_, SIGNAL(wroteStdin(KProcess *)),
01119              this,        SLOT(slotDbgWroteStdin(KProcess *)) );
01120 
01121     connect( dbgProcess_, SIGNAL(processExited(KProcess*)),
01122              this,        SLOT(slotDbgProcessExited(KProcess*)) );
01123 
01124 
01125     if (!sDbgShell.isEmpty())
01126         *dbgProcess_<<"/bin/sh"<<"-c"<<sDbgShell+" "+config_jdbPath_+
01127             QString("jdb")<<"-classpath"<<classpath_<<mainclass_<<args;
01128     else
01129         *dbgProcess_<<config_jdbPath_+QString("jdb")<<"-classpath"<<classpath_<<mainclass_<<args;
01130 
01131     if (! dbgProcess_->start(   KProcess::NotifyOnExit,
01132                                 KProcess::Communication(KProcess::All) ) )
01133     {
01134         JDB_DISPLAY("\nFailed to start JDB - app:["+mainclass_+"]\n");
01135     }
01136 
01137     // JDB takes some time to start up
01138     setStateOn(s_dbgNotStarted);
01139     emit dbgStatus ("", state_);
01140 
01141     // Initialise jdb. At this stage jdb is sitting wondering what to do,
01142     // and to whom. Organise a few things, then set up the tty for the application,
01143     // and the application itself
01144 
01145 }
01146 
01147 // **************************************************************************
01148 
01149 void JDBController::slotCoreFile(const QString&)
01150 {
01151 }
01152 
01153 
01154 void JDBController::slotAttachTo(int)
01155 {
01156 }
01157 
01158 // **************************************************************************
01159 
01160 void JDBController::slotDebuggerStarted() {
01161     kdDebug() << "slotRun()" << endl;
01162     if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown))
01163         return;
01164     bool first_flag = FALSE;
01165 
01166     kdDebug() << "slotRun()" << endl;
01167     if (stateIsOn(s_appNotStarted)) {
01168         first_flag = TRUE;
01169         queueCmd(new JDBCommand(QString("stop in " + mainclass_ + ".main(java.lang.String[])" ).latin1() , NOTRUNCMD, NOTINFOCMD, 0 ) );
01170     }
01171 
01172     queueCmd(new JDBCommand(stateIsOn(s_appNotStarted) ? "run" : "cont", RUNCMD, NOTINFOCMD, 0));
01173 
01174     // Signal we are waiting for the first breakpoint to be reached
01175     setStateOn(s_appStarting);
01176 }
01177 
01178 void JDBController::slotRun()
01179 {
01180     if (stateIsOn(s_dbgNotStarted)) {
01181         // Connect to debuggerStarted slot to wait for jdb to finish
01182         // initialization
01183         connect(this, SIGNAL(debuggerStarted()), SLOT(slotDebuggerStarted()));
01184     } else {
01185 //        emit debuggerStarted();
01186     }
01187 
01188 }
01189 
01190 // **************************************************************************
01191 
01192 void JDBController::slotRunUntil(const QString &, int)
01193 {
01194 }
01195 
01196 // **************************************************************************
01197 
01198 void JDBController::slotStepInto()
01199 {
01200     kdDebug() << "slotStepInstruction" << endl;
01201     if (stateIsOn(s_dbgNotStarted) || stateIsOn(s_appBusy) || stateIsOn(s_parsingOutput)) { return; }
01202     queueCmd(new JDBCommand("stepi", RUNCMD, NOTINFOCMD, 0));
01203 }
01204 
01205 // **************************************************************************
01206 
01207 void JDBController::slotStepIntoIns()
01208 {
01209 }
01210 
01211 // **************************************************************************
01212 
01213 void JDBController::slotStepOver() {
01214     kdDebug() << "slotStepOver" << endl;
01215     if (stateIsOn(s_appStarting) || stateIsOn(s_dbgNotStarted) || stateIsOn(s_appBusy) || stateIsOn(s_parsingOutput)) { return; }
01216     queueCmd(new JDBCommand("step", RUNCMD, NOTINFOCMD, 0));
01217 }
01218 
01219 // **************************************************************************
01220 
01221 void JDBController::slotStepOverIns()
01222 {
01223 }
01224 
01225 // **************************************************************************
01226 
01227 void JDBController::slotStepOutOff()
01228 {
01229 }
01230 
01231 // **************************************************************************
01232 
01233 // Only interrupt a running program.
01234 void JDBController::slotBreakInto()
01235 {
01236 }
01237 
01238 // **************************************************************************
01239 
01240 // See what, if anything needs doing to this breakpoint.
01241 void JDBController::slotBPState(Breakpoint *)
01242 {
01243 }
01244 
01245 // **************************************************************************
01246 
01247 void JDBController::slotClearAllBreakpoints()
01248 {
01249 }
01250 
01251 // **************************************************************************
01252 
01253 void JDBController::slotDisassemble(const QString &, const QString &)
01254 {
01255 }
01256 
01257 // **************************************************************************
01258 
01259 void JDBController::slotMemoryDump(const QString &, const QString &)
01260 {
01261 }
01262 
01263 // **************************************************************************
01264 
01265 void JDBController::slotRegisters()
01266 {
01267 }
01268 
01269 // **************************************************************************
01270 
01271 void JDBController::slotLibraries()
01272 {
01273 }
01274 
01275 // **************************************************************************
01276 
01277 void JDBController::slotSelectFrame(int)
01278 {
01279 }
01280 
01281 // **************************************************************************
01282 
01283 // This is called when the user desires to see the details of an item, by
01284 // clicking open an varItem on the varTree.
01285 void JDBController::slotExpandItem(VarItem *)
01286 {
01287 }
01288 
01289 // **************************************************************************
01290 
01291 // This is called when an item needs special processing to show a value.
01292 // Example = QStrings. We want to display the QString string against the var name
01293 // so the user doesn't have to open the qstring to find it. Here's where that happens
01294 void JDBController::slotExpandUserItem(VarItem *, const QCString& )
01295 {
01296 }
01297 
01298 // **************************************************************************
01299 
01300 // The user will only get locals if one of the branches to the local tree
01301 // is open. This speeds up stepping through code a great deal.
01303 void JDBController::slotSetLocalViewState(bool)
01304 {
01305 }
01306 
01307 // **************************************************************************
01308 
01309 // Data from jdb gets processed here.
01310 void JDBController::slotDbgStdout(KProcess *, char *buf, int buflen)
01311 {
01312     // Allocate some buffer space, if adding to this buffer will exceed it
01313     if (jdbOutputLen_+buflen+1 > jdbSizeofBuf_) {
01314         jdbSizeofBuf_ = jdbOutputLen_+buflen+1;
01315         char *newBuf = new char[jdbSizeofBuf_];     // ??? shoudn't this be malloc ???
01316         if (jdbOutputLen_)
01317             memcpy(newBuf, jdbOutput_, jdbOutputLen_+1);
01318         delete[] jdbOutput_;                        // ??? and free ???
01319         jdbOutput_ = newBuf;
01320     }
01321 
01322     // Copy the data out of the KProcess buffer before it gets overwritten
01323     // and fake a string so we can use the string fns on this buffer
01324     memcpy(jdbOutput_+jdbOutputLen_, buf, buflen);
01325     jdbOutputLen_ += buflen;
01326     *(jdbOutput_+jdbOutputLen_) = 0;
01327 
01328     if (char *nowAt = parse(jdbOutput_)) {
01329         Q_ASSERT(nowAt <= jdbOutput_+jdbOutputLen_+1);
01330         jdbOutputLen_ = strlen(nowAt);
01331         // Some bytes that weren't parsed need to be moved to the head of the buffer
01332         if (jdbOutputLen_)
01333             memmove(jdbOutput_, nowAt, jdbOutputLen_);     // Overlapping data
01334 
01335     }
01336     // check the queue for any commands to send
01337     executeCmd();
01338     kdDebug() << "stdout" << endl;
01339 }
01340 
01341 // **************************************************************************
01342 
01343 void JDBController::slotDbgStderr(KProcess */*proc*/, char *buf, int/* buflen*/)
01344 {
01345     // At the moment, just drop a message out
01346     // dont and redirect
01347     kdDebug() << "STDERR\n";
01348     DBG_DISPLAY(QString("\nSTDERR: ")+QString(buf));
01349 //    slotDbgStdout(proc, buf, buflen);
01350 }
01351 
01352 // **************************************************************************
01353 
01354 void JDBController::slotDbgWroteStdin(KProcess *)
01355 {
01356     setStateOff(s_waitForWrite);
01357     executeCmd();
01358     kdDebug() << "dbgwrotestdin" << endl;
01359 }
01360 
01361 // **************************************************************************
01362 
01363 void JDBController::slotDbgProcessExited(KProcess*)
01364 {
01365     destroyCmds();
01366     state_ = s_appNotStarted|s_programExited|(state_&s_viewLocals);
01367     emit dbgStatus (i18n("Process exited"), state_);
01368 
01369     JDB_DISPLAY(QString("\n(jdb) Process exited"));
01370 }
01371 
01372 // **************************************************************************
01373 
01374 
01381 QString JDBController::getFile(QString className)
01382 {
01383     return QString(projectDirectory_ + "/" + className + ".java");
01384 }
01385 
01386 // **********************************************************************
01387 
01388 void JDBController::varUpdateDone()
01389 {
01390     kdDebug() << "VarUpdateDone" << endl;
01391 
01392     QString locals = "";
01393     QDictIterator<JDBVarItem> it(localData); // iterator for dict
01394     if (!it.toFirst()) { return; }
01395     // make sure we dont visit nodes more than once
01396     while (it.current()) {
01397 
01398        if (!it.currentKey().contains(".")) {
01399            locals += it.current()->toString() + QString(",");
01400        }
01401        ++it;
01402     }
01403 
01404     locals[locals.length()-1] = ' '; // remove trailing comma
01405     char* _l = new char[locals.length()];
01406     strcpy(_l, locals.latin1());
01407     kdDebug() << "\nLocals: "<< _l << endl;
01408 
01409 
01410     varTree_->trim();
01411 
01412     FrameRoot *frame;
01413     // The locals are always attached to the currentFrame
01414     // so make sure we have one of those.
01415     if (!(frame = varTree_->findFrame(currentFrame_)))
01416         frame = new FrameRoot(varTree_, currentFrame_);
01417 
01418     Q_ASSERT(frame);
01419     frame->setFrameName(frameStack_->getFrameName(currentFrame_));
01420 
01421     frame->setLocals(_l);
01422 
01423     varTree_->viewport()->setUpdatesEnabled(true);
01424     varTree_->repaint();
01425     localData.clear();
01426     setStateOff(s_parsingOutput);
01427 
01428 }
01429 
01430 
01431 // The time limit has expired so set the state off.
01432 void JDBController::slotAbortTimedEvent()
01433 {
01434     setStateOff(s_waitTimer);
01435     DBG_DISPLAY(QString("Timer aborted\n"));
01436 }
01437 
01438 // **************************************************************************
01439 
01440 void JDBController::slotStepInSource(const QString &fileName, int lineNum)
01441 {
01442     DBG_DISPLAY((QString("(Show step in source) ")+fileName+QString(":")
01443                  +QString().setNum(lineNum)).local8Bit().data());
01444 }
01445 
01446 // **************************************************************************
01447 
01448 void JDBController::slotDbgStatus(const QString &status, int state)
01449 {
01450     QString s("(status) ");
01451     if (!state)
01452         s += QString("<program paused>");
01453     if (state & s_dbgNotStarted)
01454         s += QString("<dbg not started>");
01455     if (state & s_appNotStarted)
01456         s += QString("<app not started>");
01457     if (state & s_appBusy)
01458         s += QString("<app busy>");
01459     if (state & s_waitForWrite)
01460         s += QString("<wait for write>");
01461     if (state & s_programExited)
01462         s += QString("<program exited>");
01463     if (state & s_silent)
01464         s += QString("<silent>");
01465     if (state & s_viewLocals)
01466         s += QString("<viewing locals>");
01467 
01468     DBG_DISPLAY((s+status).local8Bit().data());
01469 }
01470 
01471 
01472 JDBVarItem::JDBVarItem() {
01473     value = "";
01474     name = "";
01475 }
01476 
01477 QString JDBVarItem::toString() {
01478     if (!value.isEmpty()) {
01479         kdDebug() << value <<" - ";
01480         return name + " = " + value;
01481     } else {
01482         // iterate over siblings and build return string
01483         QString tmp;
01484         JDBVarItem *item;
01485 
01486         for (item = this->siblings.first(); item != 0; item = this->siblings.next()) {
01487             tmp += item->toString() + ",";
01488             delete item;
01489         }
01490 
01491         tmp = name + " = {" +tmp;
01492         tmp[tmp.length()-1] = '}'; // remove trailing comma
01493         return tmp;
01494     }
01495 }
01496 
01497 }
01498 
01499 // **************************************************************************
01500 #include "jdbcontroller.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:30 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003