Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

odebug.cpp

Go to the documentation of this file.
00001 /*
00002                              This file is part of the Opie Project
00003                              (C) 2003 Michael 'Mickey' Lauer (mickey@tm.informatik.uni-frankfurt.de)
00004                              (C) 2002 Holger Freyther (freyther@kde.org)
00005                              (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
00006               =.
00007             .=l.
00008            .>+-=
00009  _;:,     .>    :=|.         This program is free software; you can
00010 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00011 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00012 .="- .-=="i,     .._         License as published by the Free Software
00013  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00014      ._= =}       :          or (at your option) any later version.
00015     .%`+i>       _;_.
00016     .i_,=:_.      -<s.       This program is distributed in the hope that
00017      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00018     : ..    .:,     . . .    without even the implied warranty of
00019     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00020   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00021 ..}^=.=       =       ;      Library General Public License for more
00022 ++=   -.     .`     .:       details.
00023  :     =  ...= . :.=-
00024  -.   .:....=;==+<;          You should have received a copy of the GNU
00025   -_. . .   )=.  =           Library General Public License along with
00026     --        :-=`           this library; see the file COPYING.LIB.
00027                              If not, write to the Free Software Foundation,
00028                              Inc., 59 Temple Place - Suite 330,
00029                              Boston, MA 02111-1307, USA.
00030 */
00031 
00032 // Include this header without OPIE_NO_DEBUG defined to avoid having the oDebugInfo
00033 // functions inlined to noops (which would then conflict with their definition here).
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 /* OPIE */
00047 
00048 #include <opie2/oapplication.h>
00049 #include <opie2/oglobalsettings.h>
00050 #include <opie2/oconfig.h>
00051 
00052 /* QT */
00053 
00054 #include <qfile.h>
00055 #include <qmessagebox.h>
00056 #include <qsocketdevice.h>
00057 
00058 /* UNIX */
00059 
00060 #include <stdlib.h>     // abort
00061 #include <unistd.h>     // getpid
00062 #include <stdarg.h>     // vararg stuff
00063 #include <ctype.h>      // isprint
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  * debug levels
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  * oDebug private data
00088  *======================================================================================*/
00089 
00090 /*======================================================================================
00091  * the main debug function
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     //qDebug( "oDebugBackend: Level=%d, Area=%d, Data=%s", level, area, data );
00123 
00124     // ML: OPIE doesn't use areacodes at the moment. See the KDE debug classes for an
00125     // ML: example use. I think it's not necessary to implement such a strategy here.
00126     // ML: Comments?
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; // need an application object to use MsgBox
00143     }
00144 
00145     // gcc 2.9x is dumb and sucks... can you hear it?
00146     //QString areaName = (oApp) ? oApp->appName() : "<unknown>";
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     /* something went wrong with the file don't bother.. */
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     /* go to end of file */
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  * odbgstream
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 odbgstream::odbgstream &form(const char *format, ...)
00415 #ifdef __GNUC__
00416       __attribute__ ( ( format ( printf, 2, 3 ) ) )
00417 #endif
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  * either use 'output' directly and do the flush if needed
00511  * or use the QString operator which calls the char* operator
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     // can't use operator<<(str, b.color()) because that terminates a odbgstream (flushes)
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     delete oDebug_data->config;
00638     oDebug_data->config = 0;
00639     */
00640 }
00641 
00642 
00643 #ifdef OPIE_NO_DEBUG
00644 #define odDebug ondDebug
00645 #define odBacktrace ondBacktrace
00646 #endif
00647 
00648 }
00649 }

Generated on Sat Nov 5 16:16:08 2005 for OPIE by  doxygen 1.4.2