• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdecore
 

kdecore

  • kdecore
kdebug.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
3  2002 Holger Freyther (freyther@kde.org)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "kdebug.h"
22 
23 #ifdef NDEBUG
24 #undef kdDebug
25 #undef kdBacktrace
26 #endif
27 
28 #include "kdebugdcopiface.h"
29 
30 #include "kapplication.h"
31 #include "kglobal.h"
32 #include "kinstance.h"
33 #include "kstandarddirs.h"
34 
35 #include <tqmessagebox.h>
36 #include <klocale.h>
37 #include <tqfile.h>
38 #include <tqintdict.h>
39 #include <tqstring.h>
40 #include <tqdatetime.h>
41 #include <tqpoint.h>
42 #include <tqrect.h>
43 #include <tqregion.h>
44 #include <tqstringlist.h>
45 #include <tqpen.h>
46 #include <tqbrush.h>
47 #include <tqsize.h>
48 
49 #include <kurl.h>
50 
51 #include <stdlib.h> // abort
52 #include <unistd.h> // getpid
53 #include <stdarg.h> // vararg stuff
54 #include <ctype.h> // isprint
55 #include <syslog.h>
56 #include <errno.h>
57 #include <string.h>
58 #include <kconfig.h>
59 #include "kstaticdeleter.h"
60 #include <config.h>
61 
62 #ifdef HAVE_BACKTRACE
63 #include <execinfo.h>
64 #endif
65 
66 class KDebugEntry;
67 
68 class KDebugEntry
69 {
70 public:
71  KDebugEntry (int n, const TQCString& d) {number=n; descr=d;}
72  unsigned int number;
73  TQCString descr;
74 };
75 
76 static TQIntDict<KDebugEntry> *KDebugCache;
77 
78 static KStaticDeleter< TQIntDict<KDebugEntry> > kdd;
79 
80 static TQCString getDescrFromNum(unsigned int _num)
81 {
82  if (!KDebugCache) {
83  kdd.setObject(KDebugCache, new TQIntDict<KDebugEntry>( 601 ));
84  // Do not call this deleter from ~KApplication
85  KGlobal::unregisterStaticDeleter(&kdd);
86  KDebugCache->setAutoDelete(true);
87  }
88 
89  KDebugEntry *ent = KDebugCache->find( _num );
90  if ( ent )
91  return ent->descr;
92 
93  if ( !KDebugCache->isEmpty() ) // areas already loaded
94  return TQCString();
95 
96  TQString filename(locate("config","kdebug.areas"));
97  if (filename.isEmpty())
98  return TQCString();
99 
100  TQFile file(filename);
101  if (!file.open(IO_ReadOnly)) {
102  qWarning("Couldn't open %s", filename.local8Bit().data());
103  file.close();
104  return TQCString();
105  }
106 
107  uint lineNumber=0;
108  TQCString line(1024);
109  int len;
110 
111  while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
112  int i=0;
113  ++lineNumber;
114 
115  while (line[i] && line[i] <= ' ')
116  i++;
117 
118  unsigned char ch=line[i];
119 
120  if ( !ch || ch =='#' || ch =='\n')
121  continue; // We have an eof, a comment or an empty line
122 
123  if (ch < '0' && ch > '9') {
124  qWarning("Syntax error: no number (line %u)",lineNumber);
125  continue;
126  }
127 
128  const int numStart=i;
129  do {
130  ch=line[++i];
131  } while ( ch >= '0' && ch <= '9');
132 
133  const TQ_ULONG number =line.mid(numStart,i).toULong();
134 
135  while (line[i] && line[i] <= ' ')
136  i++;
137 
138  KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1)));
139  }
140  file.close();
141 
142  ent = KDebugCache->find( _num );
143  if ( ent )
144  return ent->descr;
145 
146  return TQCString();
147 }
148 
149 enum DebugLevels {
150  KDEBUG_INFO= 0,
151  KDEBUG_WARN= 1,
152  KDEBUG_ERROR= 2,
153  KDEBUG_FATAL= 3
154 };
155 
156 
157 struct kDebugPrivate {
158  kDebugPrivate() :
159  oldarea(0), config(0) { }
160 
161  ~kDebugPrivate() { delete config; }
162 
163  TQCString aAreaName;
164  unsigned int oldarea;
165  KConfig *config;
166 };
167 
168 static kDebugPrivate *kDebug_data = 0;
169 static KStaticDeleter<kDebugPrivate> pcd;
170 static KStaticDeleter<KDebugDCOPIface> dcopsd;
171 static KDebugDCOPIface* kDebugDCOPIface = 0;
172 
173 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
174 {
175  if ( !kDebug_data )
176  {
177  pcd.setObject(kDebug_data, new kDebugPrivate());
178  // Do not call this deleter from ~KApplication
179  KGlobal::unregisterStaticDeleter(&pcd);
180 
181  // create the dcop interface if it has not been created yet
182  if (!kDebugDCOPIface)
183  {
184  kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface);
185  }
186  }
187 
188  if (!kDebug_data->config && KGlobal::_instance )
189  {
190  kDebug_data->config = new KConfig("kdebugrc", false, false);
191  kDebug_data->config->setGroup("0");
192 
193  //AB: this is necessary here, otherwise all output with area 0 won't be
194  //prefixed with anything, unless something with area != 0 is called before
195  if ( KGlobal::_instance )
196  kDebug_data->aAreaName = KGlobal::instance()->instanceName();
197  }
198 
199  if (kDebug_data->config && kDebug_data->oldarea != nArea) {
200  kDebug_data->config->setGroup( TQString::number(static_cast<int>(nArea)) );
201  kDebug_data->oldarea = nArea;
202  if ( nArea > 0 && KGlobal::_instance )
203  kDebug_data->aAreaName = getDescrFromNum(nArea);
204  if ((nArea == 0) || kDebug_data->aAreaName.isEmpty())
205  if ( KGlobal::_instance )
206  kDebug_data->aAreaName = KGlobal::instance()->instanceName();
207  }
208 
209  int nPriority = 0;
210  TQString aCaption;
211 
212  /* Determine output */
213 
214  TQString key;
215  switch( nLevel )
216  {
217  case KDEBUG_INFO:
218  key = "InfoOutput";
219  aCaption = "Info";
220  nPriority = LOG_INFO;
221  break;
222  case KDEBUG_WARN:
223  key = "WarnOutput";
224  aCaption = "Warning";
225  nPriority = LOG_WARNING;
226  break;
227  case KDEBUG_FATAL:
228  key = "FatalOutput";
229  aCaption = "Fatal Error";
230  nPriority = LOG_CRIT;
231  break;
232  case KDEBUG_ERROR:
233  default:
234  /* Programmer error, use "Error" as default */
235  key = "ErrorOutput";
236  aCaption = "Error";
237  nPriority = LOG_ERR;
238  break;
239  }
240 
241  // if no output mode is specified default to no debug output
242  short nOutput = kDebug_data->config ? kDebug_data->config->readNumEntry(key, 4) : 4;
243 
244  // If the application doesn't have a TQApplication object it can't use
245  // a messagebox.
246  if (!kapp && (nOutput == 1))
247  nOutput = 2;
248  else if ( nOutput == 4 && nLevel != KDEBUG_FATAL )
249  return;
250 
251  const int BUFSIZE = 4096;
252  char buf[BUFSIZE];
253  if ( !kDebug_data->aAreaName.isEmpty() ) {
254  strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE );
255  strlcat( buf, ": ", BUFSIZE );
256  strlcat( buf, data, BUFSIZE );
257  }
258  else
259  strlcpy( buf, data, BUFSIZE );
260 
261 
262  // Output
263  switch( nOutput )
264  {
265  case 0: // File
266  {
267  const char* aKey;
268  switch( nLevel )
269  {
270  case KDEBUG_INFO:
271  aKey = "InfoFilename";
272  break;
273  case KDEBUG_WARN:
274  aKey = "WarnFilename";
275  break;
276  case KDEBUG_FATAL:
277  aKey = "FatalFilename";
278  break;
279  case KDEBUG_ERROR:
280  default:
281  aKey = "ErrorFilename";
282  break;
283  }
284  TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") );
285  aOutputFile.open( (TQIODevice_OpenModeFlag)((int)IO_WriteOnly | (int)IO_Append | (int)IO_Raw) );
286  aOutputFile.writeBlock( buf, strlen( buf ) );
287  aOutputFile.close();
288  break;
289  }
290  case 1: // Message Box
291  {
292  // Since we are in kdecore here, we cannot use KMsgBox and use
293  // TQMessageBox instead
294  if ( !kDebug_data->aAreaName.isEmpty() )
295  aCaption += TQString("(%1)").arg( QString(kDebug_data->aAreaName) );
296  TQMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
297  break;
298  }
299  case 2: // Shell
300  {
301  write( 2, buf, strlen( buf ) ); //fputs( buf, stderr );
302  break;
303  }
304  case 3: // syslog
305  {
306  syslog( nPriority, "%s", buf);
307  break;
308  }
309  }
310 
311  // check if we should abort
312  if( ( nLevel == KDEBUG_FATAL )
313  && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
314  abort();
315 }
316 
317 kdbgstream &perror( kdbgstream &s) { return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
318 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
319 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
320 
321 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
322 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
323 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
324 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
325 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
326 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
327 
328 kdbgstream::kdbgstream(kdbgstream &str)
329  : output(str.output), area(str.area), level(str.level), print(str.print)
330 {
331  str.output.truncate(0);
332 }
333 
334 void kdbgstream::flush() {
335  if (output.isEmpty() || !print)
336  return;
337  kDebugBackend( level, area, output.local8Bit().data() );
338  output = TQString::null;
339 }
340 
341 kdbgstream &kdbgstream::form(const char *format, ...)
342 {
343  char buf[4096];
344  va_list arguments;
345  va_start( arguments, format );
346  vsnprintf( buf, sizeof(buf), format, arguments );
347  va_end(arguments);
348  *this << buf;
349  return *this;
350 }
351 
352 kdbgstream::~kdbgstream() {
353  if (!output.isEmpty()) {
354  fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
355  TQString backtrace = kdBacktrace();
356  if (backtrace.ascii() != NULL) {
357  fprintf(stderr, "%s", backtrace.latin1());
358  }
359  *this << "\n";
360  }
361 }
362 
363 kdbgstream& kdbgstream::operator << (char ch)
364 {
365  if (!print) return *this;
366  if (!isprint(ch))
367  output += "\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
368  else {
369  output += ch;
370  if (ch == '\n') flush();
371  }
372  return *this;
373 }
374 
375 kdbgstream& kdbgstream::operator << (TQChar ch)
376 {
377  if (!print) return *this;
378  if (!ch.isPrint())
379  output += "\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2, '0');
380  else {
381  output += ch;
382  if (ch == QChar('\n')) flush();
383  }
384  return *this;
385 }
386 
387 kdbgstream& kdbgstream::operator << (TQWidget* widget)
388 {
389  return *this << const_cast< const TQWidget* >( widget );
390 }
391 
392 kdbgstream& kdbgstream::operator << (const TQWidget* widget)
393 {
394  TQString string, temp;
395  // -----
396  if(widget==0)
397  {
398  string=(TQString)"[Null pointer]";
399  } else {
400  temp.setNum((ulong)widget, 16);
401  string=(TQString)"["+widget->className()+" pointer "
402  + "(0x" + temp + ")";
403  if(widget->name(0)==0)
404  {
405  string += " to unnamed widget, ";
406  } else {
407  string += (TQString)" to widget " + widget->name() + ", ";
408  }
409  string += "geometry="
410  + TQString().setNum(widget->width())
411  + "x"+TQString().setNum(widget->height())
412  + "+"+TQString().setNum(widget->x())
413  + "+"+TQString().setNum(widget->y())
414  + "]";
415  }
416  if (!print)
417  {
418  return *this;
419  }
420  output += string;
421  if (output.at(output.length() -1 ) == QChar('\n'))
422  {
423  flush();
424  }
425  return *this;
426 }
427 /*
428  * either use 'output' directly and do the flush if needed
429  * or use the TQString operator which calls the char* operator
430  *
431  */
432 kdbgstream& kdbgstream::operator<<( const TQDateTime& time) {
433  *this << time.toString();
434  return *this;
435 }
436 kdbgstream& kdbgstream::operator<<( const TQDate& date) {
437  *this << TQString(date.toString());
438 
439  return *this;
440 }
441 kdbgstream& kdbgstream::operator<<( const TQTime& time ) {
442  *this << TQString(time.toString());
443  return *this;
444 }
445 kdbgstream& kdbgstream::operator<<( const TQPoint& p ) {
446  *this << "(" << p.x() << ", " << p.y() << ")";
447  return *this;
448 }
449 kdbgstream& kdbgstream::operator<<( const TQSize& s ) {
450  *this << "[" << s.width() << "x" << s.height() << "]";
451  return *this;
452 }
453 kdbgstream& kdbgstream::operator<<( const TQRect& r ) {
454  *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
455  return *this;
456 }
457 kdbgstream& kdbgstream::operator<<( const TQRegion& reg ) {
458  *this<< "[ ";
459 
460  TQMemArray<TQRect>rs=reg.rects();
461  for (uint i=0;i<rs.size();++i)
462  *this << TQString(TQString("[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
463 
464  *this <<"]";
465  return *this;
466 }
467 kdbgstream& kdbgstream::operator<<( const KURL& u ) {
468  *this << u.prettyURL();
469  return *this;
470 }
471 kdbgstream& kdbgstream::operator<<( const TQStringList& l ) {
472  *this << "(";
473  *this << l.join(",");
474  *this << ")";
475 
476  return *this;
477 }
478 kdbgstream& kdbgstream::operator<<( const TQColor& c ) {
479  if ( c.isValid() )
480  *this << TQString(c.name());
481  else
482  *this << "(invalid/default)";
483  return *this;
484 }
485 kdbgstream& kdbgstream::operator<<( const TQPen& p ) {
486  static const char* const s_penStyles[] = {
487  "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
488  "DashDotDotLine" };
489  static const char* const s_capStyles[] = {
490  "FlatCap", "SquareCap", "RoundCap" };
491  *this << "[ style:";
492  *this << s_penStyles[ p.style() ];
493  *this << " width:";
494  *this << p.width();
495  *this << " color:";
496  if ( p.color().isValid() )
497  *this << TQString(p.color().name());
498  else
499  *this <<"(invalid/default)";
500  if ( p.width() > 0 ) // cap style doesn't matter, otherwise
501  {
502  *this << " capstyle:";
503  *this << s_capStyles[ p.capStyle() >> 4 ];
504  // join style omitted
505  }
506  *this <<" ]";
507  return *this;
508 }
509 kdbgstream& kdbgstream::operator<<( const TQBrush& b) {
510  static const char* const s_brushStyles[] = {
511  "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern",
512  "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern",
513  "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern",
514  "DiagCrossPattern" };
515 
516  *this <<"[ style: ";
517  *this <<s_brushStyles[ b.style() ];
518  *this <<" color: ";
519  // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
520  if ( b.color().isValid() )
521  *this << TQString(b.color().name()) ;
522  else
523  *this <<"(invalid/default)";
524  if ( b.pixmap() )
525  *this <<" has a pixmap";
526  *this <<" ]";
527  return *this;
528 }
529 
530 kdbgstream& kdbgstream::operator<<( const TQVariant& v) {
531  *this << "[variant: ";
532  *this << v.typeName();
533  // For now we just attempt a conversion to string.
534  // Feel free to switch(v.type()) and improve the output.
535  *this << " toString=";
536  *this << v.toString();
537  *this << "]";
538  return *this;
539 }
540 
541 kdbgstream& kdbgstream::operator<<( const TQByteArray& data) {
542  if (!print) return *this;
543  output += '[';
544  unsigned int i = 0;
545  unsigned int sz = QMIN( data.size(), 64 );
546  for ( ; i < sz ; ++i ) {
547  output += TQString::number( (unsigned char) data[i], 16 ).rightJustify(2, '0');
548  if ( i < sz )
549  output += ' ';
550  }
551  if ( sz < data.size() )
552  output += "...";
553  output += ']';
554  return *this;
555 }
556 
557 TQString kdBacktrace(int levels)
558 {
559  TQString s;
560 #ifdef HAVE_BACKTRACE
561  void* trace[256];
562  int n = backtrace(trace, 256);
563  if (!n)
564  return s;
565  char** strings = backtrace_symbols (trace, n);
566 
567  if ( levels != -1 )
568  n = QMIN( n, levels );
569  s = "[\n";
570 
571  for (int i = 0; i < n; ++i)
572  s += TQString::number(i) +
573  TQString::fromLatin1(": ") +
574  TQString::fromLatin1(strings[i]) + TQString::fromLatin1("\n");
575  s += "]\n";
576  if (strings)
577  free (strings);
578 #endif
579  return s;
580 }
581 
582 TQString kdBacktrace()
583 {
584  return kdBacktrace(-1 /*all*/);
585 }
586 
587 void kdClearDebugConfig()
588 {
589  if (kDebug_data) {
590  delete kDebug_data->config;
591  kDebug_data->config = 0;
592  }
593 }
594 
595 
596 // Needed for --enable-final
597 #ifdef NDEBUG
598 #define kdDebug kndDebug
599 #endif

kdecore

Skip menu "kdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |