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