| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kdebug.cpp

    00001 /* This file is part of the KDE libraries
    00002     Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
    00003
    00004     This library is free software; you can redistribute it and/or
    00005     modify it under the terms of the GNU Library General Public
    00006     License as published by the Free Software Foundation; either
    00007     version 2 of the License, or (at your option) any later version.
    00008
    00009     This library is distributed in the hope that it will be useful,
    00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012     Library General Public License for more details.
    00013
    00014     You should have received a copy of the GNU Library General Public License
    00015     along with this library; see the file COPYING.LIB.  If not, write to
    00016     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017     Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 // Include our header without NDEBUG defined to avoid having the kDebugInfo
    00021 // functions inlined to noops (which would then conflict with their definition
    00022 // here).
    00023
    00024 #include "kdebug.h"
    00025
    00026 #ifdef NDEBUG
    00027 #undef kdDebug
    00028 #undef kdBacktrace
    00029 #endif
    00030
    00031 #include "kapplication.h"
    00032 #include "kglobal.h"
    00033 #include "kinstance.h"
    00034 #include "kstandarddirs.h"
    00035 #include <qmessagebox.h>
    00036 #include <klocale.h>
    00037 #include <qfile.h>
    00038 #include <qintdict.h>
    00039 #include <qstring.h>
    00040 #include <qtextstream.h>
    00041
    00042 #include <stdlib.h>     // abort
    00043 #include <unistd.h>     // getpid
    00044 #include <stdarg.h>     // vararg stuff
    00045 #include <ctype.h>      // isprint
    00046 #include <syslog.h>
    00047 #include <errno.h>
    00048 #include <string.h>
    00049 #include <kconfig.h>
    00050 #include "kstaticdeleter.h"
    00051 #include <config.h>
    00052
    00053 #ifdef HAVE_BACKTRACE
    00054 #include <execinfo.h>
    00055 #endif
    00056
    00057 class KDebugEntry;
    00058
    00059 class KDebugEntry
    00060 {
    00061 public:
    00062     KDebugEntry (int n, QString d) {number=n; descr=d;}
    00063     unsigned int number;
    00064     QString descr;
    00065 };
    00066
    00067 static QIntDict<KDebugEntry> *KDebugCache;
    00068
    00069 static KStaticDeleter< QIntDict<KDebugEntry> > kdd;
    00070
    00071 static QString getDescrFromNum(unsigned int _num)
    00072 {
    00073   if (!KDebugCache) {
    00074     kdd.setObject(KDebugCache, new QIntDict<KDebugEntry>);
    00075     // Do not call this deleter from ~KApplication
    00076     KGlobal::unregisterStaticDeleter(&kdd);
    00077     KDebugCache->setAutoDelete(true);
    00078   }
    00079
    00080   KDebugEntry *ent = KDebugCache->find( _num );
    00081   if ( ent )
    00082     return ent->descr;
    00083
    00084   if ( !KDebugCache->isEmpty() ) // areas already loaded
    00085     return QString::null;
    00086
    00087   QString filename(locate("config","kdebug.areas"));
    00088   QFile file(filename);
    00089   if (!file.open(IO_ReadOnly)) {
    00090     qWarning("Couldn't open %s", filename.local8Bit().data());
    00091     file.close();
    00092     return "";
    00093   }
    00094
    00095   unsigned long number = 0;
    00096   bool longOK;
    00097
    00098   QTextStream *ts = new QTextStream(&file);
    00099   ts->setEncoding( QTextStream::Latin1 );
    00100   while (!ts->eof()) {
    00101     const QString data(ts->readLine());
    00102     int i = 0;
    00103     int len = data.length();
    00104
    00105     QChar ch = data[0];
    00106     if (ch == '#' || ch.isNull()) {
    00107       continue;
    00108     }
    00109     while (ch.isSpace()) {
    00110       if (!(i < len))
    00111         continue;
    00112       ++i;
    00113       ch = data[i];
    00114     }
    00115     if (ch.isNumber()) {
    00116         int numStart = i ;
    00117         while (ch.isNumber())  {
    00118           if (!(i < len))
    00119             continue;
    00120           ++i;
    00121           ch = data[i];
    00122         }
    00123         number = data.mid(numStart,i).toULong(&longOK);
    00124     }
    00125     while (ch.isSpace()) {
    00126       if (!(i < len))
    00127         continue;
    00128       ++i;
    00129       ch = data[i];
    00130     }
    00131     const QString description(data.mid(i, len));
    00132     //qDebug("number: [%i] description: [%s]", number, description.latin1());
    00133
    00134     KDebugCache->insert(number, new KDebugEntry(number,description));
    00135   }
    00136
    00137   delete ts;
    00138   file.close();
    00139
    00140   ent = KDebugCache->find( _num );
    00141   if ( ent )
    00142       return ent->descr;
    00143
    00144   return QString::null;
    00145 }
    00146
    00147 enum DebugLevels {
    00148     KDEBUG_INFO=    0,
    00149     KDEBUG_WARN=    1,
    00150     KDEBUG_ERROR=   2,
    00151     KDEBUG_FATAL=   3
    00152 };
    00153
    00154
    00155 struct kDebugPrivate {
    00156   kDebugPrivate() :
    00157         oldarea(0), config(0) { }
    00158
    00159   ~kDebugPrivate() { delete config; }
    00160
    00161   QString aAreaName;
    00162   unsigned int oldarea;
    00163   KConfig *config;
    00164 };
    00165
    00166 static kDebugPrivate *kDebug_data = 0;
    00167 static KStaticDeleter<kDebugPrivate> pcd;
    00168
    00169 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
    00170 {
    00171   if ( !kDebug_data )
    00172   {
    00173       pcd.setObject(kDebug_data, new kDebugPrivate());
    00174       // Do not call this deleter from ~KApplication
    00175       KGlobal::unregisterStaticDeleter(&pcd);
    00176   }
    00177
    00178   if (!kDebug_data->config && KGlobal::_instance )
    00179   {
    00180       kDebug_data->config = new KConfig("kdebugrc", false, false);
    00181       kDebug_data->config->setGroup("0");
    00182   }
    00183
    00184   if (kDebug_data->config && kDebug_data->oldarea != nArea) {
    00185     kDebug_data->config->setGroup( QString::number(static_cast<int>(nArea)) );
    00186     kDebug_data->oldarea = nArea;
    00187     if ( nArea > 0 && KGlobal::_instance )
    00188       kDebug_data->aAreaName = getDescrFromNum(nArea);
    00189     if ((nArea == 0) || kDebug_data->aAreaName.isEmpty())
    00190       if ( KGlobal::_instance )
    00191         kDebug_data->aAreaName = KGlobal::instance()->instanceName();
    00192   }
    00193
    00194   int nPriority = 0;
    00195   QString aCaption;
    00196
    00197     /* Determine output */
    00198
    00199     QString key;
    00200     switch( nLevel )
    00201       {
    00202       case KDEBUG_INFO:
    00203         key = "InfoOutput";
    00204         aCaption = "Info";
    00205         nPriority = LOG_INFO;
    00206         break;
    00207       case KDEBUG_WARN:
    00208         key = "WarnOutput";
    00209         aCaption = "Warning";
    00210         nPriority = LOG_WARNING;
    00211         break;
    00212       case KDEBUG_FATAL:
    00213         key = "FatalOutput";
    00214         aCaption = "Fatal Error";
    00215         nPriority = LOG_CRIT;
    00216         break;
    00217       case KDEBUG_ERROR:
    00218       default:
    00219         /* Programmer error, use "Error" as default */
    00220         key = "ErrorOutput";
    00221         aCaption = "Error";
    00222         nPriority = LOG_ERR;
    00223         break;
    00224       }
    00225
    00226   short nOutput = kDebug_data->config ? kDebug_data->config->readNumEntry(key, 2) : 2;
    00227
    00228   // If the application doesn't have a QApplication object it can't use
    00229   // a messagebox.
    00230   if (!kapp && (nOutput == 1))
    00231     nOutput = 2;
    00232
    00233   // Output
    00234   switch( nOutput )
    00235         {
    00236         case 0: // File
    00237           {
    00238                 QString aKey;
    00239                 switch( nLevel )
    00240                 {
    00241                     case KDEBUG_INFO:
    00242                         aKey = "InfoFilename";
    00243                         break;
    00244                     case KDEBUG_WARN:
    00245                         aKey = "WarnFilename";
    00246                         break;
    00247                     case KDEBUG_FATAL:
    00248                         aKey = "FatalFilename";
    00249                         break;
    00250                     case KDEBUG_ERROR:
    00251                     default:
    00252                         aKey = "ErrorFilename";
    00253                         break;
    00254                 }
    00255                 QString aOutputFileName = kDebug_data->config->readPathEntry(aKey, "kdebug.dbg");
    00256
    00257                 const int BUFSIZE = 4096;
    00258                 char buf[BUFSIZE] = "";
    00259                 buf[BUFSIZE-1] = '\0';
    00260                 int nSize;
    00261                 if ( !kDebug_data->aAreaName.isEmpty() )
    00262                     nSize = snprintf( buf, BUFSIZE-1, "%s: %s", kDebug_data->aAreaName.ascii(), data);
    00263                 else
    00264                     nSize = snprintf( buf, BUFSIZE-1, "%s", data);
    00265
    00266                 QFile aOutputFile( aOutputFileName );
    00267                 aOutputFile.open( IO_WriteOnly | IO_Append );
    00268                 if ( ( nSize == -1 ) || ( nSize >= BUFSIZE ) )
    00269                     aOutputFile.writeBlock( buf, BUFSIZE-1 );
    00270                 else
    00271                     aOutputFile.writeBlock( buf, nSize );
    00272                 aOutputFile.close();
    00273                 break;
    00274           }
    00275         case 1: // Message Box
    00276           {
    00277                 // Since we are in kdecore here, we cannot use KMsgBox and use
    00278                 // QMessageBox instead
    00279               if ( !kDebug_data->aAreaName.isEmpty() ) aCaption += QString("(")+kDebug_data->aAreaName+")";
    00280               QMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
    00281               break;
    00282           }
    00283         case 2: // Shell
    00284           {
    00285               FILE *output;
    00286               /* we used to use stdout for debug
    00287               if (nPriority == LOG_INFO)
    00288                   output = stderr;
    00289               else */
    00290                   output = stderr;
    00291               // Uncomment this to get the pid of the app in the output (useful for e.g. kioslaves)
    00292               // if ( !kDebug_data->aAreaName.isEmpty() ) fprintf( output, "%d %s: ", (int)getpid(), kDebug_data->aAreaName.ascii() );
    00293               if ( !kDebug_data->aAreaName.isEmpty() ) fprintf( output, "%s: ", kDebug_data->aAreaName.ascii() );
    00294               fputs(  data, output);
    00295               break;
    00296           }
    00297         case 3: // syslog
    00298           {
    00299               syslog( nPriority, "%s", data);
    00300           }
    00301         case 4: // nothing
    00302           {
    00303           }
    00304         }
    00305
    00306   // check if we should abort
    00307   if( ( nLevel == KDEBUG_FATAL )
    00308       && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
    00309         abort();
    00310 }
    00311
    00312 kdbgstream &perror( kdbgstream &s) { return s << QString::fromLocal8Bit(strerror(errno)); }
    00313 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
    00314 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
    00315
    00316 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
    00317 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
    00318 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
    00319 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
    00320 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
    00321 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
    00322
    00323 void kdbgstream::flush() {
    00324     if (output.isEmpty() || !print)
    00325         return;
    00326     kDebugBackend( level, area, output.local8Bit().data() );
    00327     output = QString::null;
    00328 }
    00329
    00330 kdbgstream &kdbgstream::form(const char *format, ...)
    00331 {
    00332     char buf[4096];
    00333     va_list arguments;
    00334     va_start( arguments, format );
    00335     buf[sizeof(buf)-1] = '\0';
    00336     vsnprintf( buf, sizeof(buf)-1, format, arguments );
    00337     va_end(arguments);
    00338     *this << buf;
    00339     return *this;
    00340 }
    00341
    00342 kdbgstream::~kdbgstream() {
    00343     if (!output.isEmpty()) {
    00344         fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
    00345         *this << "\n";
    00346     }
    00347 }
    00348
    00349 kdbgstream& kdbgstream::operator << (char ch)
    00350 {
    00351   if (!print) return *this;
    00352   if (!isprint(ch))
    00353     output += "\\x" + QString::number( static_cast<uint>( ch ) + 0x100, 16 ).right(2);
    00354   else {
    00355     output += ch;
    00356     if (ch == '\n') flush();
    00357   }
    00358   return *this;
    00359 }
    00360
    00361 kdbgstream& kdbgstream::operator << (QWidget* widget)
    00362 {
    00363   QString string, temp;
    00364   // -----
    00365   if(widget==0)
    00366     {
    00367       string=(QString)"[Null pointer]";
    00368     } else {
    00369       temp.setNum((ulong)widget, 16);
    00370       string=(QString)"["+widget->className()+" pointer "
    00371         + "(0x" + temp + ")";
    00372       if(widget->name(0)==0)
    00373         {
    00374           string += " to unnamed widget, ";
    00375         } else {
    00376           string += (QString)" to widget " + widget->name() + ", ";
    00377         }
    00378       string += "geometry="
    00379         + QString().setNum(widget->width())
    00380         + "x"+QString().setNum(widget->height())
    00381         + "+"+QString().setNum(widget->x())
    00382         + "+"+QString().setNum(widget->y())
    00383         + "]";
    00384     }
    00385   if (!print)
    00386     {
    00387       return *this;
    00388     }
    00389   output += string;
    00390   if (output.at(output.length() -1 ) == '\n')
    00391     {
    00392       flush();
    00393     }
    00394   return *this;
    00395 }
    00396
    00397 QString kdBacktrace(int levels)
    00398 {
    00399     QString s;
    00400 #ifdef HAVE_BACKTRACE
    00401     void* trace[256];
    00402     int n = backtrace(trace, 256);
    00403     char** strings = backtrace_symbols (trace, n);
    00404
    00405     if ( levels != -1 )
    00406         n = QMIN( n, levels );
    00407     s = "[\n";
    00408
    00409     for (int i = 0; i < n; ++i)
    00410         s += QString::number(i) +
    00411              QString::fromLatin1(": ") +
    00412              QString::fromLatin1(strings[i]) + QString::fromLatin1("\n");
    00413     s += "]\n";
    00414     free (strings);
    00415 #endif
    00416     return s;
    00417 }
    00418
    00419 QString kdBacktrace()
    00420 {
    00421     return kdBacktrace(-1 /*all*/);
    00422 }
    00423
    00424 // Needed for --enable-final
    00425 #ifdef NDEBUG
    00426 #define kdDebug kndDebug
    00427 #endif

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:25 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001