kdecore Library API Documentation

kdebug.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) 00003 2002 Holger Freyther (freyther@kde.org) 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #include "kdebug.h" 00022 00023 #ifdef NDEBUG 00024 #undef kdDebug 00025 #undef kdBacktrace 00026 #undef kdWarning 00027 #endif 00028 00029 #include "kdebugdcopiface.h" 00030 00031 #include "kapplication.h" 00032 #include "kglobal.h" 00033 #include "kinstance.h" 00034 #include "kstandarddirs.h" 00035 00036 #include <qmessagebox.h> 00037 #include <klocale.h> 00038 #include <qfile.h> 00039 #include <qintdict.h> 00040 #include <qstring.h> 00041 #include <qdatetime.h> 00042 #include <qpoint.h> 00043 #include <qrect.h> 00044 #include <qregion.h> 00045 #include <qstringlist.h> 00046 #include <qpen.h> 00047 #include <qbrush.h> 00048 #include <qsize.h> 00049 00050 #include <kurl.h> 00051 00052 #include <stdlib.h> // abort 00053 #include <unistd.h> // getpid 00054 #include <stdarg.h> // vararg stuff 00055 #include <ctype.h> // isprint 00056 #include <syslog.h> 00057 #include <errno.h> 00058 #include <string.h> 00059 #include <kconfig.h> 00060 #include "kstaticdeleter.h" 00061 #include <config.h> 00062 00063 #ifdef HAVE_BACKTRACE 00064 #include <execinfo.h> 00065 #endif 00066 00067 class KDebugEntry; 00068 00069 class KDebugEntry 00070 { 00071 public: 00072 KDebugEntry (int n, const QCString& d) {number=n; descr=d;} 00073 unsigned int number; 00074 QCString descr; 00075 }; 00076 00077 static QIntDict<KDebugEntry> *KDebugCache; 00078 00079 static KStaticDeleter< QIntDict<KDebugEntry> > kdd; 00080 00081 static QCString getDescrFromNum(unsigned int _num) 00082 { 00083 if (!KDebugCache) { 00084 kdd.setObject(KDebugCache, new QIntDict<KDebugEntry>( 601 )); 00085 // Do not call this deleter from ~KApplication 00086 KGlobal::unregisterStaticDeleter(&kdd); 00087 KDebugCache->setAutoDelete(true); 00088 } 00089 00090 KDebugEntry *ent = KDebugCache->find( _num ); 00091 if ( ent ) 00092 return ent->descr; 00093 00094 if ( !KDebugCache->isEmpty() ) // areas already loaded 00095 return QCString(); 00096 00097 QString filename(locate("config","kdebug.areas")); 00098 if (filename.isEmpty()) 00099 return QCString(); 00100 00101 QFile file(filename); 00102 if (!file.open(IO_ReadOnly)) { 00103 qWarning("Couldn't open %s", filename.local8Bit().data()); 00104 file.close(); 00105 return QCString(); 00106 } 00107 00108 uint lineNumber=0; 00109 QCString line(1024); 00110 int len; 00111 00112 while (( len = file.readLine(line.data(),line.size()-1) ) > 0) { 00113 int i=0; 00114 ++lineNumber; 00115 00116 while (line[i] && line[i] <= ' ') 00117 i++; 00118 00119 unsigned char ch=line[i]; 00120 00121 if ( !ch || ch =='#' || ch =='\n') 00122 continue; // We have an eof, a comment or an empty line 00123 00124 if (ch < '0' && ch > '9') { 00125 qWarning("Syntax error: no number (line %u)",lineNumber); 00126 continue; 00127 } 00128 00129 const int numStart=i; 00130 do { 00131 ch=line[++i]; 00132 } while ( ch >= '0' && ch <= '9'); 00133 00134 const Q_ULONG number =line.mid(numStart,i).toULong(); 00135 00136 while (line[i] && line[i] <= ' ') 00137 i++; 00138 00139 KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1))); 00140 } 00141 file.close(); 00142 00143 ent = KDebugCache->find( _num ); 00144 if ( ent ) 00145 return ent->descr; 00146 00147 return QCString(); 00148 } 00149 00150 enum DebugLevels { 00151 KDEBUG_INFO= 0, 00152 KDEBUG_WARN= 1, 00153 KDEBUG_ERROR= 2, 00154 KDEBUG_FATAL= 3 00155 }; 00156 00157 00158 struct kDebugPrivate { 00159 kDebugPrivate() : 00160 oldarea(0), config(0) { } 00161 00162 ~kDebugPrivate() { delete config; } 00163 00164 QCString aAreaName; 00165 unsigned int oldarea; 00166 KConfig *config; 00167 }; 00168 00169 static kDebugPrivate *kDebug_data = 0; 00170 static KStaticDeleter<kDebugPrivate> pcd; 00171 static KStaticDeleter<KDebugDCOPIface> dcopsd; 00172 static KDebugDCOPIface* kDebugDCOPIface = 0; 00173 00174 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data) 00175 { 00176 if ( !kDebug_data ) 00177 { 00178 pcd.setObject(kDebug_data, new kDebugPrivate()); 00179 // Do not call this deleter from ~KApplication 00180 KGlobal::unregisterStaticDeleter(&pcd); 00181 00182 // create the dcop interface if it has not been created yet 00183 if (!kDebugDCOPIface) 00184 { 00185 kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface); 00186 } 00187 } 00188 00189 if (!kDebug_data->config && KGlobal::_instance ) 00190 { 00191 kDebug_data->config = new KConfig("kdebugrc", false, false); 00192 kDebug_data->config->setGroup("0"); 00193 00194 //AB: this is necessary here, otherwise all output with area 0 won't be 00195 //prefixed with anything, unless something with area != 0 is called before 00196 if ( KGlobal::_instance ) 00197 kDebug_data->aAreaName = KGlobal::instance()->instanceName(); 00198 } 00199 00200 if (kDebug_data->config && kDebug_data->oldarea != nArea) { 00201 kDebug_data->config->setGroup( QString::number(static_cast<int>(nArea)) ); 00202 kDebug_data->oldarea = nArea; 00203 if ( nArea > 0 && KGlobal::_instance ) 00204 kDebug_data->aAreaName = getDescrFromNum(nArea); 00205 if ((nArea == 0) || kDebug_data->aAreaName.isEmpty()) 00206 if ( KGlobal::_instance ) 00207 kDebug_data->aAreaName = KGlobal::instance()->instanceName(); 00208 } 00209 00210 int nPriority = 0; 00211 QString aCaption; 00212 00213 /* Determine output */ 00214 00215 QString key; 00216 switch( nLevel ) 00217 { 00218 case KDEBUG_INFO: 00219 key = "InfoOutput"; 00220 aCaption = "Info"; 00221 nPriority = LOG_INFO; 00222 break; 00223 case KDEBUG_WARN: 00224 key = "WarnOutput"; 00225 aCaption = "Warning"; 00226 nPriority = LOG_WARNING; 00227 break; 00228 case KDEBUG_FATAL: 00229 key = "FatalOutput"; 00230 aCaption = "Fatal Error"; 00231 nPriority = LOG_CRIT; 00232 break; 00233 case KDEBUG_ERROR: 00234 default: 00235 /* Programmer error, use "Error" as default */ 00236 key = "ErrorOutput"; 00237 aCaption = "Error"; 00238 nPriority = LOG_ERR; 00239 break; 00240 } 00241 00242 short nOutput = kDebug_data->config ? kDebug_data->config->readNumEntry(key, 2) : 2; 00243 00244 // If the application doesn't have a QApplication object it can't use 00245 // a messagebox. 00246 if (!kapp && (nOutput == 1)) 00247 nOutput = 2; 00248 else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) 00249 return; 00250 00251 const int BUFSIZE = 4096; 00252 char buf[BUFSIZE]; 00253 int nSize; 00254 if ( !kDebug_data->aAreaName.isEmpty() ) { 00255 strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE ); 00256 strlcat( buf, ": ", BUFSIZE ); 00257 strlcat( buf, data, BUFSIZE ); 00258 nSize = strlen( buf ); 00259 } 00260 else 00261 nSize = strlcpy( buf, data, BUFSIZE ); 00262 00263 00264 // Output 00265 switch( nOutput ) 00266 { 00267 case 0: // File 00268 { 00269 const char* aKey; 00270 switch( nLevel ) 00271 { 00272 case KDEBUG_INFO: 00273 aKey = "InfoFilename"; 00274 break; 00275 case KDEBUG_WARN: 00276 aKey = "WarnFilename"; 00277 break; 00278 case KDEBUG_FATAL: 00279 aKey = "FatalFilename"; 00280 break; 00281 case KDEBUG_ERROR: 00282 default: 00283 aKey = "ErrorFilename"; 00284 break; 00285 } 00286 QFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") ); 00287 aOutputFile.open( IO_WriteOnly | IO_Append | IO_Raw ); 00288 if ( ( nSize == -1 ) || ( nSize >= BUFSIZE ) ) 00289 aOutputFile.writeBlock( buf, BUFSIZE-1 ); 00290 else 00291 aOutputFile.writeBlock( buf, nSize ); 00292 aOutputFile.close(); 00293 break; 00294 } 00295 case 1: // Message Box 00296 { 00297 // Since we are in kdecore here, we cannot use KMsgBox and use 00298 // QMessageBox instead 00299 if ( !kDebug_data->aAreaName.isEmpty() ) 00300 aCaption += QString("(%1)").arg( kDebug_data->aAreaName ); 00301 QMessageBox::warning( 0L, aCaption, data, i18n("&OK") ); 00302 break; 00303 } 00304 case 2: // Shell 00305 { 00306 write( 2, buf, nSize ); //fputs( buf, stderr ); 00307 break; 00308 } 00309 case 3: // syslog 00310 { 00311 syslog( nPriority, "%s", buf); 00312 break; 00313 } 00314 } 00315 00316 // check if we should abort 00317 if( ( nLevel == KDEBUG_FATAL ) 00318 && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) ) 00319 abort(); 00320 } 00321 00322 kdbgstream &perror( kdbgstream &s) { return s << QString::fromLocal8Bit(strerror(errno)); } 00323 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); } 00324 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); } 00325 00326 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); } 00327 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); } 00328 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); } 00329 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); } 00330 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); } 00331 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); } 00332 00333 void kdbgstream::flush() { 00334 if (output.isEmpty() || !print) 00335 return; 00336 kDebugBackend( level, area, output.local8Bit().data() ); 00337 output = QString::null; 00338 } 00339 00340 kdbgstream &kdbgstream::form(const char *format, ...) 00341 { 00342 char buf[4096]; 00343 va_list arguments; 00344 va_start( arguments, format ); 00345 vsnprintf( buf, sizeof(buf), format, arguments ); 00346 va_end(arguments); 00347 *this << buf; 00348 return *this; 00349 } 00350 00351 kdbgstream::~kdbgstream() { 00352 if (!output.isEmpty()) { 00353 fprintf(stderr, "ASSERT: debug output not ended with \\n\n"); 00354 fprintf(stderr, "%s", kdBacktrace().latin1()); 00355 *this << "\n"; 00356 } 00357 } 00358 00359 kdbgstream& kdbgstream::operator << (char ch) 00360 { 00361 if (!print) return *this; 00362 if (!isprint(ch)) 00363 output += "\\x" + QString::number( static_cast<uint>( ch ) + 0x100, 16 ).right(2); 00364 else { 00365 output += ch; 00366 if (ch == '\n') flush(); 00367 } 00368 return *this; 00369 } 00370 00371 kdbgstream& kdbgstream::operator << (QWidget* widget) 00372 { 00373 return *this << const_cast< const QWidget* >( widget ); 00374 } 00375 00376 kdbgstream& kdbgstream::operator << (const QWidget* widget) 00377 { 00378 QString string, temp; 00379 // ----- 00380 if(widget==0) 00381 { 00382 string=(QString)"[Null pointer]"; 00383 } else { 00384 temp.setNum((ulong)widget, 16); 00385 string=(QString)"["+widget->className()+" pointer " 00386 + "(0x" + temp + ")"; 00387 if(widget->name(0)==0) 00388 { 00389 string += " to unnamed widget, "; 00390 } else { 00391 string += (QString)" to widget " + widget->name() + ", "; 00392 } 00393 string += "geometry=" 00394 + QString().setNum(widget->width()) 00395 + "x"+QString().setNum(widget->height()) 00396 + "+"+QString().setNum(widget->x()) 00397 + "+"+QString().setNum(widget->y()) 00398 + "]"; 00399 } 00400 if (!print) 00401 { 00402 return *this; 00403 } 00404 output += string; 00405 if (output.at(output.length() -1 ) == '\n') 00406 { 00407 flush(); 00408 } 00409 return *this; 00410 } 00411 /* 00412 * either use 'output' directly and do the flush if needed 00413 * or use the QString operator which calls the char* operator 00414 * 00415 */ 00416 kdbgstream& kdbgstream::operator<<( const QDateTime& time) { 00417 *this << time.toString(); 00418 return *this; 00419 } 00420 kdbgstream& kdbgstream::operator<<( const QDate& date) { 00421 *this << date.toString(); 00422 00423 return *this; 00424 } 00425 kdbgstream& kdbgstream::operator<<( const QTime& time ) { 00426 *this << time.toString(); 00427 return *this; 00428 } 00429 kdbgstream& kdbgstream::operator<<( const QPoint& p ) { 00430 *this << "(" << p.x() << ", " << p.y() << ")"; 00431 return *this; 00432 } 00433 kdbgstream& kdbgstream::operator<<( const QSize& s ) { 00434 *this << "[" << s.width() << "x" << s.height() << "]"; 00435 return *this; 00436 } 00437 kdbgstream& kdbgstream::operator<<( const QRect& r ) { 00438 *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]"; 00439 return *this; 00440 } 00441 kdbgstream& kdbgstream::operator<<( const QRegion& reg ) { 00442 *this<< "[ "; 00443 00444 QMemArray<QRect>rs=reg.rects(); 00445 for (uint i=0;i<rs.size();++i) 00446 *this << QString("[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() ) ; 00447 00448 *this <<"]"; 00449 return *this; 00450 } 00451 kdbgstream& kdbgstream::operator<<( const KURL& u ) { 00452 *this << u.prettyURL(); 00453 return *this; 00454 } 00455 kdbgstream& kdbgstream::operator<<( const QStringList& l ) { 00456 *this << "("; 00457 *this << l.join(","); 00458 *this << ")"; 00459 00460 return *this; 00461 } 00462 kdbgstream& kdbgstream::operator<<( const QColor& c ) { 00463 if ( c.isValid() ) 00464 *this <<c.name(); 00465 else 00466 *this << "(invalid/default)"; 00467 return *this; 00468 } 00469 kdbgstream& kdbgstream::operator<<( const QPen& p ) { 00470 static const char* const s_penStyles[] = { 00471 "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine", 00472 "DashDotDotLine" }; 00473 static const char* const s_capStyles[] = { 00474 "FlatCap", "SquareCap", "RoundCap" }; 00475 *this << "[ style:"; 00476 *this << s_penStyles[ p.style() ]; 00477 *this << " width:"; 00478 *this << p.width(); 00479 *this << " color:"; 00480 if ( p.color().isValid() ) 00481 *this << p.color().name(); 00482 else 00483 *this <<"(invalid/default)"; 00484 if ( p.width() > 0 ) // cap style doesn't matter, otherwise 00485 { 00486 *this << " capstyle:"; 00487 *this << s_capStyles[ p.capStyle() >> 4 ]; 00488 // join style omitted 00489 } 00490 *this <<" ]"; 00491 return *this; 00492 } 00493 kdbgstream& kdbgstream::operator<<( const QBrush& b) { 00494 static const char* const s_brushStyles[] = { 00495 "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern", 00496 "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern", 00497 "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern", 00498 "DiagCrossPattern" }; 00499 00500 *this <<"[ style: "; 00501 *this <<s_brushStyles[ b.style() ]; 00502 *this <<" color: "; 00503 // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes) 00504 if ( b.color().isValid() ) 00505 *this <<b.color().name() ; 00506 else 00507 *this <<"(invalid/default)"; 00508 if ( b.pixmap() ) 00509 *this <<" has a pixmap"; 00510 *this <<" ]"; 00511 return *this; 00512 } 00513 00514 QString kdBacktrace(int levels) 00515 { 00516 QString s; 00517 #ifdef HAVE_BACKTRACE 00518 void* trace[256]; 00519 int n = backtrace(trace, 256); 00520 if (!n) 00521 return s; 00522 char** strings = backtrace_symbols (trace, n); 00523 00524 if ( levels != -1 ) 00525 n = QMIN( n, levels ); 00526 s = "[\n"; 00527 00528 for (int i = 0; i < n; ++i) 00529 s += QString::number(i) + 00530 QString::fromLatin1(": ") + 00531 QString::fromLatin1(strings[i]) + QString::fromLatin1("\n"); 00532 s += "]\n"; 00533 if (strings) 00534 free (strings); 00535 #endif 00536 return s; 00537 } 00538 00539 QString kdBacktrace() 00540 { 00541 return kdBacktrace(-1 /*all*/); 00542 } 00543 00544 void kdClearDebugConfig() 00545 { 00546 delete kDebug_data->config; 00547 kDebug_data->config = 0; 00548 } 00549 00550 00551 // Needed for --enable-final 00552 #ifdef NDEBUG 00553 #define kdDebug kndDebug 00554 #endif
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:14:00 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003