KDevelop API Documentation

languages/java/debugger/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 <kregexp.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 KRegExp ex( "Breakpoint hit: thread=\\\"(.*)\\\", (.*\\)), line=([0-9]*), bci\\=[0-9]*.*\\n[^\\[]*\\[[0-9]*\\] "); 00417 if (ex.match( buf)) { 00418 DBG_DISPLAY(QString("Breakpoint hit in line ") + ex.group(3)); 00419 if (stateIsOn(s_appStarting)) { 00420 setStateOff(s_appStarting); 00421 } 00422 curMethod = ex.group(2), 00423 curLine = ex.group(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.group(3)), ""); 00435 actOnProgramPause(QString("Reached Breakpoint in line ")+ex.group(3)); 00436 00437 return buf + ex.groupEnd(0); 00438 } 00439 00440 } 00441 } else if (memcmp(buf, "Step", 4) == 0) { 00442 if ((strncmp(buf, "Step completed:", 15) == 0)) { 00443 kdDebug() << "STEP: " << buf << endl; 00444 KRegExp ex( " thread=\\\"(.*)\\\", (.*\\)), line=([0-9]*)"); 00445 if (ex.match( buf)) { 00446 kdDebug() << "MATCH\n"; 00447 curMethod = ex.group(2), 00448 curLine = ex.group(3); 00449 00450 00451 if (currentCmd_ && currentCmd_->typeMatch(STEP)) { 00452 delete currentCmd_; 00453 currentCmd_ = 0; 00454 DBG_DISPLAY("Deleting step command"); 00455 } 00456 00457 QString curClass = QString(ex.group(2)).left(QString(ex.group(2)).findRev(".")); 00458 QString curFile = getFile(curClass); 00459 kdDebug() << "Filename: " << curFile <<endl; 00460 emit showStepInSource(curFile, atoi(ex.group(3)), ""); 00461 00462 actOnProgramPause(QString("step completed, stopped in ") + ex.group(2)); 00463 00464 return buf + QString(buf).length(); 00465 } 00466 00467 } 00468 00469 } 00470 00471 return 0; 00472 } 00473 00474 // ********************************************************************** 00475 00476 char* JDBController::parseInfo(char *buf) 00477 { 00478 00479 // Every string we are looking for has to match at the 00480 // beginning of buf! 00481 if (currentCmd_ && currentCmd_->typeMatch(BACKTRACE)) { 00482 return parseBacktrace(buf); 00483 } else if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) { 00484 setStateOn(s_parsingLocals); 00485 return parseLocalVars(buf); 00486 } else if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) { 00487 setStateOn(s_parsingLocals); 00488 if (char* tmp = parseDump(buf)) { return tmp; } 00489 } 00490 00491 return 0; 00492 } 00493 00494 00495 // ********************************************************************** 00496 00497 char* JDBController::parseBacktrace(char* buf) { 00498 KRegExp* exp = 0; 00499 // Check for a new line of stacktrace output first 00500 exp = new KRegExp( "^ \\[[0-9]+\\][^\\)]+\\)"); 00501 if (exp->match( buf)) { 00502 DBG_DISPLAY(QString("Found some stacktrace output")); 00503 frameStack_->addItem(exp->group(0)); 00504 stackLineCount++; 00505 buf += exp->groupEnd(0); 00506 delete exp; 00507 return buf; 00508 } 00509 00510 // If that fails we check if the standard prompt is displayed 00511 if (stackLineCount > 0) { 00512 kdDebug() << ">" << *buf<<endl; 00513 exp->compile("^[^ ]+\\[[0-9]+\\]"); 00514 if (exp->match( buf)) { 00515 DBG_DISPLAY(QString("Found end of stacktrace (prompt)")); 00516 00517 if (currentCmd_ && currentCmd_->typeMatch(BACKTRACE)) { 00518 delete currentCmd_; 00519 currentCmd_ = 0; 00520 } 00521 00522 setStateOff(s_parsingOutput); 00523 00524 frameStack_->updateDone(); 00525 buf += exp->groupEnd(0); 00526 delete exp; 00527 return buf; 00528 00529 } 00530 } 00531 00532 // we know there will be a stack trace, so we just need to wait for 00533 // more data flowing in 00534 delete exp; 00535 return 0; 00536 } 00537 00538 // ********************************************************************** 00539 00540 00541 char* JDBController::parseLocalVars(char* buf) { 00542 KRegExp* exp = 0; 00543 exp = new KRegExp( "^Local variable information not available. Compile with -g to generate variable information\n"); 00544 if (exp->match( buf)) { 00545 DBG_DISPLAY(QString("No var info available")); 00546 if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) { 00547 delete currentCmd_; 00548 currentCmd_ = 0; 00549 } 00550 varUpdateDone(); 00551 buf += exp->groupEnd(0); 00552 delete exp; 00553 return buf; 00554 } 00555 00556 exp->compile( "^No local variables"); 00557 if (exp->match( buf)) { 00558 DBG_DISPLAY(QString("No locals")); 00559 00560 // wait for prompt 00561 buf += exp->groupEnd(0); 00562 delete exp; 00563 return buf; 00564 } 00565 00566 // Seems as if Java outputs some very strange spaces sometimes 00567 // or \s is partly broken in KRegExp 00568 exp->compile( "^ ([^ ]+) \\= ([^\\(\n]+)\\s*\\(id\\=[0-9]*\\)"); 00569 if (exp->match( buf)) { 00570 DBG_DISPLAY(QString("Var info:")); 00571 varLineCount++; 00572 kdDebug() << "Name: " << exp->group(1) << endl; 00573 kdDebug() << "Type: " << exp->group(2) << endl; // Remove possible trailing whitespace 00574 00575 // Queue current var for processing. 00576 // kdDebug() << "APPENDING: " << exp->group(1) << endl; 00577 nameQueue.append(exp->group(1)); 00578 00579 buf += exp->groupEnd(0); 00580 delete exp; 00581 return buf; 00582 00583 } 00584 00585 exp->compile("^ ([^ ]+) \\= ([^\n]+)"); 00586 if (exp->match( buf)) { 00587 DBG_DISPLAY(QString("Local Var info:")); 00588 00589 varLineCount++; 00590 kdDebug() << "Name: " << exp->group(1) << endl; 00591 kdDebug() << "Type: " << exp->group(2) << endl; // Remove possible trailing whitespace 00592 00593 // primitive type, add directly 00594 analyzeDump(exp->group(0)); 00595 00596 buf += exp->groupEnd(0); 00597 delete exp; 00598 return buf; 00599 00600 } 00601 00602 00603 exp->compile("^([^ ]+)\\[[0-9]+\\] "); 00604 if (exp->match(buf)) { 00605 DBG_DISPLAY(QString("Found end of var dump (prompt)")); 00606 kdDebug() << ">" << exp->group(0) << "<\n"; 00607 if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) { 00608 delete currentCmd_; 00609 currentCmd_ = 0; 00610 } 00611 00612 if (currentCmd_ && currentCmd_->typeMatch(LOCALS)) { 00613 delete currentCmd_; 00614 currentCmd_ = 0; 00615 } 00616 00617 buf += exp->groupEnd(0); 00618 delete exp; 00619 return buf; 00620 00621 00622 } 00623 delete exp; 00624 00625 return 0; 00626 } 00627 00628 // ********************************************************************** 00629 00630 00631 char* JDBController::parseDump(char* buf) { 00632 // Looking for dump output 00633 KRegExp *exp; 00634 00635 // compound object 00636 exp = new KRegExp( "^([^ ]+) \\= ([^\\(]+)\\s*\\(id\\=[0-9]*\\) \\{([^\\}]+)\\}"); 00637 if (exp->match( buf)) { 00638 DBG_DISPLAY(QString("Found dump info")); 00639 00640 analyzeDump(exp->group(0)); 00641 00642 if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) { 00643 delete currentCmd_; 00644 currentCmd_ = 0; 00645 } 00646 00647 buf += exp->groupEnd(0); 00648 delete exp; 00649 return buf; 00650 } 00651 00652 // Array element 00653 exp->compile("^ ([^\\[]+\\[[0-9]+\\]) \\= ([^\n]+)"); 00654 if (exp->match( buf)) { 00655 DBG_DISPLAY(QString("Found dump info")); 00656 kdDebug() << "Array element: " << exp->group(1) << " - " << exp->group(2) << endl; 00657 analyzeDump(exp->group(0)); 00658 00659 if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) { 00660 delete currentCmd_; 00661 currentCmd_ = 0; 00662 } 00663 00664 00665 buf += exp->groupEnd(0); 00666 delete exp; 00667 return buf; 00668 } 00669 00670 exp->compile("^No 'this'. In native or static method\n"); 00671 if (exp->match( buf)) { 00672 00673 if (currentCmd_ && currentCmd_->typeMatch(DATAREQUEST)) { 00674 delete currentCmd_; 00675 currentCmd_ = 0; 00676 } 00677 00678 buf += exp->groupEnd(0); 00679 delete exp; 00680 return buf; 00681 } 00682 00683 delete exp; 00684 return 0; 00685 } 00686 00687 00688 00689 00690 // ************************************************************************** 00691 00692 /* 00693 * There aren't too many possibilities here: 00694 * a) Object is of primitive type: data should match something like name: value(id=xxx) 00695 * b) Object is an array element of primitive type: name[index] = value 00696 * b) Object is of compound type: name: instance of package.classname(id=xxx) { properties } 00697 * where properties can be variables of primitive type (a) or are in the form 00698 * name: instance of type name or are arrays of either primitive or non primitive types 00699 * c) Object is an array of primitive type objects: name: instance of type[dimension] (id=xxx) 00700 * d) Object is an array of compound objects: 00701 */ 00702 void JDBController::analyzeDump(QString data) 00703 { 00704 00705 kdDebug() << "Parsing dump: " << data << endl; 00706 00707 // case a 00708 // if we have a primitive type we add it to the list of locals directly 00709 KRegExp *exp = new KRegExp( "^ ([^ \\[]+) \\= ([^\n]+)"); // dup if it's really a var of primitive type 00710 if (exp->match(data.latin1())) { 00711 QString name = exp->group(1); 00712 QString value = exp->group(2); 00713 JDBVarItem *item = new JDBVarItem(); 00714 item->value = value; 00715 item->name = name; 00716 if (!localData[name]) { 00717 kdDebug() << "inserting local var" << endl; 00718 localData.insert(name, item); 00719 } else { /* The object is already being referred to as a property */ } 00720 delete exp; 00721 return; 00722 00723 } 00724 00725 exp->compile( " ([^ \\[]+)\\[([0-9]+)\\] \\= ([^\n]+)"); 00726 if (exp->match(data.latin1())) { 00727 kdDebug() << "Array element: " << exp->group(1) << "[" << exp->group(2)<< "] = " << exp->group(3) << endl; 00728 00729 QString name = exp->group(1); 00730 00731 JDBVarItem *item; 00732 JDBVarItem *subItem = new JDBVarItem(); 00733 subItem->name = QString(exp->group(1)) + "[" + QString(exp->group(2)) + "]"; 00734 subItem->value = exp->group(3); 00735 item = localData[name]; 00736 Q_ASSERT((name != 0)); 00737 00738 //kdDebug() << "->Appending to: " << name << endl; 00739 //kdDebug() << "Which is at: " << (int)item << endl; 00740 00741 // item.insertSibling(subItem); 00742 item->siblings.append(subItem); 00743 00744 delete exp; 00745 return; 00746 } 00747 00748 00749 00750 exp->compile( "^([^ ]+) \\= instance of ([^[]+)\\[([0-9])+] \\(id\\=[0-9]+\\) {"); 00751 if (exp->match(data.latin1())) { 00752 kdDebug() << "Array...\n"; 00753 kdDebug() << "Name: " << exp->group(1) << endl; 00754 kdDebug() << "Type: " << exp->group(2) << endl; 00755 kdDebug() << "Dimension: " << exp->group(3) << endl; 00756 00757 kdDebug() << "Adding array to var tree... \n"; 00758 JDBVarItem *item = new JDBVarItem(); 00759 item->name = exp->group(1); 00760 QString name = exp->group(1); 00761 if (atoi(exp->group(3)) == 0) { 00762 item->value="null"; 00763 } 00764 if (!localData[name]) { 00765 kdDebug() << "inserting local var " << name << " at " << (int)item << endl; 00766 localData.insert(name, item); 00767 } else { /* The object is already being referred to as a property */ } 00768 00769 for (int i=0; i<atoi(exp->group(3)); i++) { 00770 kdDebug() << QString(exp->group(1)) + QString("[") + QString::number((i)) + QString("]") << endl; 00771 nameQueue.append(QString(exp->group(1)) + QString("[") + QString::number((i)) + QString("]")); 00772 } 00773 00774 delete exp; 00775 return; 00776 } 00777 00778 // case b 00779 // otherwise we need to extract all properties and add the name of the current var 00780 // and link it with its properties 00781 exp->compile( "^([^ ]+) \\= ([^\\(]+)\\s*\\(id\\=[0-9]*\\) \\{([^\\}]+)\\}"); 00782 if (exp->match(data.latin1())) { 00783 kdDebug() << "COMPOUND DATA" << endl; 00784 // create a new jdbvaritem for the name of the object and for each property it 00785 // contains. the object's jdbvaritem has siblings then 00786 QString name = exp->group(1); 00787 JDBVarItem *item; 00788 if (!localData[name]) { 00790 item = new JDBVarItem(); 00791 kdDebug() << "NAME: " << name << " - " << (int)item << endl; 00792 item->name = name; 00793 localData.insert(name, item); 00794 } else { 00795 /* The object is already being referred to as a property */ 00796 item = localData[name]; 00797 } 00798 00799 00800 00801 unsigned int i = data.find("{")+1; 00802 exp = new KRegExp("^([^ \\:]+): ([^\n]+)"); 00803 QString tmp; 00804 while (i<data.length()) { 00805 // I guess this is really slow. Using a char* would be better here 00806 if (exp->match(data.mid(i).latin1())) { 00807 if (strncmp(exp->group(2), "instance of", 11) != 0) { 00808 // property of primitive type 00809 kdDebug() << "Primitive type..." << endl; 00810 QString fullName = name + QString(".") + QString(exp->group(1)); 00811 00812 // create new item 00813 JDBVarItem *subItem = new JDBVarItem(); 00814 subItem->value = exp->group(2); 00815 subItem->name = fullName; 00816 if (!localData[fullName]) { 00817 localData.insert(fullName, subItem); 00818 } else { /* Oops */ } 00819 00820 // item.insertSibling(subItem); 00821 item->siblings.append(subItem); 00822 00823 //DBG_DISPLAY(QString("Appending Name: ") + name + QString(".") + exp->group(1)); 00824 //DBG_DISPLAY(QString("Value: ") + exp->group(2)); 00825 } else if (QString(exp->group(2)).contains("[")) { 00826 // Array property 00827 // not parsed yet. just insert some dummy data 00828 00829 QString fullName = name + QString(".") + QString(exp->group(1)); 00830 00831 JDBVarItem *subItem = new JDBVarItem(); 00832 subItem->name = fullName; 00833 if (!localData[fullName]) { 00834 localData.insert(fullName, subItem); 00835 } else { /* Oops */ } 00836 00837 //kdDebug() << "->Appending Name: " << name << "." << exp->group(1) << endl; 00838 //kdDebug() << "Value: " << exp->group(2) << " as " << (int)subItem << endl; 00839 00840 // get array dimension andn queue elements for parsing 00841 KRegExp *exp2 = new KRegExp("\\[([0-9]+)\\]"); 00842 if (exp2->match(exp->group(2))) { 00843 int dimension = atoi(exp2->group(1)); 00844 kdDebug() << "Array dimension: " << dimension << endl; 00845 for (int i=0; i<dimension; i++) { 00846 nameQueue.append(fullName + "[" + QString::number((i)) + "]"); 00847 } 00848 00849 // item.insertSibling(subItem); 00850 item->siblings.append(subItem); 00851 } 00852 00853 } else { 00854 // property of non-primitive type, we will request additional 00855 // information later 00856 kdDebug() << "complex..." << endl; 00857 QString fullName = name + QString(".") + QString(exp->group(1)); 00858 nameQueue.append(fullName); 00859 00860 JDBVarItem *subItem = new JDBVarItem(); 00861 subItem->name = fullName; 00862 if (!localData[fullName]) { 00863 localData.insert(fullName, subItem); 00864 } else { /* Oops */ } 00865 00866 kdDebug() << "appending: " << fullName << " as " << (int)subItem << endl; 00867 00868 // item.insertSibling(subItem); 00869 item->siblings.append(subItem); 00870 00871 00872 } 00873 i += exp->groupEnd(0); 00874 } else { 00875 i++; 00876 } 00877 } 00878 00879 } 00880 00881 delete exp; exp = 0; 00882 } 00883 00884 00885 // If there are elements left in the queue we remove the first one and issue 00886 // a dump command 00887 void JDBController::parseLocals() 00888 { 00889 if (!stateIsOn(s_parsingLocals)) { return; } 00890 if (currentCmd_) { return; } 00891 DBG_DISPLAY("Trying to continue with locals"); 00892 if (!nameQueue.isEmpty()) { 00893 DBG_DISPLAY("Issueing newdump command"); 00894 QString varName = nameQueue.first(); 00895 nameQueue.remove(nameQueue.begin()); 00896 // kdDebug() << nameQueue.count() << endl; 00897 queueCmd(new JDBCommand(QString("dump " + varName).latin1(), NOTRUNCMD, INFOCMD, DATAREQUEST), FALSE); 00898 } else if (!parsedThis) { 00899 parsedThis = TRUE; 00900 queueCmd(new JDBCommand(QCString("dump this"), NOTRUNCMD, INFOCMD, DATAREQUEST), FALSE); 00901 00902 } else { 00903 parsedThis = FALSE; 00904 setStateOff(s_parsingLocals); 00905 00906 varUpdateDone(); 00907 } 00908 } 00909 00910 // ************************************************************************** 00911 00912 // parsing the backtrace list will cause the vartree to be refreshed 00913 void JDBController::parseBacktraceList(char *) 00914 { 00915 } 00916 00917 // ************************************************************************** 00918 00919 // If the user gives us a bad program, catch that here. 00920 //void JDBController::parseFileStart(char *buf) 00921 //{ 00922 // if (strstr(buf, "not in executable format:") || 00923 // strstr(buf, "No such file or directory.")) 00924 // { 00925 // programNoApp(QString(buf), true); 00926 // DBG_DISPLAY("Bad file start <" + QString(buf) + ">"); 00927 // } 00928 //} 00929 00930 // ************************************************************************** 00931 00932 // Select a different frame to view. We need to get and (maybe) display 00933 // where we are in the program source. 00934 void JDBController::parseFrameSelected(char *) 00935 { 00936 } 00937 00938 // ************************************************************************** 00939 00940 00941 00942 char *JDBController::parse(char *buf) 00943 { 00944 00945 if (stateIsOn(s_dbgNotStarted)) { 00946 kdDebug() << "dbgnotstarted" << endl; 00947 // Check for first prompt 00948 kdDebug() << QString(buf).left(20) << endl; 00949 if (QString(buf).left(20) == "Initializing jdb...\n") { return buf+20; } 00950 if (QString(buf) == "> ") { 00951 setStateOff(s_dbgNotStarted); 00952 emit debuggerStarted(); 00953 return buf + 2; 00954 } 00955 curLine = ""; 00956 return buf++; 00957 } 00958 00959 00960 if (stateIsOn(s_appStarting)) { 00961 kdDebug() << "appstarting" << endl; 00962 char* unparsed = buf; 00963 char* orig = buf; 00964 while (*buf) { 00965 if ( (buf = parseLine(buf)) ) { 00966 return buf; 00967 } else { 00968 buf = ++unparsed; 00969 } 00970 } 00971 return orig; 00972 } 00973 00974 00975 // If the app is currently running eat all output 00976 // until we recognize something 00977 if (stateIsOn(s_appBusy)) { 00978 kdDebug() << "\nApp busy:" << endl; 00979 char* unparsed = buf; 00980 char* orig = buf; 00981 while (*buf) { 00982 if ( (buf = parseLine(unparsed)) ) { 00983 return buf; // application is stopped now 00984 // additional output will be ignored for 00985 // now. we parse it later on 00986 } else { 00987 buf = ++unparsed; 00988 } 00989 } 00990 return orig; 00991 00992 } else { 00993 // assuming app is paused 00994 kdDebug() << "\nApp is paused:" << endl; 00995 char* unparsed = buf; 00996 char* orig = buf; 00997 while (*buf) { 00998 if ( (buf = parseInfo(buf)) ) { 00999 unparsed = orig = buf; 01000 } else { 01001 buf = ++unparsed; 01002 } 01003 } 01004 // Check if there are more vars to parse, otherwise update vartree widget 01005 parseLocals(); 01006 01007 return orig; 01008 01009 } 01010 01011 /* 01012 while (*unparsed) { 01013 char *parsed; 01014 if (*unparsed == (char)BLOCK_START) 01015 parsed = parseCmdBlock(unparsed); 01016 else 01017 parsed = parseOther(unparsed); 01018 01019 if (!parsed) 01020 break; 01021 01022 // Move one beyond the end of the parsed data 01023 unparsed = parsed+1; 01024 } 01025 */ 01026 // return (unparsed==buf) ? 0 : unparsed; 01027 } 01028 01029 // ************************************************************************** 01030 01031 void JDBController::setBreakpoint(const QCString &/*BPSetCmd*/, int /*key*/) 01032 { 01033 // queueCmd(new JDBSetBreakpointCommand("", key)); 01034 } 01035 01036 // ************************************************************************** 01037 01038 void JDBController::clearBreakpoint(const QCString &/*BPClearCmd*/) 01039 { 01040 // queueCmd(new JDBCommand("info breakpoints", NOTRUNCMD, NOTINFOCMD, BPLIST)); 01041 } 01042 01043 // ************************************************************************** 01044 01045 void JDBController::modifyBreakpoint(Breakpoint *) 01046 { 01047 } 01048 01049 // ************************************************************************** 01050 // SLOTS 01051 // ***** 01052 // For most of these slots data can only be sent to jdb when it 01053 // isn't busy and it is running. 01054 // ************************************************************************** 01055 01059 void JDBController::slotStart(const QString &/*application*/, const QString &args, const QString &sDbgShell) 01060 { 01061 Q_ASSERT (!dbgProcess_ && !tty_); 01062 01063 // Remove .class suffix and leading path information from appname 01064 // (should not be there anyway) 01065 01066 tty_ = new STTY(config_dbgTerminal_, "konsole"); 01067 if (!config_dbgTerminal_) { 01068 connect( tty_, SIGNAL(OutOutput(const char*)), SIGNAL(ttyStdout(const char*)) ); 01069 connect( tty_, SIGNAL(ErrOutput(const char*)), SIGNAL(ttyStderr(const char*)) ); 01070 } 01071 01072 QString tty(tty_->getSlave()); 01073 01074 if (tty.isEmpty()) { 01075 KMessageBox::error(0, i18n("JDB cannot use the tty* or pty* devices.\n" 01076 "Check the settings on /dev/tty* and /dev/pty*\n" 01077 "As root you may need to \"chmod ug+rw\" tty* and pty* devices " 01078 "and/or add the user to the tty group using " 01079 "\"usermod -G tty username\"")); 01080 01081 delete tty_; 01082 tty_ = 0; 01083 return; 01084 } 01085 01086 JDB_DISPLAY("\nStarting JDB - app:["+mainclass_+"] classpath:["+classpath_+"] args:["+args+"] sDbgShell:["+sDbgShell+"]\n"); 01087 dbgProcess_ = new KProcess; 01088 01089 connect( dbgProcess_, SIGNAL(receivedStdout(KProcess *, char *, int)), 01090 this, SLOT(slotDbgStdout(KProcess *, char *, int)) ); 01091 01092 connect( dbgProcess_, SIGNAL(receivedStderr(KProcess *, char *, int)), 01093 this, SLOT(slotDbgStderr(KProcess *, char *, int)) ); 01094 01095 connect( dbgProcess_, SIGNAL(wroteStdin(KProcess *)), 01096 this, SLOT(slotDbgWroteStdin(KProcess *)) ); 01097 01098 connect( dbgProcess_, SIGNAL(processExited(KProcess*)), 01099 this, SLOT(slotDbgProcessExited(KProcess*)) ); 01100 01101 01102 if (!sDbgShell.isEmpty()) 01103 *dbgProcess_<<"/bin/sh"<<"-c"<<sDbgShell+" "+config_jdbPath_+ 01104 QString("jdb")<<"-classpath"<<classpath_<<mainclass_<<args; 01105 else 01106 *dbgProcess_<<config_jdbPath_+QString("jdb")<<"-classpath"<<classpath_<<mainclass_<<args; 01107 01108 if (! dbgProcess_->start( KProcess::NotifyOnExit, 01109 KProcess::Communication(KProcess::All) ) ) 01110 { 01111 JDB_DISPLAY("\nFailed to start JDB - app:["+mainclass_+"]\n"); 01112 } 01113 01114 // JDB takes some time to start up 01115 setStateOn(s_dbgNotStarted); 01116 emit dbgStatus ("", state_); 01117 01118 // Initialise jdb. At this stage jdb is sitting wondering what to do, 01119 // and to whom. Organise a few things, then set up the tty for the application, 01120 // and the application itself 01121 01122 } 01123 01124 // ************************************************************************** 01125 01126 void JDBController::slotCoreFile(const QString&) 01127 { 01128 } 01129 01130 01131 void JDBController::slotAttachTo(int) 01132 { 01133 } 01134 01135 // ************************************************************************** 01136 01137 void JDBController::slotDebuggerStarted() { 01138 kdDebug() << "slotRun()" << endl; 01139 if (stateIsOn(s_appBusy|s_dbgNotStarted|s_shuttingDown)) 01140 return; 01141 bool first_flag = FALSE; 01142 01143 kdDebug() << "slotRun()" << endl; 01144 if (stateIsOn(s_appNotStarted)) { 01145 first_flag = TRUE; 01146 queueCmd(new JDBCommand(QString("stop in " + mainclass_ + ".main(java.lang.String[])" ).latin1() , NOTRUNCMD, NOTINFOCMD, 0 ) ); 01147 } 01148 01149 queueCmd(new JDBCommand(stateIsOn(s_appNotStarted) ? "run" : "cont", RUNCMD, NOTINFOCMD, 0)); 01150 01151 // Signal we are waiting for the first breakpoint to be reached 01152 setStateOn(s_appStarting); 01153 } 01154 01155 void JDBController::slotRun() 01156 { 01157 if (stateIsOn(s_dbgNotStarted)) { 01158 // Connect to debuggerStarted slot to wait for jdb to finish 01159 // initialization 01160 connect(this, SIGNAL(debuggerStarted()), SLOT(slotDebuggerStarted())); 01161 } else { 01162 // emit debuggerStarted(); 01163 } 01164 01165 } 01166 01167 // ************************************************************************** 01168 01169 void JDBController::slotRunUntil(const QString &, int) 01170 { 01171 } 01172 01173 // ************************************************************************** 01174 01175 void JDBController::slotStepInto() 01176 { 01177 kdDebug() << "slotStepInstruction" << endl; 01178 if (stateIsOn(s_dbgNotStarted) || stateIsOn(s_appBusy) || stateIsOn(s_parsingOutput)) { return; } 01179 queueCmd(new JDBCommand("stepi", RUNCMD, NOTINFOCMD, 0)); 01180 } 01181 01182 // ************************************************************************** 01183 01184 void JDBController::slotStepIntoIns() 01185 { 01186 } 01187 01188 // ************************************************************************** 01189 01190 void JDBController::slotStepOver() { 01191 kdDebug() << "slotStepOver" << endl; 01192 if (stateIsOn(s_appStarting) || stateIsOn(s_dbgNotStarted) || stateIsOn(s_appBusy) || stateIsOn(s_parsingOutput)) { return; } 01193 queueCmd(new JDBCommand("step", RUNCMD, NOTINFOCMD, 0)); 01194 } 01195 01196 // ************************************************************************** 01197 01198 void JDBController::slotStepOverIns() 01199 { 01200 } 01201 01202 // ************************************************************************** 01203 01204 void JDBController::slotStepOutOff() 01205 { 01206 } 01207 01208 // ************************************************************************** 01209 01210 // Only interrupt a running program. 01211 void JDBController::slotBreakInto() 01212 { 01213 } 01214 01215 // ************************************************************************** 01216 01217 // See what, if anything needs doing to this breakpoint. 01218 void JDBController::slotBPState(Breakpoint *) 01219 { 01220 } 01221 01222 // ************************************************************************** 01223 01224 void JDBController::slotClearAllBreakpoints() 01225 { 01226 } 01227 01228 // ************************************************************************** 01229 01230 void JDBController::slotDisassemble(const QString &, const QString &) 01231 { 01232 } 01233 01234 // ************************************************************************** 01235 01236 void JDBController::slotMemoryDump(const QString &, const QString &) 01237 { 01238 } 01239 01240 // ************************************************************************** 01241 01242 void JDBController::slotRegisters() 01243 { 01244 } 01245 01246 // ************************************************************************** 01247 01248 void JDBController::slotLibraries() 01249 { 01250 } 01251 01252 // ************************************************************************** 01253 01254 void JDBController::slotSelectFrame(int) 01255 { 01256 } 01257 01258 // ************************************************************************** 01259 01260 // This is called when the user desires to see the details of an item, by 01261 // clicking open an varItem on the varTree. 01262 void JDBController::slotExpandItem(VarItem *) 01263 { 01264 } 01265 01266 // ************************************************************************** 01267 01268 // This is called when an item needs special processing to show a value. 01269 // Example = QStrings. We want to display the QString string against the var name 01270 // so the user doesn't have to open the qstring to find it. Here's where that happens 01271 void JDBController::slotExpandUserItem(VarItem *, const QCString& ) 01272 { 01273 } 01274 01275 // ************************************************************************** 01276 01277 // The user will only get locals if one of the branches to the local tree 01278 // is open. This speeds up stepping through code a great deal. 01280 void JDBController::slotSetLocalViewState(bool) 01281 { 01282 } 01283 01284 // ************************************************************************** 01285 01286 // Data from jdb gets processed here. 01287 void JDBController::slotDbgStdout(KProcess *, char *buf, int buflen) 01288 { 01289 // Allocate some buffer space, if adding to this buffer will exceed it 01290 if (jdbOutputLen_+buflen+1 > jdbSizeofBuf_) { 01291 jdbSizeofBuf_ = jdbOutputLen_+buflen+1; 01292 char *newBuf = new char[jdbSizeofBuf_]; // ??? shoudn't this be malloc ??? 01293 if (jdbOutputLen_) 01294 memcpy(newBuf, jdbOutput_, jdbOutputLen_+1); 01295 delete[] jdbOutput_; // ??? and free ??? 01296 jdbOutput_ = newBuf; 01297 } 01298 01299 // Copy the data out of the KProcess buffer before it gets overwritten 01300 // and fake a string so we can use the string fns on this buffer 01301 memcpy(jdbOutput_+jdbOutputLen_, buf, buflen); 01302 jdbOutputLen_ += buflen; 01303 *(jdbOutput_+jdbOutputLen_) = 0; 01304 01305 if (char *nowAt = parse(jdbOutput_)) { 01306 Q_ASSERT(nowAt <= jdbOutput_+jdbOutputLen_+1); 01307 jdbOutputLen_ = strlen(nowAt); 01308 // Some bytes that weren't parsed need to be moved to the head of the buffer 01309 if (jdbOutputLen_) 01310 memmove(jdbOutput_, nowAt, jdbOutputLen_); // Overlapping data 01311 01312 } 01313 // check the queue for any commands to send 01314 executeCmd(); 01315 kdDebug() << "stdout" << endl; 01316 } 01317 01318 // ************************************************************************** 01319 01320 void JDBController::slotDbgStderr(KProcess */*proc*/, char *buf, int/* buflen*/) 01321 { 01322 // At the moment, just drop a message out 01323 // dont and redirect 01324 kdDebug() << "STDERR\n"; 01325 DBG_DISPLAY(QString("\nSTDERR: ")+QString(buf)); 01326 // slotDbgStdout(proc, buf, buflen); 01327 } 01328 01329 // ************************************************************************** 01330 01331 void JDBController::slotDbgWroteStdin(KProcess *) 01332 { 01333 setStateOff(s_waitForWrite); 01334 executeCmd(); 01335 kdDebug() << "dbgwrotestdin" << endl; 01336 } 01337 01338 // ************************************************************************** 01339 01340 void JDBController::slotDbgProcessExited(KProcess*) 01341 { 01342 destroyCmds(); 01343 state_ = s_appNotStarted|s_programExited|(state_&s_viewLocals); 01344 emit dbgStatus (i18n("Process exited"), state_); 01345 01346 JDB_DISPLAY(QString("\n(jdb) Process exited")); 01347 } 01348 01349 // ************************************************************************** 01350 01351 01358 QString JDBController::getFile(QString className) 01359 { 01360 return QString(projectDirectory_ + "/" + className + ".java"); 01361 } 01362 01363 // ********************************************************************** 01364 01365 void JDBController::varUpdateDone() 01366 { 01367 kdDebug() << "VarUpdateDone" << endl; 01368 01369 QString locals = ""; 01370 QDictIterator<JDBVarItem> it(localData); // iterator for dict 01371 if (!it.toFirst()) { return; } 01372 // make sure we dont visit nodes more than once 01373 while (it.current()) { 01374 01375 if (!it.currentKey().contains(".")) { 01376 locals += it.current()->toString() + QString(","); 01377 } 01378 ++it; 01379 } 01380 01381 locals[locals.length()-1] = ' '; // remove trailing comma 01382 char* _l = new char[locals.length()]; 01383 strcpy(_l, locals.latin1()); 01384 kdDebug() << "\nLocals: "<< _l << endl; 01385 01386 01387 varTree_->trim(); 01388 01389 FrameRoot *frame; 01390 // The locals are always attached to the currentFrame 01391 // so make sure we have one of those. 01392 if (!(frame = varTree_->findFrame(currentFrame_))) 01393 frame = new FrameRoot(varTree_, currentFrame_); 01394 01395 Q_ASSERT(frame); 01396 frame->setFrameName(frameStack_->getFrameName(currentFrame_)); 01397 01398 frame->setLocals(_l); 01399 01400 varTree_->viewport()->setUpdatesEnabled(true); 01401 varTree_->repaint(); 01402 localData.clear(); 01403 setStateOff(s_parsingOutput); 01404 01405 } 01406 01407 01408 // The time limit has expired so set the state off. 01409 void JDBController::slotAbortTimedEvent() 01410 { 01411 setStateOff(s_waitTimer); 01412 DBG_DISPLAY(QString("Timer aborted\n")); 01413 } 01414 01415 // ************************************************************************** 01416 01417 void JDBController::slotStepInSource(const QString &fileName, int lineNum) 01418 { 01419 DBG_DISPLAY((QString("(Show step in source) ")+fileName+QString(":") 01420 +QString().setNum(lineNum)).local8Bit().data()); 01421 } 01422 01423 // ************************************************************************** 01424 01425 void JDBController::slotDbgStatus(const QString &status, int state) 01426 { 01427 QString s("(status) "); 01428 if (!state) 01429 s += QString("<program paused>"); 01430 if (state & s_dbgNotStarted) 01431 s += QString("<dbg not started>"); 01432 if (state & s_appNotStarted) 01433 s += QString("<app not started>"); 01434 if (state & s_appBusy) 01435 s += QString("<app busy>"); 01436 if (state & s_waitForWrite) 01437 s += QString("<wait for write>"); 01438 if (state & s_programExited) 01439 s += QString("<program exited>"); 01440 if (state & s_silent) 01441 s += QString("<silent>"); 01442 if (state & s_viewLocals) 01443 s += QString("<viewing locals>"); 01444 01445 DBG_DISPLAY((s+status).local8Bit().data()); 01446 } 01447 01448 01449 JDBVarItem::JDBVarItem() { 01450 value = ""; 01451 name = ""; 01452 } 01453 01454 QString JDBVarItem::toString() { 01455 if (!value.isEmpty()) { 01456 kdDebug() << value <<" - "; 01457 return name + " = " + value; 01458 } else { 01459 // iterate over siblings and build return string 01460 QString tmp; 01461 JDBVarItem *item; 01462 01463 for (item = this->siblings.first(); item != 0; item = this->siblings.next()) { 01464 tmp += item->toString() + ","; 01465 delete item; 01466 } 01467 01468 tmp = name + " = {" +tmp; 01469 tmp[tmp.length()-1] = '}'; // remove trailing comma 01470 return tmp; 01471 } 01472 } 01473 01474 } 01475 01476 // ************************************************************************** 01477 #include "jdbcontroller.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:02 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003