00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <opie2/odebug.h>
00036
00037 #if defined(__UCLIBC__)
00038 #define OPIE_NO_BACKTRACE
00039 #endif
00040
00041 #ifdef OPIE_NO_DEBUG
00042 #undef odDebug
00043 #undef odBacktrace
00044 #endif
00045
00046
00047
00048 #include <opie2/oapplication.h>
00049 #include <opie2/oglobalsettings.h>
00050 #include <opie2/oconfig.h>
00051
00052
00053
00054 #include <qfile.h>
00055 #include <qmessagebox.h>
00056 #include <qsocketdevice.h>
00057
00058
00059
00060 #include <stdlib.h>
00061 #include <unistd.h>
00062 #include <stdarg.h>
00063 #include <ctype.h>
00064 #include <syslog.h>
00065 #include <errno.h>
00066 #include <string.h>
00067
00068 #ifndef OPIE_NO_BACKTRACE
00069 #include <execinfo.h>
00070 #endif
00071
00072 namespace Opie {
00073 namespace Core {
00074 namespace Internal {
00075
00076
00077
00078
00079 enum DebugLevels {
00080 ODEBUG_INFO = 0,
00081 ODEBUG_WARN = 1,
00082 ODEBUG_ERROR = 2,
00083 ODEBUG_FATAL = 3
00084 };
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 struct DebugBackend {
00097 DebugBackend() : m_opened( false ), m_file( 0 ) ,m_port( -1 ),m_sock( 0 ) {
00098 m_outp = OGlobalSettings::debugMode();
00099 }
00100 ~DebugBackend() {
00101 delete m_file;
00102 delete m_sock;
00103 }
00104 void debug( unsigned short level, unsigned int, const QString& data );
00105
00106 private:
00107 void debugFile( const QString&, const QString& data );
00108 void debugMsgB( const QString&, const QString& data );
00109 void debugShel( const QString&, const QString& data );
00110 void debugSysl( int, const QString& );
00111 void debugSock( const QString&, const QString& data );
00112 QCString line( const QString&, const QString& data );
00113 bool m_opened : 1;
00114 QFile *m_file;
00115 QHostAddress m_addr;
00116 int m_port;
00117 QSocketDevice *m_sock;
00118 short m_outp;
00119 };
00120
00121 void DebugBackend::debug(unsigned short level, unsigned int, const QString& data) {
00122
00123
00124
00125
00126
00127
00128 int priority = 0;
00129 QString caption;
00130 QString lev;
00131 switch( level )
00132 {
00133 case ODEBUG_INFO: lev = "(Info)"; caption = "Info"; priority = LOG_INFO; break;
00134 case ODEBUG_WARN: lev = "(Warn)"; caption = "Warning"; priority = LOG_WARNING; break;
00135 case ODEBUG_FATAL: lev = "(Fatal)"; caption = "Fatal Error"; priority = LOG_CRIT; break;
00136 default: qDebug( "oDebugBackend: Warning: Unknown debug level! - defaulting to ODEBUG_ERROR." );
00137 case ODEBUG_ERROR: lev = "(Error)"; caption = "Error"; priority = LOG_ERR; break;
00138 }
00139
00140 if (!oApp && (m_outp == 1)) {
00141 qDebug( "oDebugBackend: Warning: no oapplication object - can't use MsgBox" );
00142 m_outp = 2;
00143 }
00144
00145
00146
00147 QString areaName;
00148 if ( oApp ) areaName = oApp->appName();
00149 else areaName = "<unknown>";
00150
00151 switch( m_outp ) {
00152 case ODEBUG_IGNORE:
00153 return;
00154 case ODEBUG_FILE:
00155 return debugFile( areaName, data );
00156 case ODEBUG_MSGBOX:
00157 return debugMsgB( areaName, data );
00158 case ODEBUG_STDERR:
00159 return debugShel( areaName,data );
00160 case ODEBUG_SYSLOG:
00161 return debugSysl( priority, data );
00162 case ODEBUG_SOCKET:
00163 return debugSock( areaName, data );
00164 }
00165 }
00166
00167 inline void DebugBackend::debugFile(const QString& area, const QString& data) {
00168
00169 if ( m_opened && !m_file )
00170 return;
00171 else if ( !m_opened ) {
00172 m_opened = true;
00173 m_file = new QFile( OGlobalSettings::debugOutput() );
00174 if (!m_file->open( IO_WriteOnly | IO_Append ) ) {
00175 delete m_file; m_file = 0;
00176 qDebug( "ODebug: can't write to file '%s' (%s)", (const char*)OGlobalSettings::debugOutput(),
00177 strerror(errno) );
00178 return;
00179 }
00180 }
00181
00182
00183 m_file->at( m_file->size() );
00184 QCString li = line( area, data );
00185 m_file->writeBlock(li.data(), li.length() );
00186 }
00187
00188 void DebugBackend::debugMsgB( const QString& area, const QString& data ) {
00189 QMessageBox::warning( 0l, "("+area+")", data, ("Ok") );
00190 }
00191
00192 void DebugBackend::debugShel( const QString& are, const QString& data ) {
00193 FILE *output = stderr;
00194 fprintf( output, "%s: %s", are.local8Bit().data(),
00195 data.local8Bit().data() );
00196 }
00197
00198 void DebugBackend::debugSysl( int prio, const QString& data ) {
00199 ::syslog( prio, "%s", data.local8Bit().data() );
00200 }
00201
00202 void DebugBackend::debugSock( const QString& are, const QString& data ) {
00203 if ( m_opened && !m_sock )
00204 return;
00205 else if ( !m_opened ){
00206 m_opened = true;
00207 QString destination = OGlobalSettings::debugOutput();
00208 if ( destination && destination.find(":") != -1 ) {
00209 QString host = destination.left( destination.find(":") );
00210 m_port = destination.right( destination.length()-host.length()-1 ).toInt();
00211 m_addr.setAddress( host );
00212 m_sock = new QSocketDevice( QSocketDevice::Datagram );
00213 }else{
00214 m_sock = 0;
00215 return;
00216 }
00217 }
00218
00219 QCString li = line( are, data );
00220 int result = m_sock->writeBlock(li.data(), li.length(), m_addr, m_port );
00221 if ( result == -1 ) {
00222 qDebug( "ODebug: can't send to address '"+ m_addr.toString() +":%d' (%s)",
00223 m_port, strerror(errno) );
00224 }
00225 }
00226
00227 QCString DebugBackend::line( const QString& area, const QString& data ) {
00228 QString str = area +":"+data;
00229 return str.local8Bit();
00230 }
00231
00232 static DebugBackend *backEnd = 0;
00233 }
00234 static void clean_up_routine() {
00235 qWarning( "Clean up Debug" );
00236 delete Internal::backEnd;
00237 Internal::backEnd = 0;
00238 }
00239
00240
00241
00242
00243 odbgstream& perror( odbgstream &s)
00244 {
00245 return s << QString::fromLocal8Bit(strerror(errno));
00246 }
00247
00248 odbgstream odDebug(int area)
00249 {
00250 return odbgstream(area, Internal::ODEBUG_INFO);
00251 }
00252 odbgstream odDebug(bool cond, int area)
00253 {
00254 if (cond) return odbgstream(area, Internal::ODEBUG_INFO);
00255 else return odbgstream(0, 0, false);
00256 }
00257
00258 odbgstream odError(int area)
00259 {
00260 return odbgstream("ERROR: ", area, Internal::ODEBUG_ERROR);
00261 }
00262
00263 odbgstream odError(bool cond, int area)
00264 {
00265 if (cond) return odbgstream("ERROR: ", area, Internal::ODEBUG_ERROR); else return odbgstream(0,0,false);
00266 }
00267
00268 odbgstream odWarning(int area)
00269 {
00270 return odbgstream("WARNING: ", area, Internal::ODEBUG_WARN);
00271 }
00272
00273 odbgstream odWarning(bool cond, int area)
00274 {
00275 if (cond) return odbgstream("WARNING: ", area, Internal::ODEBUG_WARN); else return odbgstream(0,0,false);
00276 }
00277
00278 odbgstream odFatal(int area)
00279 {
00280 return odbgstream("FATAL: ", area, Internal::ODEBUG_FATAL);
00281 }
00282
00283 odbgstream odFatal(bool cond, int area)
00284 {
00285 if (cond) return odbgstream("FATAL: ", area, Internal::ODEBUG_FATAL); else return odbgstream(0,0,false);
00286 }
00287
00288 odbgstream::odbgstream(unsigned int _area, unsigned int _level, bool _print)
00289 :area(_area), level(_level), print(_print)
00290 {
00291 }
00292
00293
00294 odbgstream::odbgstream(const char * initialString, unsigned int _area, unsigned int _level, bool _print)
00295 :output(QString::fromLatin1(initialString)), area(_area), level(_level), print(_print)
00296 {
00297 }
00298
00299
00300 odbgstream::odbgstream(odbgstream &str)
00301 :output(str.output), area(str.area), level(str.level), print(str.print)
00302 {
00303 str.output.truncate(0);
00304 }
00305
00306
00307 odbgstream::odbgstream(const odbgstream &str)
00308 :output(str.output), area(str.area), level(str.level), print(str.print)
00309 {
00310 }
00311
00312 odbgstream& odbgstream::operator<<(bool i)
00313 {
00314 if (!print) return *this;
00315 output += QString::fromLatin1(i ? "true" : "false");
00316 return *this;
00317 }
00318
00319
00320 odbgstream& odbgstream::operator<<(short i)
00321 {
00322 if (!print) return *this;
00323 QString tmp; tmp.setNum(i); output += tmp;
00324 return *this;
00325 }
00326
00327
00328 odbgstream& odbgstream::operator<<(unsigned short i)
00329 {
00330 if (!print) return *this;
00331 QString tmp; tmp.setNum(i); output += tmp;
00332 return *this;
00333 }
00334
00335
00336 odbgstream& odbgstream::operator<<(unsigned char i)
00337 {
00338 return operator<<( static_cast<char>( i ) );
00339 }
00340
00341
00342 odbgstream& odbgstream::operator<<(int i)
00343 {
00344 if (!print) return *this;
00345 QString tmp; tmp.setNum(i); output += tmp;
00346 return *this;
00347 }
00348
00349
00350 odbgstream& odbgstream::operator<<(unsigned int i)
00351 {
00352 if (!print) return *this;
00353 QString tmp; tmp.setNum(i); output += tmp;
00354 return *this;
00355 }
00356
00357
00358 odbgstream& odbgstream::operator<<(long i)
00359 {
00360 if (!print) return *this;
00361 QString tmp; tmp.setNum(i); output += tmp;
00362 return *this;
00363 }
00364
00365
00366 odbgstream& odbgstream::operator<<(unsigned long i)
00367 {
00368 if (!print) return *this;
00369 QString tmp; tmp.setNum(i); output += tmp;
00370 return *this;
00371 }
00372
00373
00374 odbgstream& odbgstream::operator<<(const QString& string)
00375 {
00376 if (!print) return *this;
00377 output += string;
00378 if (output.at(output.length() -1 ) == '\n')
00379 flush();
00380 return *this;
00381 }
00382
00383
00384 odbgstream& odbgstream::operator<<(const char *string)
00385 {
00386 if (!print) return *this;
00387 output += QString::fromUtf8(string);
00388 if (output.at(output.length() - 1) == '\n')
00389 flush();
00390 return *this;
00391 }
00392
00393
00394 odbgstream& odbgstream::operator<<(const QCString& string)
00395 {
00396 *this << string.data();
00397 return *this;
00398 }
00399
00400
00401 odbgstream& odbgstream::operator<<(const void * p)
00402 {
00403 form("%p", p);
00404 return *this;
00405 }
00406
00407 odbgstream& odbgstream::operator<<(double d)
00408 {
00409 QString tmp; tmp.setNum(d); output += tmp;
00410 return *this;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 void odbgstream::flush()
00422 {
00423 if ( output.isEmpty() || !print )
00424 {
00425 return;
00426 }
00427 else
00428 {
00429 if ( !Internal::backEnd ) {
00430 Internal::backEnd = new Internal::DebugBackend;
00431 qAddPostRoutine( clean_up_routine );
00432 }
00433 Internal::backEnd->debug( level, area, output );
00434 output = QString::null;
00435 }
00436 }
00437
00438 odbgstream& odbgstream::form(const char *format, ...)
00439 {
00440 char buf[4096];
00441 va_list arguments;
00442 va_start( arguments, format );
00443 buf[sizeof(buf)-1] = '\0';
00444 vsnprintf( buf, sizeof(buf)-1, format, arguments );
00445 va_end(arguments);
00446 *this << buf;
00447 return *this;
00448 }
00449
00450 odbgstream::~odbgstream()
00451 {
00452 if (!output.isEmpty())
00453 {
00454 fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
00455 *this << "\n";
00456 }
00457 }
00458
00459 odbgstream& odbgstream::operator<<(char ch)
00460 {
00461 if (!print) return *this;
00462 if (!isprint(ch))
00463 {
00464 output += "\\x" + QString::number( static_cast<uint>( ch ) + 0x100, 16 ).right(2);
00465 }
00466 else
00467 {
00468 output += ch;
00469 if (ch == '\n') flush();
00470 }
00471 return *this;
00472 }
00473
00474 odbgstream& odbgstream::operator<<( QWidget* widget )
00475 {
00476 QString string, temp;
00477
00478 if(widget==0)
00479 {
00480 string=(QString)"[Null pointer]";
00481 } else
00482 {
00483 temp.setNum((ulong)widget, 16);
00484 string=(QString)"["+widget->className()+" pointer " + "(0x" + temp + ")";
00485 if(widget->name(0)==0)
00486 {
00487 string += " to unnamed widget, ";
00488 } else
00489 {
00490 string += (QString)" to widget " + widget->name() + ", ";
00491 }
00492 string += "geometry="
00493 + QString().setNum(widget->width())
00494 + "x"+QString().setNum(widget->height())
00495 + "+"+QString().setNum(widget->x())
00496 + "+"+QString().setNum(widget->y())
00497 + "]";
00498 }
00499 if (!print) return *this;
00500
00501 output += string;
00502 if (output.at(output.length()-1) == '\n')
00503 {
00504 flush();
00505 }
00506 return *this;
00507 }
00508
00509
00510
00511
00512
00513
00514 odbgstream& odbgstream::operator<<( const QDateTime& time)
00515 {
00516 *this << time.toString();
00517 return *this;
00518 }
00519
00520
00521 odbgstream& odbgstream::operator<<( const QDate& date)
00522 {
00523 *this << date.toString();
00524
00525 return *this;
00526 }
00527
00528
00529 odbgstream& odbgstream::operator<<( const QTime& time )
00530 {
00531 *this << time.toString();
00532 return *this;
00533 }
00534
00535
00536 odbgstream& odbgstream::operator<<( const QPoint& p )
00537 {
00538 *this << "(" << p.x() << ", " << p.y() << ")";
00539 return *this;
00540 }
00541
00542
00543 odbgstream& odbgstream::operator<<( const QSize& s )
00544 {
00545 *this << "[" << s.width() << "x" << s.height() << "]";
00546 return *this;
00547 }
00548
00549
00550 odbgstream& odbgstream::operator<<( const QRect& r )
00551 {
00552 *this << "[" << r.left() << ", " << r.top() << " - " << r.right() << ", " << r.bottom() << "]";
00553 return *this;
00554 }
00555
00556
00557 odbgstream& odbgstream::operator<<( const QRegion& reg )
00558 {
00559 *this << "[ ";
00560 QArray<QRect>rs=reg.rects();
00561 for (uint i=0;i<rs.size();++i)
00562 *this << QString("[%1, %2 - %3, %4] ").arg(rs[i].left()).arg(rs[i].top()).arg(rs[i].right()).arg(rs[i].bottom() ) ;
00563 *this <<"]";
00564 return *this;
00565 }
00566
00567
00568 odbgstream& odbgstream::operator<<( const QStringList& l )
00569 {
00570 *this << "(";
00571 *this << l.join(",");
00572 *this << ")";
00573
00574 return *this;
00575 }
00576
00577
00578 odbgstream& odbgstream::operator<<( const QColor& c )
00579 {
00580 if ( c.isValid() )
00581 *this << c.name();
00582 else
00583 *this << "(invalid/default)";
00584 return *this;
00585 }
00586
00587
00588 odbgstream& odbgstream::operator<<( const QBrush& b)
00589 {
00590 static const char* const s_brushStyles[] = {
00591 "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern",
00592 "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern",
00593 "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern",
00594 "DiagCrossPattern" };
00595
00596 *this <<"[ style: ";
00597 *this <<s_brushStyles[ b.style() ];
00598 *this <<" color: ";
00599
00600 if ( b.color().isValid() )
00601 *this <<b.color().name() ;
00602 else
00603 *this <<"(invalid/default)";
00604 if ( b.pixmap() )
00605 *this <<" has a pixmap";
00606 *this <<" ]";
00607 return *this;
00608 }
00609
00610
00611
00612 QString odBacktrace( int levels )
00613 {
00614 QString s;
00615 #ifndef OPIE_NO_BACKTRACE
00616 void* trace[256];
00617 int n = backtrace(trace, 256);
00618 char** strings = backtrace_symbols (trace, n);
00619
00620 if ( levels != -1 )
00621 n = QMIN( n, levels );
00622 s = "[\n";
00623
00624 for (int i = 0; i < n; ++i)
00625 s += QString::number(i) +
00626 QString::fromLatin1(": ") +
00627 QString::fromLatin1(strings[i]) + QString::fromLatin1("\n");
00628 s += "]\n";
00629 free (strings);
00630 #endif
00631 return s;
00632 }
00633
00634 void odClearDebugConfig()
00635 {
00636
00637
00638
00639
00640 }
00641
00642
00643 #ifdef OPIE_NO_DEBUG
00644 #define odDebug ondDebug
00645 #define odBacktrace ondBacktrace
00646 #endif
00647
00648 }
00649 }