00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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>
00052
#include <unistd.h>
00053
#include <stdarg.h>
00054
#include <ctype.h>
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
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() )
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;
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
00179
KGlobal::unregisterStaticDeleter(&pcd);
00180
00181
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
00194
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
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
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
00244
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
00264
switch( nOutput )
00265 {
00266
case 0:
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:
00295 {
00296
00297
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:
00304 {
00305 write( 2, buf, nSize );
00306
break;
00307 }
00308
case 3:
00309 {
00310 syslog( nPriority,
"%s", buf);
00311
break;
00312 }
00313 }
00314
00315
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
00412
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 )
00484 {
00485 *
this <<
" capstyle:";
00486 *
this << s_capStyles[ p.
capStyle() >> 4 ];
00487
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
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 );
00541 }
00542
00543 void kdClearDebugConfig()
00544 {
00545
delete kDebug_data->config;
00546 kDebug_data->config = 0;
00547 }
00548
00549
00550
00551
#ifdef NDEBUG
00552
#define kdDebug kndDebug
00553
#endif