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