• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kdebug.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, 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   buf[0] = '\0';
00253 
00254   static bool printTimeStamp = !(QCString(getenv("KDE_DEBUG_TIMESTAMP")).isEmpty());
00255   if ( printTimeStamp ) {
00256       const QString ts = QDateTime::currentDateTime().time().toString() + ' ';
00257       strlcat( buf, ts.latin1(), BUFSIZE );
00258   }
00259 
00260   if ( !kDebug_data->aAreaName.isEmpty() ) {
00261       strlcat( buf, kDebug_data->aAreaName.data(), BUFSIZE );
00262       strlcat( buf, ": ", BUFSIZE );
00263       strlcat( buf, data, BUFSIZE );
00264   }
00265   else
00266       strlcat( buf, data, BUFSIZE );
00267 
00268 
00269   // Output
00270   switch( nOutput )
00271   {
00272   case 0: // File
00273   {
00274       const char* aKey;
00275       switch( nLevel )
00276       {
00277       case KDEBUG_INFO:
00278           aKey = "InfoFilename";
00279           break;
00280       case KDEBUG_WARN:
00281           aKey = "WarnFilename";
00282           break;
00283       case KDEBUG_FATAL:
00284           aKey = "FatalFilename";
00285           break;
00286       case KDEBUG_ERROR:
00287       default:
00288           aKey = "ErrorFilename";
00289           break;
00290       }
00291       QFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") );
00292       aOutputFile.open( IO_WriteOnly | IO_Append | IO_Raw );
00293       aOutputFile.writeBlock( buf, strlen( buf ) );
00294       aOutputFile.close();
00295       break;
00296   }
00297   case 1: // Message Box
00298   {
00299       // Since we are in kdecore here, we cannot use KMsgBox and use
00300       // QMessageBox instead
00301       if ( !kDebug_data->aAreaName.isEmpty() )
00302           aCaption += QString("(%1)").arg( kDebug_data->aAreaName );
00303       QMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
00304       break;
00305   }
00306   case 2: // Shell
00307   {
00308       write( 2, buf, strlen( buf ) );  //fputs( buf, stderr );
00309       break;
00310   }
00311   case 3: // syslog
00312   {
00313       syslog( nPriority, "%s", buf);
00314       break;
00315   }
00316   }
00317 
00318   // check if we should abort
00319   if( ( nLevel == KDEBUG_FATAL )
00320       && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
00321         abort();
00322 }
00323 
00324 kdbgstream &perror( kdbgstream &s) { return s << QString::fromLocal8Bit(strerror(errno)); }
00325 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
00326 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
00327 
00328 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
00329 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
00330 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
00331 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
00332 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
00333 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
00334 
00335 kdbgstream::kdbgstream(kdbgstream &str)
00336  : output(str.output), area(str.area), level(str.level), print(str.print) 
00337 { 
00338     str.output.truncate(0); 
00339 }
00340 
00341 void kdbgstream::flush() {
00342     if (output.isEmpty() || !print)
00343     return;
00344     kDebugBackend( level, area, output.local8Bit().data() );
00345     output = QString::null;
00346 }
00347 
00348 kdbgstream &kdbgstream::form(const char *format, ...)
00349 {
00350     char buf[4096];
00351     va_list arguments;
00352     va_start( arguments, format );
00353     vsnprintf( buf, sizeof(buf), format, arguments );
00354     va_end(arguments);
00355     *this << buf;
00356     return *this;
00357 }
00358 
00359 kdbgstream::~kdbgstream() {
00360     if (!output.isEmpty()) {
00361     fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
00362         fprintf(stderr, "%s", kdBacktrace().latin1());
00363     *this << "\n";
00364     }
00365 }
00366 
00367 kdbgstream& kdbgstream::operator << (char ch)
00368 {
00369   if (!print) return *this;
00370   if (!isprint(ch))
00371     output += "\\x" + QString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
00372   else {
00373     output += ch;
00374     if (ch == '\n') flush();
00375   }
00376   return *this;
00377 }
00378 
00379 kdbgstream& kdbgstream::operator << (QChar ch)
00380 {
00381   if (!print) return *this;
00382   if (!ch.isPrint())
00383     output += "\\x" + QString::number( ch.unicode(), 16 ).rightJustify(2, '0');
00384   else {
00385     output += ch;
00386     if (ch == '\n') flush();
00387   }
00388   return *this;
00389 }
00390 
00391 kdbgstream& kdbgstream::operator << (QWidget* widget)
00392 {
00393     return *this << const_cast< const QWidget* >( widget );
00394 }
00395 
00396 kdbgstream& kdbgstream::operator << (const QWidget* widget)
00397 {
00398   QString string, temp;
00399   // -----
00400   if(widget==0)
00401     {
00402       string=(QString)"[Null pointer]";
00403     } else {
00404       temp.setNum((ulong)widget, 16);
00405       string=(QString)"["+widget->className()+" pointer "
00406     + "(0x" + temp + ")";
00407       if(widget->name(0)==0)
00408     {
00409       string += " to unnamed widget, ";
00410     } else {
00411       string += (QString)" to widget " + widget->name() + ", ";
00412     }
00413       string += "geometry="
00414     + QString().setNum(widget->width())
00415     + "x"+QString().setNum(widget->height())
00416     + "+"+QString().setNum(widget->x())
00417     + "+"+QString().setNum(widget->y())
00418     + "]";
00419     }
00420   if (!print)
00421     {
00422       return *this;
00423     }
00424   output += string;
00425   if (output.at(output.length() -1 ) == '\n')
00426     {
00427       flush();
00428     }
00429   return *this;
00430 }
00431 /*
00432  * either use 'output' directly and do the flush if needed
00433  * or use the QString operator which calls the char* operator
00434  *
00435  */
00436 kdbgstream& kdbgstream::operator<<( const QDateTime& time) {
00437     *this << time.toString();
00438     return *this;
00439 }
00440 kdbgstream& kdbgstream::operator<<( const QDate& date) {
00441     *this << date.toString();
00442 
00443     return *this;
00444 }
00445 kdbgstream& kdbgstream::operator<<( const QTime& time ) {
00446     *this << time.toString();
00447     return *this;
00448 }
00449 kdbgstream& kdbgstream::operator<<( const QPoint& p ) {
00450     *this << "(" << p.x() << ", " << p.y() << ")";
00451     return *this;
00452 }
00453 kdbgstream& kdbgstream::operator<<( const QSize& s ) {
00454     *this << "[" << s.width() << "x" << s.height() << "]";
00455     return *this;
00456 }
00457 kdbgstream& kdbgstream::operator<<( const QRect& r ) {
00458     *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
00459     return *this;
00460 }
00461 kdbgstream& kdbgstream::operator<<( const QRegion& reg ) {
00462     *this<< "[ ";
00463 
00464     QMemArray<QRect>rs=reg.rects();
00465     for (uint i=0;i<rs.size();++i)
00466         *this << QString("[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() ) ;
00467 
00468     *this <<"]";
00469     return *this;
00470 }
00471 kdbgstream& kdbgstream::operator<<( const KURL& u ) {
00472     *this << u.prettyURL();
00473     return *this;
00474 }
00475 kdbgstream& kdbgstream::operator<<( const QStringList& l ) {
00476     *this << "(";
00477     *this << l.join(",");
00478     *this << ")";
00479 
00480     return *this;
00481 }
00482 kdbgstream& kdbgstream::operator<<( const QColor& c ) {
00483     if ( c.isValid() )
00484         *this <<c.name();
00485     else
00486         *this << "(invalid/default)";
00487     return *this;
00488 }
00489 kdbgstream& kdbgstream::operator<<( const QPen& p ) {
00490     static const char* const s_penStyles[] = {
00491         "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
00492         "DashDotDotLine" };
00493     static const char* const s_capStyles[] = {
00494         "FlatCap", "SquareCap", "RoundCap" };
00495     *this << "[ style:";
00496     *this << s_penStyles[ p.style() ];
00497     *this << " width:";
00498     *this << p.width();
00499     *this << " color:";
00500     if ( p.color().isValid() )
00501         *this << p.color().name();
00502     else
00503         *this <<"(invalid/default)";
00504     if ( p.width() > 0 ) // cap style doesn't matter, otherwise
00505     {
00506         *this << " capstyle:";
00507         *this << s_capStyles[ p.capStyle() >> 4 ];
00508         // join style omitted
00509     }
00510     *this <<" ]";
00511     return *this;
00512 }
00513 kdbgstream& kdbgstream::operator<<( const QBrush& b) {
00514     static const char* const s_brushStyles[] = {
00515         "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern",
00516         "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern",
00517         "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern",
00518         "DiagCrossPattern" };
00519 
00520     *this <<"[ style: ";
00521     *this <<s_brushStyles[ b.style() ];
00522     *this <<" color: ";
00523     // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
00524     if ( b.color().isValid() )
00525         *this <<b.color().name() ;
00526     else
00527         *this <<"(invalid/default)";
00528     if ( b.pixmap() )
00529         *this <<" has a pixmap";
00530     *this <<" ]";
00531     return *this;
00532 }
00533 
00534 kdbgstream& kdbgstream::operator<<( const QVariant& v) {
00535     *this << "[variant: ";
00536     *this << v.typeName();
00537     // For now we just attempt a conversion to string.
00538     // Feel free to switch(v.type()) and improve the output.
00539     *this << " toString=";
00540     *this << v.toString();
00541     *this << "]";
00542     return *this;
00543 }
00544 
00545 kdbgstream& kdbgstream::operator<<( const QByteArray& data) {
00546     if (!print) return *this;
00547     output += '[';
00548     unsigned int i = 0;
00549     unsigned int sz = QMIN( data.size(), 64 );
00550     for ( ; i < sz ; ++i ) {
00551         output += QString::number( (unsigned char) data[i], 16 ).rightJustify(2, '0');
00552         if ( i < sz )
00553             output += ' ';
00554     }
00555     if ( sz < data.size() )
00556         output += "...";
00557     output += ']';
00558     return *this;
00559 }
00560 
00561 QString kdBacktrace(int levels)
00562 {
00563     QString s;
00564 #ifdef HAVE_BACKTRACE
00565     void* trace[256];
00566     int n = backtrace(trace, 256);
00567     if (!n)
00568     return s;
00569     char** strings = backtrace_symbols (trace, n);
00570 
00571     if ( levels != -1 )
00572         n = QMIN( n, levels );
00573     s = "[\n";
00574 
00575     for (int i = 0; i < n; ++i)
00576         s += QString::number(i) +
00577              QString::fromLatin1(": ") +
00578              QString::fromLatin1(strings[i]) + QString::fromLatin1("\n");
00579     s += "]\n";
00580     if (strings)
00581         free (strings);
00582 #endif
00583     return s;
00584 }
00585 
00586 QString kdBacktrace()
00587 {
00588     return kdBacktrace(-1 /*all*/);
00589 }
00590 
00591 void kdClearDebugConfig()
00592 {
00593     if (kDebug_data) {
00594         delete kDebug_data->config;
00595         kDebug_data->config = 0;
00596     }
00597 }
00598 
00599 
00600 // Needed for --enable-final
00601 #ifdef NDEBUG
00602 #define kdDebug kndDebug
00603 #endif

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal