Bug Summary

File:libsynthesis/src/sysync/debuglogger.cpp
Warning:line 1106, column 17
Value stored to 's' is never read

Annotated Source Code

1/*
2 * File: debuglogger.cpp
3 *
4 * Author: Lukas Zeller (luz@plan44.ch)
5 *
6 * Global debug mechanisms
7 *
8 * Copyright (c) 2005-2011 by Synthesis AG + plan44.ch
9 *
10 * 2005-08-04 : luz : created
11 *
12 */
13
14
15#include "prefix_file.h"
16
17#ifdef SYDEBUG2
18
19#include "debuglogger.h"
20
21
22#ifdef MULTI_THREAD_SUPPORT1
23#include "platform_thread.h"
24#endif
25
26#ifdef USE_DLT
27#include <dlt.h>
28#endif
29
30namespace sysync {
31
32#ifdef USE_DLT
33static bool DbgDLTInitialized;
34static DltContext DbgProtoContext;
35static DltContext DbgSessionContext;
36static DltContext DbgAdminContext;
37static DltContext DbgDataContext;
38static DltContext DbgRemoteInfoContext;
39static DltContext DbgParseContext;
40static DltContext DbgGenerateContext;
41static DltContext DbgTranspContext;
42static DltContext DbgSyncMLTKContext;
43static DltContext DbgDefaultContext;
44#endif
45
46
47#ifndef HARDCODED_CONFIG
48
49// debug format modes
50cAppCharP const DbgOutFormatNames[numDbgOutFormats] = {
51 "text", // plain text format (but can be indented)
52 "xml", // XML format
53 "html" // HTML format
54#ifdef USE_DLT
55 // If DLT support is not enabled, then trying to uses it in a config
56 // will lead to a generic parse error. Might be good enough, although
57 // a dedicated error message about "DLT being disabled in this build"
58 // would be nicer.
59 , "dlt" // GENIVI Diagnostic Log and Trace
60#endif
61};
62
63
64// HTML dynamic folding modes
65cAppCharP const DbgFoldingModeNames[numDbgFoldingModes] = {
66 "none", // do not include dynamic folding into HTML logs
67 "collapsed", // include folding - all collapsed by default
68 "expanded", // include folding - all expanded by default
69 "auto" // include folding - collapse/expand state predefined on a block-by-block basis
70};
71
72
73cAppCharP const DbgSourceModeNames[numDbgSourceModes] = {
74 "none", // do not include links into source code in HTML logs
75 "hint", // no links, but info about what file/line number the message comes from
76 "doxygen", // include link into doxygen prepared HTML version of source code
77 "txmt", // include txmt:// link (understood by TextMate and BBEdit) into source code
78};
79
80
81// debug flush modes
82cAppCharP const DbgFlushModeNames[numDbgFlushModes] = {
83 "buffered", // no flush, keep open as long as possible, output buffered (fast, needed for network drives)
84 "flush", // flush every debug message
85 "openclose" // open and close debug channel separately for every message (as in 2.x engine)
86};
87
88// debug subthread isolation modes
89cAppCharP const DbgSubthreadModeNames[numDbgSubthreadModes] = {
90 "none", // do not handle output from subthread specially
91 "suppress", // suppress output from subthreads
92 "separate", // create separate output stream (=file) for each subthread
93 "mix", // mix on a line by line basis
94 "mixblocks" // buffer thread's output and mix block-wise it into main stream when appropriate
95};
96
97#endif
98
99// file extentsions for debug format modes
100cAppCharP const DbgOutFormatExtensions[numDbgOutFormats] = {
101 ".log", // plain text format (but can be indented)
102 ".xml", // XML format
103 ".html" // HTML format
104};
105
106
107cAppCharP const DbgOutDefaultPrefixes[numDbgOutFormats] = {
108 "*** Start of log",
109 "<?xml version=\"1.0\"?>\n"
110 "<sysync_log version=\"1.0\">",
111 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
112 "<html><head><title>SySync SyncML Engine " SYSYNC_FULL_VERSION_STRING"3" "." "4" "." "0" "." "47" " Log</title>\n"
113 "<meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\">\n"
114 "<style type=\"text/css\" media=\"screen\"><!--\n"
115 ".block { color: #0000FF; font-weight: bold; }\n"
116 ".attribute { color: #A5002C; }\n"
117 ".attrval { color: #D80039; font-weight: bold; }\n"
118 ".error { color: red; font-weight: bold; }\n"
119 ".hotalone { color: #000000; font-weight: bold; }\n"
120 ".hot { font-weight: bold; }\n"
121 ".script { color: #996633; }\n" // brownish
122 ".source { color: #3333FF; font-family:courier,monospace; font-size: 90%; font-weight: bold; }\n" // keyword blue
123 ".comment { color: #669933; font-family:courier,monospace; font-size: 90%; font-weight: bold; }\n" // comment green
124 ".skipped { color: #BBBBBB; font-family:courier,monospace; font-size: 90%; font-weight: bold; }\n" // skipped code
125 ".value { color: #FF3300; }\n" // bright orange
126 ".filter { color: #997F66; }\n" // brownish pale
127 ".match { color: #A95E38; }\n" // brownish orange
128 ".dbapi { color: #CC3366; }\n" // dark reddish/pink (pink/violet = database)
129 ".plugin { color: #9151A3; }\n" // dark violet (pink/violet = database)
130 ".incoming { color: #196D00; }\n" // really dark green (green = remote)
131 ".outgoing { color: #002C84; }\n" // really dark blue (blue = local)
132 ".conflict { color: #990000; }\n" // dark red
133 ".remote { color: #709900; }\n" // greenish (green = remote)
134 ".proto { color: #777100; }\n" // dark yellowish/brown
135 ".rest { color: #AAAAAA; }\n" // greyed
136 ".exotic { color: #FF9900; }\n" // mango
137 "a.jump { color: #5D82BA; }\n"
138 "pre { font-size: 90%; }\n"
139 // for folding (always included, as it must be in header)
140 ".exp {\n"
141 " color: #FF0000;\n"
142 " font-weight: bold;\n"
143 " font-size: 90%;\n"
144 " width: 1em;\n"
145 " height: 1em;\n"
146 " display: inline;\n"
147 " border-width: 0.2em;\n"
148 " border-style: solid;\n"
149 " text-align: center;\n"
150 " vertical-align: middle;\n"
151 " padding: 0px 0.2em 0px 0.2em;\n"
152 " margin: 0 4px 2px 0;\n"
153 "}\n"
154 ".coll {\n"
155 " color: #754242;\n"
156 " font-weight: bold;\n"
157 " font-size: 90%;\n"
158 " width: 1em;\n"
159 " height: 1em;\n"
160 " display: inline;\n"
161 " border-width: 0.2em;\n"
162 " border-style: solid;\n"
163 " text-align: center;\n"
164 " vertical-align: middle;\n"
165 " padding: 0px 0.2em 0px 0.2em;\n"
166 " margin: 0 4px 2px 0;\n"
167 "}\n"
168 ".doall { color: #754242; }\n"
169 "--></style>\n"
170 "</head><body><h2>Start of log - SySync SyncML Engine " SYSYNC_FULL_VERSION_STRING"3" "." "4" "." "0" "." "47" "</h2>\n<ul>\n"
171};
172
173cAppCharP const DbgOutDefaultSuffixes[numDbgOutFormats] = {
174 "*** End of log",
175 "</sysync_log>",
176 "</ul><h2>End of log</h2></html>"
177};
178
179
180cAppCharP FoldingPrefix =
181 "<script language=javascript1.2 type=text/javascript><!--\n"
182 "function div_ref_style (id) {\n"
183 " if (document.layers) return document.layers[id];\n"
184 " else if (document.all) return document.all[id].style;\n"
185 " else if (document.getElementById) return document.getElementById(id).style;\n"
186 " else return null;\n"
187 "}\n"
188 "function exp(id) {\n"
189 " if(div_ref_style('B'+id).display!='block') {\n"
190 " div_ref_style('B'+id).display='block';\n"
191 " div_ref_style('E'+id).display='none';\n"
192 " div_ref_style('C'+id).display='inline';\n"
193 " }\n"
194 "}\n"
195 "function coll(id) {\n"
196 " if(div_ref_style('B'+id).display!='none') {\n"
197 " div_ref_style('B'+id).display='none';\n"
198 " div_ref_style('E'+id).display='inline';\n"
199 " div_ref_style('C'+id).display='none';\n"
200 " }\n"
201 "}\n"
202 "function doall(id,collapse) {\n"
203 " // get parent element\n"
204 " if (id=='') {\n"
205 " mydiv=document;\n"
206 " }\n"
207 " else {\n"
208 " mydiv=document.getElementById('B'+id); // get div to collapse or expand\n"
209 " if (collapse) {\n"
210 " coll(id);\n"
211 " }\n"
212 " else {\n"
213 " exp(id);\n"
214 " }\n"
215 " }\n"
216 " // get all contained blocks\n"
217 " divs=mydiv.getElementsByTagName('div') // all divs\n"
218 " for (i=0 ; i<divs.length ; i++) {\n"
219 " if (divs[i].className=='blk') {\n"
220 " // this is a foldable block div\n"
221 " bid = divs[i].id.substring(1);\n"
222 " if (collapse) {\n"
223 " coll(bid);\n"
224 " }\n"
225 " else {\n"
226 " exp(bid);\n"
227 " }\n"
228 " }\n"
229 " }\n"
230 "}\n"
231 "--></script>\n"
232 "<li><span class=\"doall\" onclick=\"doall('',true)\">[-- collapse all --]</span><span class=\"doall\" onclick=\"doall('',false)\">[++ expand all ++]</span></li>\n";
233
234
235// externals
236
237#ifdef CONSOLEINFO
238// privately redefined here to avoid circular headers (would need syncappbase.h)
239extern "C" void ConsolePuts(const char *text);
240#endif
241
242// TDbgOptions implementation
243// --------------------------
244
245TDbgOptions::TDbgOptions()
246{
247 // set defaults
248 clear();
249} // TDbgOptions::TDbgOptions
250
251
252void TDbgOptions::clear(void)
253{
254 fOutputFormat = dbgfmt_html; // most universally readable and convenient
255 fIndentString = " "; // two spaces
256 fCustomPrefix.erase(); // no custom prefix
257 fCustomSuffix.erase(); // no custom suffix
258 fSeparateMsgs = true; // separate text message lines (<msg></msg> in xml)
259 fTimestampStructure = true; // timestamps in structure...
260 fTimestampForAll = false; // ..but not for every line
261 fThreadIDForAll = false; // not by default
262 fFlushMode = dbgflush_none; // no special flush or openclose (fast, but might loose info on process abort)
263 fFoldingMode = dbgfold_auto; // dynamic folding enabled, expanded/collapsed defaults automatically set on block-by-block basis
264 #ifdef SYDEBUG_LOCATION
265 fSourceLinkMode = dbgsource_none; // no links into source code
266 fSourceRootPath = SYDEBUG_LOCATION; // use default path from build
267 #endif
268 fAppend = false; // default to overwrite existing logfiles
269 fSubThreadMode = dbgsubthread_suppress; // simply suppress subthread info
270 fSubThreadBufferMax = 1024*1024; // don't buffer more than one meg.
271} // TDbgOptions::clear
272
273
274
275// TDbgOut implementation
276// ----------------------
277
278TDbgOut::TDbgOut() :
279 fDestructed(false)
280{
281 // init
282 fIsOpen=false;
283} // TDbgOut::TDbgOut
284
285
286TDbgOut::~TDbgOut()
287{
288 destruct();
289} // TDbgOut::~TDbgOut
290
291
292void TDbgOut::destruct(void)
293{
294 if (!fDestructed) doDestruct();
295 fDestructed=true;
296} // TDbgOut::destruct
297
298
299void TDbgOut::doDestruct(void)
300{
301 // make sure files are closed
302 closeDbg();
303} // TDbgOut::doDestruct
304
305
306// TStdFileDbgOut implementation
307// -----------------------------
308
309#ifndef NO_C_FILES
310
311TStdFileDbgOut::TStdFileDbgOut()
312{
313 // init
314 fFileName.erase();
315 fFile=NULL__null;
316 mutex=newMutex();
317} // TStdFileDbgOut::TStdFileDbgOut
318
319
320TStdFileDbgOut::~TStdFileDbgOut()
321{
322 destruct();
323 freeMutex(mutex);
324} // TStdFileDbgOut::~TStdFileDbgOut
325
326
327#ifdef LINUX
328# include <unistd.h>
329# include <fcntl.h>
330#endif
331
332static FILE *FOpen(const char *path, const char *mode)
333{
334 FILE *file = fopen(path, mode);
335#ifdef LINUX
336 // Be careful not to leak this file descriptor into forked
337 // processes.
338 int fd = file ? fileno(file) : -1;
339 if (fd >= 0) {
340 int flags = fcntl(fd, F_GETFD1);
341 if (flags != -1) {
342 fcntl(fd, F_SETFD2, flags | FD_CLOEXEC1);
343 }
344 }
345#endif
346 return file;
347}
348
349// open standard C file based debug output channel
350bool TStdFileDbgOut::openDbg(cAppCharP aDbgOutputName, cAppCharP aSuggestedExtension, TDbgFlushModes aFlushMode, bool aOverWrite, bool aRawMode)
351{
352 if (fIsOpen) {
353 // first close
354 closeDbg();
355 }
356 // now apply new flush mode
357 fFlushMode=aFlushMode;
358 // save new file name
359 fFileName=aDbgOutputName;
360 // for C files, use the extension provided
361 fFileName+=aSuggestedExtension;
362 // open
363 fFile=FOpen(fFileName.c_str(),aRawMode ? (aOverWrite ? "wb" : "ab") : (aOverWrite ? "w" : "a"));
364 // in case this fails, we'll have a NULL fFile. We can't do anything more here
365 fIsOpen=fFile!=NULL__null;
366 // For openclose mode, we have opened here only to check for logfile writability - close again
367 if (fIsOpen && fFlushMode==dbgflush_openclose) {
368 fclose(fFile);
369 fFile=NULL__null;
370 }
371 // return false if we haven't been successful opening the channel
372 return fIsOpen;
373} // TStdFileDbgOut::openDbg
374
375
376// return current size of debug file
377uInt32 TStdFileDbgOut::dbgFileSize(void)
378{
379 if (!fIsOpen) return 0; // no file, no size
380 uInt32 sz;
381 if (fFlushMode==dbgflush_openclose) {
382 // we need to open the file for append first
383 fFile=FOpen(fFileName.c_str(),"a");
384 fseek(fFile,0,SEEK_END2); // move to end (needed, otherwise ftell may return 0 despite "a" fopen mode)
385 sz=ftell(fFile);
386 fclose(fFile);
387 fFile=NULL__null;
388 }
389 else {
390 fseek(fFile,0,SEEK_END2); // move to end (needed, otherwise ftell may return 0 despite "a" fopen mode)
391 sz=ftell(fFile); // return size
392 }
393 return sz;
394} // TStdFileDbgOut::dbgFileSize
395
396
397// close standard C file based debug channel
398void TStdFileDbgOut::closeDbg(void)
399{
400 if (fIsOpen) {
401 if (fFile) {
402 fclose(fFile);
403 fFile=NULL__null;
404 }
405 fIsOpen=false;
406 }
407} // TStdFileDbgOut::closeDbg
408
409
410// write single line to standard file based output channel
411void TStdFileDbgOut::putLine(cAppCharP aLine, bool aForceFlush)
412{
413 // if not open, just NOP
414 if (fIsOpen) {
415 if (fFlushMode==dbgflush_openclose) {
416 // we need to open the file for append first
417 lockMutex(mutex);
418 fFile=FOpen(fFileName.c_str(),"a");
419 if (!fFile)
420 unlockMutex(mutex);
421 }
422 if (fFile) {
423 // now output
424 fputs(aLine,fFile);
425 fputs("\n",fFile);
426
427 // do required flushing
428 if (fFlushMode==dbgflush_openclose) {
429 // we need to close the file after every line of output
430 fclose(fFile);
431 fFile=NULL__null;
432 unlockMutex(mutex);
433 }
434 else if (aForceFlush || fFlushMode==dbgflush_flush) {
435 // simply flush
436 fflush(fFile);
437 }
438 }
439 }
440} // TStdFileDbgOut::putLine
441
442
443// write raw data to output file
444void TStdFileDbgOut::putRawData(cAppPointer aData, memSize aSize)
445{
446 if (fIsOpen) {
447 if (fFlushMode==dbgflush_openclose) {
448 // we need to open the file for append first
449 lockMutex(mutex);
450 fFile=FOpen(fFileName.c_str(),"a");
451 }
452 if (fFile) {
453 if (fwrite(aData, 1, aSize, fFile) != 1) {
454 // error ignored
455 }
456 }
457 // do required flushing
458 if (fFlushMode==dbgflush_openclose) {
459 // we need to close the file after every line of output
460 fclose(fFile);
461 fFile=NULL__null;
462 unlockMutex(mutex);
463 }
464 else if (fFlushMode==dbgflush_flush) {
465 // simply flush
466 fflush(fFile);
467 }
468 }
469} // TStdFileDbgOut::putRawData
470
471
472#endif
473
474
475// TConsoleDbgOut implementation
476// -----------------------------
477
478TConsoleDbgOut::TConsoleDbgOut()
479{
480 // init
481} // TStdFileDbgOut::TStdFileDbgOut
482
483
484// open standard C file based debug output channel
485bool TConsoleDbgOut::openDbg(cAppCharP aDbgOutputName, cAppCharP aSuggestedExtension, TDbgFlushModes aFlushMode, bool aOverWrite, bool aRawMode)
486{
487 if (fIsOpen) {
488 // first close
489 closeDbg();
490 }
491 // raw mode is not supported
492 if (!aRawMode)
493 fIsOpen=true;
494 // return false if we haven't been successful opening the channel
495 return fIsOpen;
496} // TConsoleDbgOut::openDbg
497
498
499// close standard C file based debug channel
500void TConsoleDbgOut::closeDbg(void)
501{
502 fIsOpen=false;
503} // TConsoleDbgOut::closeDbg
504
505
506// write single line to standard file based output channel
507void TConsoleDbgOut::putLine(cAppCharP aLine, bool aForceFlush)
508{
509 // if not open, just NOP
510 if (fIsOpen) {
511 CONSOLEPUTS(aLine)SySync_ConsolePrintf(stderr, "SYSYNC " "%s" "\n", (aLine));
512 }
513} // TConsoleDbgOut::putLine
514
515
516
517
518// TDebugLoggerBase implementation
519// -------------------------------
520
521// constructor
522TDebugLoggerBase::TDebugLoggerBase(GZones *aGZonesP) :
523 fGZonesP(aGZonesP)
524{
525 fDebugMask=0;
526 fDebugEnabled=true; // enabled by default
527 fNextDebugMask=0;
528 fDbgOutP=NULL__null;
529 fDbgOptionsP=NULL__null;
530 fIndent=0;
531 fBlockHistory=NULL__null; // no Block open yet
532 fOutStarted=false; // not yet started
533 fBlockNo=0;
534 fGZonesP=NULL__null;
535 fOutputLoggerP=NULL__null; // no redirected output yet
536} // TDebugLoggerBase::TDebugLoggerBase
537
538
539// destructor
540TDebugLoggerBase::~TDebugLoggerBase()
541{
542 // make sure debug is finalized
543 DebugFinalizeOutput();
544 // make sure possibly left-over history elements are erased
545 while (fBlockHistory) {
546 TBlockLevel *bl=fBlockHistory;
547 fBlockHistory=bl->fNext;
548 delete bl;
549 }
550 // get rid of output object
551 if (fDbgOutP) delete fDbgOutP;
552 fDbgOutP=NULL__null;
553} // TDebugLoggerBase::TDebugLoggerBase
554
555
556// @brief convenience version for getting time
557lineartime_t TDebugLoggerBase::getSystemNowAs(timecontext_t aContext)
558{
559 return sysync::getSystemNowAs(aContext,fGZonesP);
560} // TDebugLoggerBase::getSystemNowAs
561
562
563// install outputter
564void TDebugLoggerBase::installOutput(TDbgOut *aDbgOutP)
565{
566 // get rid of possibly installed previous outputter
567 if (fDbgOutP) delete fDbgOutP;
568 fDbgOutP=aDbgOutP;
569} // TDebugLoggerBase::installOutput
570
571
572/// @brief link this logger to another logger and redirect output to that logger
573/// @param aDebugLoggerP[in] another logger, that must be alive as long as this logger is alive
574void TDebugLoggerBase::outputVia(TDebugLoggerBase *aDebugLoggerP)
575{
576 // save logger and prefix
577 fOutputLoggerP = aDebugLoggerP;
578} // TDebugLoggerBase::outputVia
579
580#if defined(CONSOLEINFO) && defined(CONSOLEINFO_LIBC)
581extern "C" {
582 int (*SySync_ConsolePrintf)(FILE *stream, const char *format, ...) = fprintf;
583}
584#endif
585
586// output formatted text
587void TDebugLoggerBase::DebugVPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, va_list aArgs)
588{
589 // we need a format and debug not completely off
590 if ((getMask() & aDbgMask)==aDbgMask && aFormat) {
591 const sInt16 maxmsglen=1024;
592 char msg[maxmsglen];
593 msg[0]='\0';
594 // assemble the message string
595 vsnprintf(msg, maxmsglen, aFormat, aArgs);
596 // write the string
597 DebugPuts(TDBG_LOCATION_ARG aDbgMask,msg);
598 }
599} // TDebugLoggerBase::DebugVPrintf
600
601
602// helper needed for maintaining old DEBUGPRINTFX() macro syntax
603TDebugLoggerBase &TDebugLoggerBase::setNextMask(uInt32 aDbgMask)
604{
605 fNextDebugMask=aDbgMask;
606 return *this;
607} // TDebugLoggerBase::setNextMask
608
609
610// like DebugPrintf(), but using mask previously set by setNextMask()
611void TDebugLoggerBase::DebugPrintfLastMask(TDBG_LOCATION_PROTO cAppCharP aFormat, ...)
612{
613 va_list args;
614 // we need a format and debug not completely off
615 if ((getMask() & fNextDebugMask)==fNextDebugMask && aFormat) {
616 va_start(args, aFormat)__builtin_va_start(args, aFormat);
617 DebugVPrintf(TDBG_LOCATION_ARG fNextDebugMask,aFormat,args);
618 va_end(args)__builtin_va_end(args);
619 }
620 fNextDebugMask=0;
621} // TDebugLoggerBase::DebugPrintfLastMask
622
623
624// output formatted text
625void TDebugLoggerBase::DebugPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, ...)
626{
627 va_list args;
628 // we need a format and debug not completely off
629 if ((getMask() & aDbgMask)==aDbgMask && aFormat) {
630 va_start(args, aFormat)__builtin_va_start(args, aFormat);
631 DebugVPrintf(TDBG_LOCATION_ARG aDbgMask,aFormat,args);
632 va_end(args)__builtin_va_end(args);
633 }
634} // TDebugLoggerBase::DebugVPrintf
635
636
637// open new Block without attribute list
638void TDebugLoggerBase::DebugOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed)
639{
640 // we need a format and debug not completely off
641 if (getMask() && aBlockName) {
642#ifdef __clang__1
643 #pragma clang diagnostic push
644 #pragma clang diagnostic ignored "-Wformat-security"
645#endif
646 DebugOpenBlock(TDBG_LOCATION_ARG aBlockName,aBlockTitle,aCollapsed,NULL__null);
647#ifdef __clang__1
648 #pragma clang diagnostic pop
649#endif
650 }
651} // TDebugLoggerBase::DebugOpenBlock
652
653
654// open new Block with attribute list, printf style
655void TDebugLoggerBase::DebugOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, ...)
656{
657 va_list args;
658 // we need a format and debug not completely off
659 if (getMask() && aBlockName) {
660 va_start(args, aBlockFmt)__builtin_va_start(args, aBlockFmt);
661 DebugVOpenBlock(TDBG_LOCATION_ARG aBlockName,aBlockTitle,aCollapsed,aBlockFmt,args);
662 va_end(args)__builtin_va_end(args);
663 }
664} // TDebugLoggerBase::DebugOpenBlock
665
666
667// open new Block with attribute list, printf style, expanded by default
668void TDebugLoggerBase::DebugOpenBlockExpanded(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, cAppCharP aBlockFmt, ...)
669{
670 va_list args;
671 // we need a format and debug not completely off
672 if (getMask() && aBlockName) {
673 va_start(args, aBlockFmt)__builtin_va_start(args, aBlockFmt);
674 DebugVOpenBlock(TDBG_LOCATION_ARG aBlockName,aBlockTitle,false,aBlockFmt,args);
675 va_end(args)__builtin_va_end(args);
676 }
677} // TDebugLoggerBase::DebugOpenBlockExpanded
678
679
680// open new Block with attribute list, printf style, collapsed by default
681void TDebugLoggerBase::DebugOpenBlockCollapsed(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, cAppCharP aBlockFmt, ...)
682{
683 va_list args;
684 // we need a format and debug not completely off
685 if (getMask() && aBlockName) {
686 va_start(args, aBlockFmt)__builtin_va_start(args, aBlockFmt);
687 DebugVOpenBlock(TDBG_LOCATION_ARG aBlockName,aBlockTitle,true,aBlockFmt,args);
688 va_end(args)__builtin_va_end(args);
689 }
690} // TDebugLoggerBase::DebugOpenBlockCollapsed
691
692
693#ifdef SYDEBUG_LOCATION
694
695#define MAKEDBGLINK(txt)(txt) dbg2Link(TDBG_LOCATION_ARG txt)
696
697/// turn text into link to source code
698string TDebugLoggerBase::dbg2Link(const TDbgLocation &aTDbgLoc, const string &aTxt)
699{
700 if (!aTDbgLoc.fFile || !fDbgOptionsP || fDbgOptionsP->fSourceLinkMode==dbgsource_none || fDbgOptionsP->fOutputFormat!=dbgfmt_html)
701 return aTxt; // disabled, non-html or no information to create source link
702 // create link or hint to source code
703 string line;
704
705 switch(fDbgOptionsP->fSourceLinkMode) {
706 case dbgsource_hint: {
707 // only add name/line number/function as title hint (in a otherwise inactive link)
708 line = "<a href=\"#\" title=";
709 StringObjPrintf(line,"<a href=\"#\" title=\"%s:%d",aTDbgLoc.fFile,aTDbgLoc.fLine);
710 StringObjAppendPrintf(line," in %s",aTDbgLoc.fFunction);
711 line += '"';
712 goto closelink;
713 }
714 case dbgsource_doxygen: {
715 // create link into doxygen
716 line = "<a href=\"";
717 // replace path with path to Doxygen HTML pages,
718 // mangle base name like Doxygen does
719 line += fDbgOptionsP->fSourceRootPath;
720 line += "/";
721 string file = aTDbgLoc.fFile;
722 size_t off = file.rfind('/');
723 if (off != file.npos)
724 file = file.substr(off + 1);
725 for (off = 0; off < file.size(); off++) {
726 switch(file[off]) {
727 case '_':
728 line+="__";
729 break;
730 case '.':
731 line+="_8";
732 break;
733 default:
734 line+=file[off];
735 break;
736 }
737 }
738 StringObjAppendPrintf(line,"-source.html#l%05d",aTDbgLoc.fLine);
739 line+="\"";
740 if (aTDbgLoc.fFunction) {
741 line+=" title=\"";
742 line+=aTDbgLoc.fFunction;
743 line+="\"";
744 }
745 goto closelink;
746 }
747 case dbgsource_txmt: {
748 // create txmt:// URL scheme link, which opens TextMate or BBEdit at the correct line in MacOS X
749 line = "<a href=\"txmt://open/?url=file://";
750 // - create path
751 string path = fDbgOptionsP->fSourceRootPath;
752 path += aTDbgLoc.fFile;
753 // - add path CGI encoded
754 line += encodeForCGI(path.c_str());
755 // - add line number
756 if (aTDbgLoc.fLine>0)
757 StringObjAppendPrintf(line,"&line=%d",aTDbgLoc.fLine);
758 line+="\"";
759 if (aTDbgLoc.fFunction) {
760 line+=" title=\"";
761 line+=aTDbgLoc.fFunction;
762 line+='"';
763 }
764 }
765 closelink: {
766 line+=">";
767 line+=aTxt;
768 line+="</a>";
769 break;
770 }
771 default:
772 line = aTxt;
773 } // switch
774 // return
775 return line;
776} // TDebugLoggerBase::dbg2Link
777
778#else
779
780#define MAKEDBGLINK(txt)(txt) (txt)
781
782#endif // SYDEBUG_LOCATION
783
784#ifdef USE_DLT
785static void DbgText2PlainText(const char *in, size_t len, std::string &out)
786{
787 const char *q=in;
788 const char *s=q;
789 const char *end=in + len;
790
791 while (q<end) {
792 if (*q=='&') {
793 if (end-q>=6 && strucmp(q,"&html;",6)==0) {
794 if (q>s) out.append(s,q-s);
795 // everything until next &html; must be filtered out
796 // - search next &html;
797 s=q=q+6;
798 while(q+6<=end && strucmp(q,"&html;",6)!=0) q++;
799 s=q=q+6;
800 }
801 else if (end-q>=4 && strucmp(q,"&sp;",4)==0) {
802 if (q>s) out.append(s,q-s);
803 s=q=q+4;
804 out += ' '; // convert to plain space
805 }
806 else
807 q++;
808 }
809 else {
810 q++;
811 }
812 }
813 if (q>s) out.append(s,q-s);
814}
815#endif // USE_DLT
816
817
818// output text to debug channel
819void TDebugLoggerBase::DebugPuts(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aText, stringSize aTextSize, bool aPreFormatted)
820{
821 // we need a text and debug not completely off
822 if (!((getMask() & aDbgMask)==aDbgMask && aText && fDbgOptionsP)) {
823 // cannot output
824 //#ifdef __MWERKS__
825 //#warning "ugly hack"
826 DebugPutLine(TDBG_LOCATION_NONE "<li><span class=\"error\">Warning: Dbg output system already half shut down (limited formatting)!</span></li><li>");
827 if (aText) DebugPutLine(TDBG_LOCATION_NONE aText);
828 DebugPutLine(TDBG_LOCATION_NONE "</li>");
829 //#endif
830 }
831 else {
832 // make sure output is started
833 if (!fOutStarted) {
834 // try starting output
835 DebugStartOutput();
836 // disable debugging in this logger if starting output failed
837 // (prevents endless re-trying to open debug logs e.g. when log directory does not exist)
838 if (!fOutStarted) {
839 fDebugEnabled = false;
840 return; // stop all efforts here
841 }
842 }
843
844#ifdef USE_DLT
845 // DLT logging logs everything in one chunk
846 if (fDbgOptionsP->fOutputFormat == dbgfmt_dlt) {
847 DltContext *context = &DbgDefaultContext;
848 if (aDbgMask & DBG_PROTO0x00000010) {
849 context = &DbgProtoContext;
850 }
851 else if (aDbgMask & DBG_SESSION0x00000020) {
852 context = &DbgSessionContext;
853 }
854 else if (aDbgMask & DBG_ADMIN0x00000040) {
855 context = &DbgAdminContext;
856 }
857 else if (aDbgMask & DBG_DATA0x00000080) {
858 context = &DbgDataContext;
859 }
860 else if (aDbgMask & DBG_REMOTEINFO0x00000100) {
861 context = &DbgRemoteInfoContext;
862 }
863 else if (aDbgMask & DBG_PARSE0x00000200) {
864 context = &DbgParseContext;
865 }
866 else if (aDbgMask & DBG_GEN0x00000400) {
867 context = &DbgGenerateContext;
868 }
869 else if (aDbgMask & DBG_TRANSP0x00002000) {
870 context = &DbgTranspContext;
871 }
872 else if (aDbgMask & (DBG_RTK_SML0x00100000|DBG_RTK_XPT0x00200000)) {
873 context = &DbgSyncMLTKContext;
874 }
875
876 DltLogLevelType level = DLT_LOG_VERBOSE;
877 if (level > DLT_LOG_INFO &&
878 (aDbgMask & DBG_HOT0x00000001)) {
879 level = DLT_LOG_INFO;
880 }
881 if (level > DLT_LOG_ERROR &&
882 (aDbgMask & DBG_ERROR0x00000002)) {
883 level = DLT_LOG_ERROR;
884 }
885 if (level > DLT_LOG_DEBUG &&
886 (aDbgMask & (DBG_USERDATA0x01000000|DBG_PLUGIN0x04000000|DBG_FILTER0x08000000|DBG_CONFLICT0x20000000))) {
887 level = DLT_LOG_DEBUG;
888 }
889 if (level < DLT_LOG_VERBOSE &&
890 (aDbgMask & DBG_DETAILS0x40000000)) {
891 level = (DltLogLevelType)((int)level + 1);
892 }
893 if ((aTextSize > 0 && strlen(aText) > aTextSize) ||
894 strstr(aText, "&html;") ||
895 strstr(aText, "&sp;")) {
896 // Must make a copy and potentially filter out html markup.
897 string buffer;
898 buffer.reserve(aTextSize);
899 DbgText2PlainText(aText, aTextSize ? aTextSize : strlen(aText), buffer);
900 DLT_LOG(*context, level, DLT_STRING(buffer.c_str()));
901 } else {
902 // Fast path: log directly.
903 DLT_LOG(*context, level, DLT_STRING(aText));
904 }
905 return;
906 }
907#endif // USE_DLT
908
909 // dissect into lines
910 cAppCharP end=aTextSize ? aText+aTextSize : NULL__null;
911 bool firstLine=true;
912 // check for preformatted message
913 bool pre=strnncmp(aText,"&pre;",5)==0;
914 if (pre) aText+=5;
915 pre = pre || aPreFormatted;
916 // now process text
917 while ((!end || aText<end) && *aText) {
918 // search for line end or end of string
919 cAppCharP p=aText;
920 while ((!end || p<end) && *p && *p!='\n' && *p!='\r') p++;
921 // output this line, properly formatted
922 string line;
923 line.erase();
924 cAppCharP q,s;
925 string ts;
926 switch (fDbgOptionsP->fOutputFormat) {
927 // HTML
928 case dbgfmt_html:
929 // prefix first line with <li>, second and further with <br/>
930 if (firstLine) {
931 line="<li>";
932 // add timestamp if needed for every line
933 if (
934 fDbgOptionsP->fTimestampForAll
935 || fDbgOptionsP->fThreadIDForAll
936 #ifdef SYDEBUG_LOCATION
937 || fDbgOptionsP->fSourceLinkMode!=dbgsource_none
938 #endif
939 ) {
940 string prefix;
941 prefix = "<i>[";
942 #ifdef MULTI_THREAD_SUPPORT1
943 if (fDbgOptionsP->fThreadIDForAll) {
944 StringObjAppendPrintf(prefix,"%09lu",myThreadID());
945 if (fDbgOptionsP->fTimestampForAll) prefix += ", ";
946 }
947 #endif
948 if (fDbgOptionsP->fTimestampForAll) {
949 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ))));
950 prefix += ts;
951 }
952 #ifdef SYDEBUG_LOCATION
953 else if (!fDbgOptionsP->fThreadIDForAll) {
954 // neither threadID nor timestamp, but source requested -> put small text here
955 prefix += "src";
956 }
957 #endif
958 prefix+="]</i>&nbsp;";
959 // if we have links into source code, add it here
960 line += MAKEDBGLINK(prefix)(prefix);
961 }
962 // colorize some messages
963 string cl="";
964 // colors, not mixable, most relevant first
965 if (aDbgMask & DBG_ERROR0x00000002) {
966 cl="error";
967 }
968 else if (aDbgMask & DBG_EXOTIC0x80000000) {
969 cl="exotic";
970 }
971 else if (aDbgMask & DBG_SCRIPTS0x00001000) {
972 cl="script";
973 }
974 else if (aDbgMask & DBG_PLUGIN0x04000000) {
975 cl="plugin";
976 }
977 else if (aDbgMask & DBG_DBAPI0x02000000) {
978 cl="dbapi";
979 }
980 else if (aDbgMask & DBG_CONFLICT0x20000000) {
981 cl="conflict";
982 }
983 else if (aDbgMask & DBG_MATCH0x10000000) {
984 cl="match";
985 }
986 else if (aDbgMask & DBG_REMOTEINFO0x00000100) {
987 cl="remote";
988 }
989 else if (aDbgMask & DBG_PROTO0x00000010) {
990 cl="proto";
991 }
992 else if (aDbgMask & DBG_FILTER0x08000000) {
993 cl="filter";
994 }
995 else if (aDbgMask & DBG_PARSE0x00000200) {
996 cl="incoming";
997 }
998 else if (aDbgMask & DBG_GEN0x00000400) {
999 cl="outgoing";
1000 }
1001 else if (aDbgMask & DBG_REST0x00008000) {
1002 cl="rest";
1003 }
1004 // apply basic color style
1005 if (!cl.empty()) {
1006 line+="<span class=\""; line+=cl; line+="\">";
1007 }
1008 // aditional style modifiers that can be combined with colors
1009 if (aDbgMask & DBG_HOT0x00000001) {
1010 if (cl.empty())
1011 line+="<span class=\"hotalone\">";
1012 else
1013 line+="<span class=\"hot\">";
1014 }
1015 // start preformatted if selected
1016 if (pre)
1017 line+="<pre>";
1018 }
1019 else {
1020 if (!pre) line="<br/>";
1021 }
1022 goto xmlize;
1023 // XML, just output and replace special chars as needed
1024 case dbgfmt_xml:
1025 if (firstLine) {
1026 #ifdef MULTI_THREAD_SUPPORT1
1027 if (fDbgOptionsP->fThreadIDForAll) {
1028 line+="<thread>";
1029 StringObjAppendPrintf(line,"%09lu",myThreadID());
1030 line+="</thread>";
1031 }
1032 #endif
1033 if (fDbgOptionsP->fTimestampForAll) {
1034 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ))));
1035 line+="<time>";
1036 line+=ts;
1037 line+="</time>";
1038 }
1039 DebugPutLine(TDBG_LOCATION_NONE line.c_str(),line.size());
1040 line.erase();
1041 }
1042 if (fDbgOptionsP->fSeparateMsgs) {
1043 line+="<msg>";
1044 }
1045 xmlize:
1046 q=aText;
1047 s=q;
1048 while (q<p) {
1049 if (*q=='&') {
1050 if (strucmp(q,"&html;",6)==0) {
1051 if (q>s) line.append(s,q-s); // flush stuff scanned so far
1052 // everything until next &html; does not need or want escaping, copy it as is
1053 // - search next &html;
1054 s=q=q+6;
1055 while(*q && strucmp(q,"&html;",6)!=0) q++;
1056 // - append everything between if we are in HTML mode
1057 if (fDbgOptionsP->fOutputFormat==dbgfmt_html && q>s)
1058 line.append(s,q-s);
1059 s=q=q+6;
1060 }
1061 else if (strucmp(q,"&sp;",4)==0) {
1062 if (q>s) line.append(s,q-s); // flush stuff scanned so far
1063 // non-breaking space in HTML, normal space otherwise
1064 if (fDbgOptionsP->fOutputFormat==dbgfmt_html)
1065 line += "&nbsp;";
1066 else
1067 line += ' ';
1068 s=q=q+4; // skip &sp;
1069 }
1070 else {
1071 if (q>s) line.append(s,q-s);
1072 line+="&amp;";
1073 s=++q;
1074 }
1075 }
1076 else if (*q=='<') {
1077 if (q>s) line.append(s,q-s);
1078 line+="&lt;";
1079 s=++q;
1080 }
1081 else if (*q=='>') {
1082 if (q>s) line.append(s,q-s);
1083 line+="&gt;";
1084 s=++q;
1085 }
1086 else {
1087 q++;
1088 }
1089 }
1090 if (q>s) line.append(s,q-s);
1091 if (fDbgOptionsP->fSeparateMsgs && fDbgOptionsP->fOutputFormat==dbgfmt_xml) {
1092 line+="</msg>";
1093 }
1094 break;
1095 // plain text
1096 default:
1097 case dbgfmt_text:
1098 q=aText;
1099 s=q;
1100 while (q<p) {
1101 if (*q=='&') {
1102 if (strucmp(q,"&html;",6)==0) {
1103 if (q>s) line.append(s,q-s);
1104 // everything until next &html; must be filtered out
1105 // - search next &html;
1106 s=q=q+6;
Value stored to 's' is never read
1107 while(*q && strucmp(q,"&html;",6)!=0) q++;
1108 s=q=q+6;
1109 }
1110 else if (strucmp(q,"&sp;",4)==0) {
1111 if (q>s) line.append(s,q-s);
1112 s=q=q+4;
1113 line += ' '; // convert to plain space
1114 }
1115 else
1116 q++;
1117 }
1118 else {
1119 q++;
1120 }
1121 }
1122 if (q>s) line.append(s,q-s);
1123 break;
1124 } // switch text output
1125 firstLine=false;
1126 // skip the lineend, if any
1127 while (((!end || p<end) && *p=='\n') || *p=='\r') p++;
1128 if (fDbgOptionsP->fOutputFormat==dbgfmt_html && ((end && p>=end) || *p==0)) {
1129 // end preformatted
1130 if (pre)
1131 line+="</pre>";
1132 // colors
1133 if (aDbgMask & (
1134 DBG_ERROR0x00000002 |
1135 DBG_SCRIPTS0x00001000 |
1136 DBG_REST0x00008000 |
1137 DBG_EXOTIC0x80000000 |
1138 DBG_DBAPI0x02000000 |
1139 DBG_PLUGIN0x04000000 |
1140 DBG_PARSE0x00000200 |
1141 DBG_GEN0x00000400 |
1142 DBG_CONFLICT0x20000000 |
1143 DBG_MATCH0x10000000 |
1144 DBG_REMOTEINFO0x00000100 |
1145 DBG_PROTO0x00000010 |
1146 DBG_FILTER0x08000000
1147 )) {
1148 line+="</span>"; // end special style
1149 }
1150 // HOT modifier
1151 if (aDbgMask & (
1152 DBG_HOT0x00000001
1153 )) {
1154 line+="</span>"; // end special style
1155 }
1156 line+="</li>"; // we need to close the list entry
1157 }
1158 DebugPutLine(TDBG_LOCATION_NONE line.c_str(),line.size(),pre);
1159 // next line, if any
1160 aText=p;
1161 } // loop until all text done
1162 }
1163} // TDebugLoggerBase::DebugPuts
1164
1165
1166// open new Block with attribute list, varargs passed
1167void TDebugLoggerBase::DebugVOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, va_list aArgs)
1168{
1169 if (!fDbgOptionsP)
1170 return;
1171 if (fDbgOptionsP->fFoldingMode==dbgfold_collapsed)
1172 aCollapsed=true;
1173 else if (fDbgOptionsP->fFoldingMode==dbgfold_expanded)
1174 aCollapsed=false;
1175 if (getMask() && aBlockName && fDbgOptionsP) {
1176 // make sure output is started
1177 if (!fOutStarted) DebugStartOutput();
1178 // create Block line on current indent level
1179 string bl;
1180 string ts;
1181 // - preamble, possibly with timestamp
1182 bool withTime = fDbgOptionsP->fTimestampStructure;
1183 if (withTime)
1184 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ))));
1185 switch (fDbgOptionsP->fOutputFormat) {
1186 // XML
1187 case dbgfmt_xml:
1188 bl="<"; bl+=aBlockName;
1189 if (withTime) {
1190 bl+=" time=\"" + ts + "\"";
1191 }
1192 if (aBlockTitle) {
1193 bl+=" title=\"";
1194 bl+=aBlockTitle;
1195 bl+="\"";
1196 }
1197 break;
1198 // HTML
1199 case dbgfmt_html:
1200 bl="<li><span class=\"block\">";
1201 if (fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1202 StringObjAppendPrintf(bl,
1203 "<div id=\"E%ld\" style=\"display:%s\" class=\"exp\" onclick=\"exp('%ld')\">+</div><div id=\"C%ld\" style=\"display:%s\" class=\"coll\" onclick=\"coll('%ld')\">&ndash;</div>",
1204 long(getBlockNo()), aCollapsed ? "inline" : "none", long(getBlockNo()),
1205 long(getBlockNo()), aCollapsed ? "none" : "inline", long(getBlockNo())
1206 );
1207 }
1208 StringObjAppendPrintf(bl,"<a name=\"H%ld\">", long(getBlockNo()));
1209 if (withTime) {
1210 bl += MAKEDBGLINK(string("[") + ts + "] ")(string("[") + ts + "] ");
1211 }
1212 #ifdef SYDEBUG_LOCATION
1213 else if (fDbgOptionsP->fSourceLinkMode!=dbgsource_none) {
1214 bl += MAKEDBGLINK(string("[src] "))(string("[src] "));
1215 }
1216 #endif
1217 bl+="'";
1218 bl+=aBlockName;
1219 bl+="'";
1220 if (aBlockTitle) {
1221 bl+=" - ";
1222 bl+=aBlockTitle;
1223 }
1224 bl+="</a></span><span class=\"attribute\">";
1225 break;
1226 // plain text
1227 default:
1228 case dbgfmt_text:
1229 bl.erase();
1230 if (!fDbgOptionsP->fTimestampForAll && withTime) { // avoid timestamp here if all lines get timestamped anyway
1231 bl+="[" + ts + "] ";
1232 }
1233 bl+=aBlockName;
1234 if (aBlockTitle) {
1235 bl+=" - ";
1236 bl+=aBlockTitle;
1237 }
1238 break;
1239 } // switch preamble
1240 // - attributes
1241 if (aBlockFmt) {
1242 // first expand all printf parameters
1243 string attrs;
1244 vStringObjPrintf(attrs,aBlockFmt,true,aArgs);
1245 // isolate |-separated attribute format strings
1246 cAppCharP q,r,s,p=attrs.c_str();
1247 while (*p) {
1248 // search for beginning of value
1249 q=p;
1250 while(*q && *q!='=' && *q!='|') q++;
1251 // search for end of value
1252 r=q;
1253 s=q; // in case we don't have a =
1254 if (*q=='=') {
1255 s=q+1;
1256 r=s;
1257 while (*r && *r!='|') r++;
1258 }
1259 // now: p=start of attrname, q=end of attrname
1260 // s=start of value, r=end of value
1261 // output an attribute now
1262 if (q>p && r>s) {
1263 switch (fDbgOptionsP->fOutputFormat) {
1264 // XML
1265 case dbgfmt_xml:
1266 bl+=" ";
1267 bl.append(p,q-p);
1268 bl+="=\"";
1269 bl.append(s,r-s);
1270 bl+="\"";
1271 break;
1272 case dbgfmt_html:
1273 bl+=", ";
1274 bl.append(p,q-p);
1275 bl+="=<span class=\"attrval\">";
1276 bl.append(s,r-s);
1277 bl+="</span>";
1278 break;
1279 case dbgfmt_text:
1280 default:
1281 bl+=", ";
1282 bl.append(p,q-p);
1283 bl+="=";
1284 bl.append(s,r-s);
1285 break;
1286 } // switch attribute
1287 } // non-empty attribute
1288 // more attributes to come?
1289 if (*r=='|') r++; // skip separator
1290 p=r;
1291 } // while
1292 } // attributes present
1293 // - finalize Block
1294 switch (fDbgOptionsP->fOutputFormat) {
1295 // XML
1296 case dbgfmt_xml:
1297 bl+=">";
1298 break;
1299 // HTML
1300 case dbgfmt_html:
1301 bl+="</span>"; // end span for attributes
1302 if (fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1303 StringObjAppendPrintf(bl,
1304 "&nbsp;<span class=\"doall\" onclick=\"doall('%ld',true)\">[--]</span><span class=\"doall\" onclick=\"doall('%ld',false)\">[++]</span>",
1305 long(getBlockNo()), long(getBlockNo())
1306 );
1307 }
1308 // link to end of block
1309 StringObjAppendPrintf(bl,"&nbsp;<a class=\"jump\" href=\"#F%ld\">[->end]</a>", long(getBlockNo()));
1310 // link to start of enclosing block (if any)
1311 if (fBlockHistory) {
1312 StringObjAppendPrintf(bl,"&nbsp;<a class=\"jump\" href=\"#H%ld\">[->enclosing]</a>", long(fBlockHistory->fBlockNo));
1313 }
1314 // start div for content folding
1315 if (fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1316 StringObjAppendPrintf(bl,
1317 "<div class=\"blk\" id=\"B%ld\" style=\"display:%s\">",
1318 long(getBlockNo()),
1319 aCollapsed ? "none" : "inline"
1320 );
1321 }
1322 bl+="<ul>"; // now start list for block's contents
1323 break;
1324 // plain text
1325 default:
1326 case dbgfmt_text:
1327 break;
1328 } // switch preamble
1329 // now output Block line (on current indent level)
1330 DebugPutLine(TDBG_LOCATION_NONE bl.c_str(), bl.size());
1331 // increase indent level (applies to all Block contents)
1332 fIndent++;
1333 // save Block on stack
1334 TBlockLevel *newLevel = new TBlockLevel;
1335 newLevel->fBlockName=aBlockName;
1336 newLevel->fNext=fBlockHistory;
1337 newLevel->fBlockNo=getBlockNo(); // save block number to reference block in collapse box at end of block
1338 nextBlock(); // increment block number
1339 fBlockHistory=newLevel; // insert new level at start of list
1340 }
1341} // TDebugLoggerBase::DebugVOpenBlock
1342
1343
1344// close named Block. If no name given, topmost Block will be closed
1345void TDebugLoggerBase::DebugCloseBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName)
1346{
1347 if (fOutStarted && getMask() && fDbgOptionsP && fBlockHistory) {
1348 if (aBlockName==NULL__null) {
1349 #if SYDEBUG2>1
1350 internalCloseBlocks(TDBG_LOCATION_ARG fBlockHistory->fBlockName.c_str(),"Block Nest Warning: Missing Block name at close");
1351 #else
1352 internalCloseBlocks(TDBG_LOCATION_ARG fBlockHistory->fBlockName.c_str(),NULL__null);
1353 #endif
1354 }
1355 else {
1356 internalCloseBlocks(TDBG_LOCATION_ARG aBlockName,NULL__null);
1357 }
1358 }
1359} // TDebugLoggerBase::DebugCloseBlock
1360
1361
1362
1363// internal helper used to close all or some Blocks
1364void TDebugLoggerBase::internalCloseBlocks(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aCloseComment)
1365{
1366 if (!fDbgOptionsP) return; // security
1367 bool withTime = fDbgOptionsP->fTimestampStructure;
1368 string comment;
1369 #if SYDEBUG2>1
1370 if (!fBlockHistory && aBlockName) {
1371 // no blocks open any more and not close-all-remaining call (log close...)
1372 DebugPrintf(TDBG_LOCATION_ARG DBG_EXOTIC0x80000000+DBG_ERROR0x00000002,"Block Nest Warning: Trying to close block '%s', but no block is open",aBlockName);
1373 }
1374 #endif
1375 while (fBlockHistory) {
1376 // prepare comment
1377 comment.erase();
1378 if (aCloseComment) {
1379 comment += " - ";
1380 comment += aCloseComment;
1381 }
1382 // check if closing top-of-stack Block now
1383 bool found=
1384 (aBlockName && strucmp(aBlockName,fBlockHistory->fBlockName.c_str())==0);
1385 if (!found && fBlockHistory->fNext==NULL__null) {
1386 // last Block always counts as "found"...
1387 found = true;
1388 #if SYDEBUG2>1
1389 // ...but issue warning as name is not what we would have expected
1390 StringObjAppendPrintf(comment, " - Block Nest Warning: closing '%s', but expected '%s'",aBlockName ? aBlockName : "<unknown>", fBlockHistory->fBlockName.c_str());
1391 #endif
1392 }
1393 // now close topmost Block
1394 string ts,bl;
1395 // - get time if needed and possibly put it within indented block
1396 if (withTime) {
1397 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ))));
1398 // for XML, the time must be shown before the close tag on a separate line
1399 if (fDbgOptionsP->fOutputFormat == dbgfmt_xml) {
1400 StringObjPrintf(bl,"<endblock time=\"%s\"/>",ts.c_str());
1401 DebugPutLine(TDBG_LOCATION_NONE bl.c_str(), bl.size()); // still within block, indented
1402 }
1403 }
1404 // - now unindent
1405 if (fIndent>0) fIndent--;
1406 // - then create closing Block
1407 #if SYDEBUG2>1
1408 if (!found) StringObjAppendPrintf(comment," - Block Nest Warning: implicitly closed (by explicitly closing '%s')",aBlockName ? aBlockName : "<unknown parent>");
1409 #endif
1410 switch (fDbgOptionsP->fOutputFormat) {
1411 // XML
1412 case dbgfmt_xml:
1413 bl="</";
1414 bl+=fBlockHistory->fBlockName;
1415 bl+=">";
1416 if (!comment.empty()) {
1417 bl+=" <!-- ";
1418 bl+=comment;
1419 bl+=" -->";
1420 }
1421 break;
1422 // HTML
1423 case dbgfmt_html:
1424 bl="</ul><span class=\"block\">"; // end of content list
1425 if (fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1426 StringObjAppendPrintf(bl,
1427 "<span class=\"coll\" onclick=\"coll('%ld')\">&ndash;</span>",
1428 long(fBlockHistory->fBlockNo)
1429 );
1430 }
1431 StringObjAppendPrintf(bl,"<a name=\"F%ld\">",long(fBlockHistory->fBlockNo));
1432 if (withTime) {
1433 bl += MAKEDBGLINK(string("[") + ts + "] ")(string("[") + ts + "] ");
1434 }
1435 bl += "End of '";
1436 bl+=fBlockHistory->fBlockName;
1437 bl+="'";
1438 bl+=comment;
1439 bl+="</a></span>";
1440 // link to top of block
1441 StringObjAppendPrintf(bl,"&nbsp;<a class=\"jump\" href=\"#H%ld\">[->top]</a>",long(fBlockHistory->fBlockNo));
1442 // link to end of enclosing block (if any)
1443 if (fBlockHistory->fNext) {
1444 StringObjAppendPrintf(bl,"&nbsp;<a class=\"jump\" href=\"#F%ld\">[->enclosing]</a>",long(fBlockHistory->fNext->fBlockNo));
1445 }
1446 if (fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1447 bl+="</div>"; // end of folding division
1448 }
1449 bl+="</li>"; // end of list entry containing entire block
1450 break;
1451 // plain text
1452 default:
1453 case dbgfmt_text:
1454 bl.erase();
1455 if (!fDbgOptionsP->fTimestampForAll && withTime) { // avoid timestamp here if all lines get timestamped anyway
1456 bl+="[" + ts + "] ";
1457 }
1458 bl+="End of '";
1459 bl+=fBlockHistory->fBlockName;
1460 bl+="'";
1461 bl+=comment;
1462 break;
1463 } // switch Block close
1464 // - output closing Block line
1465 DebugPutLine(TDBG_LOCATION_NONE bl.c_str(), bl.size());
1466 // - remove Block level
1467 TBlockLevel *closedLevel = fBlockHistory;
1468 fBlockHistory = closedLevel->fNext;
1469 delete closedLevel;
1470 // if we have found the Block, exit here
1471 if (found) break;
1472 }
1473} // TDebugLoggerBase::internalCloseBlocks
1474
1475#ifdef USE_DLT
1476static void RegisterContext(DltContext *aHandle, const char *aContextID, const char *aDescription)
1477{
1478 std::string envName = "LIBSYNTHESIS_";
1479 envName += aContextID;
1480 const char *value = getenv(envName.c_str());
1481 if (value) {
1482 // Explicit level.
1483 DltLogLevelType level = (DltLogLevelType)atoi(value);
1484 dlt_register_context_ll_ts(aHandle, aContextID, aDescription, level, DLT_TRACE_STATUS_OFF);
1485 } else {
1486 // Default level.
1487 dlt_register_context(aHandle, aContextID, aDescription);
1488 }
1489}
1490#endif // USE_DLT
1491
1492// start debugging output if needed and sets fOutStarted
1493bool TDebugLoggerBase::DebugStartOutput(void)
1494{
1495 if (!fOutStarted) {
1496#ifdef USE_DLT
1497 if (fDbgOptionsP && fDbgOptionsP->fOutputFormat==dbgfmt_dlt) {
1498 // Register our logging contexts.
1499 if (!DbgDLTInitialized) {
1500 RegisterContext(&DbgProtoContext, "PROT", "SyncML protocol related information");
1501 RegisterContext(&DbgSessionContext, "SESS", "session management related information");
1502 RegisterContext(&DbgAdminContext, "ADMN", "verything that has to do with administrative data (anchors, targets, map table)");
1503 RegisterContext(&DbgDataContext, "DATA", "Everything that has to do with handling user data (data objects). Actual user data will however be shown only if loglevel >= debug.");
1504 RegisterContext(&DbgRemoteInfoContext, "REMI", "This shows information delivered in the remote party's device information, such as manufacturer name, datatypes supported, fields supported etc.");
1505 RegisterContext(&DbgParseContext, "PARS", "This shows information related to parsing and processing incoming data from the remote party. Actual user data will however be shown only if loglevel >= debug.");
1506 RegisterContext(&DbgGenerateContext, "GEN", "This shows information related to generating outgoing data for the remote party. Actual user data will however be shown only if loglevel >= debug.");
1507 RegisterContext(&DbgTranspContext, "TRNS", "shows transport (http and TCP communication) related information");
1508 RegisterContext(&DbgSyncMLTKContext, "SMLT", "messages generated by the SyncML Toolkit code");
1509 RegisterContext(&DbgDefaultContext, "SYS", "any other libsynthesis debug log message that does not fit in any of the other contexts");
1510 DbgDLTInitialized = true;
1511 }
1512 fOutStarted = true;
1513 }
1514 else
1515#endif // USE_DLT
1516 if (fOutputLoggerP) {
1517 // using another logger, call it to start output
1518 fOutStarted = fOutputLoggerP->DebugStartOutput();
1519 if (fOutStarted) {
1520 // start with indent level of parent logger
1521 fIndent = fOutputLoggerP->fIndent;
1522 // note: we'll use the parent logger's block number...
1523 fBlockNo = 0; // ...but init to something just in case
1524 }
1525 }
1526 else if (fDbgOptionsP && fDbgOutP && !fDbgPath.empty()) {
1527 // try to open the debug channel (force to openclose if we have multiple threads mixed in one file)
1528 if (fDbgOutP->openDbg(
1529 fDbgPath.c_str(),
1530 DbgOutFormatExtensions[fDbgOptionsP->fOutputFormat],
1531 fDbgOptionsP->fSubThreadMode==dbgsubthread_linemix ? dbgflush_openclose : fDbgOptionsP->fFlushMode,
1532 !fDbgOptionsP->fAppend
1533 )) {
1534 // make sure we don't recurse when we produce some output
1535 fOutStarted = true;
1536 fIndent = 0; // reset to make sure
1537 // create a block number that is unique in the file, even if we append multiple times.
1538 // We assume that a block consumes at least 256 bytes, so size_of_file/256 always gets
1539 // an unused block ID within that file
1540 // 256 is a safe assumption because the "fold" button <divs> alone are around 250 bytes
1541 fBlockNo = 1 + (fDbgOutP->dbgFileSize()/256);
1542 // now create required prefix
1543 DebugPutLine(TDBG_LOCATION_NONE fDbgOptionsP->fCustomPrefix.empty() ? DbgOutDefaultPrefixes[fDbgOptionsP->fOutputFormat] : fDbgOptionsP->fCustomPrefix.c_str());
1544 // add folding javascript if needed
1545 if (fDbgOptionsP->fOutputFormat==dbgfmt_html && fDbgOptionsP->fFoldingMode!=dbgfold_none) {
1546 DebugPutLine(TDBG_LOCATION_NONE FoldingPrefix);
1547 }
1548 } // debug channel opened successfully
1549 } // use own debug channel
1550 } // environment ready to start output
1551 return fOutStarted;
1552} // TDebugLoggerBase::DebugStartOutput
1553
1554
1555// @brief finalize debugging output (close Blocks, close output channel)
1556void TDebugLoggerBase::DebugFinalizeOutput(void)
1557{
1558 if (fOutputLoggerP) {
1559 // just close my own blocks
1560 internalCloseBlocks(TDBG_LOCATION_NONE NULL__null,"closed because sub-log ends here");
1561 }
1562 if (fOutStarted && fDbgOptionsP && fDbgOutP) {
1563 // close all left-open open Blocks
1564 internalCloseBlocks(TDBG_LOCATION_NONE NULL__null,"closed because log ends here");
1565 // now finalize output
1566 // - special stuff before
1567 if (fDbgOptionsP->fOutputFormat == dbgfmt_xml)
1568 fIndent=0; // unindent to zero (document is not a real Block)
1569 // - then suffix
1570 DebugPutLine(TDBG_LOCATION_NONE fDbgOptionsP->fCustomSuffix.empty() ? DbgOutDefaultSuffixes[fDbgOptionsP->fOutputFormat] : fDbgOptionsP->fCustomSuffix.c_str());
1571 // now close the debug channel
1572 fDbgOutP->closeDbg();
1573 }
1574 // whatever happened, we are not started any more
1575 fOutStarted=false;
1576} // TDebugLoggerBase::DebugFinalizeOutput
1577
1578
1579// Output single line to debug channel (includes indenting and other prefixing, but no further formatting)
1580void TDebugLoggerBase::DebugPutLine(TDBG_LOCATION_PROTO cAppCharP aText, stringSize aTextSize, bool aPre)
1581{
1582#ifdef USE_DLT
1583 if (fDbgOptionsP && fDbgOptionsP->fOutputFormat==dbgfmt_dlt) {
1584 // One example where this gets called is DebugVOpen/CloseBlock()
1585 // with lines prepared as if we are printing plain text. Use
1586 // a fairly neutral log level here.
1587 if (aText) {
1588 if (aTextSize > 0 && aTextSize < strlen(aText)) {
1589 string buffer(aText, aTextSize);
1590 DLT_LOG(DbgDefaultContext, DLT_LOG_INFO, DLT_STRING(buffer.c_str()));
1591 } else {
1592 DLT_LOG(DbgDefaultContext, DLT_LOG_INFO, DLT_STRING(aText));
1593 }
1594 }
1595 return;
1596 }
1597#endif // USE_DLT
1598
1599 if (!aText || (!fDbgOutP && !fOutputLoggerP)) return;
1600 if (*aText) {
1601 // not an empty line
1602 string msg;
1603 msg.erase();
1604 // prefix with timestamp if selected in text format
1605 if (fDbgOptionsP && fDbgOptionsP->fOutputFormat==dbgfmt_text && fDbgOptionsP->fTimestampForAll) {
1606 // prefix each line (before the indent!) with a timestamp
1607 string ts;
1608 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ))));
1609 msg='[';
1610 msg+=ts;
1611 msg+="] ";
1612 }
1613 // Indent if selected
1614 if (fDbgOptionsP && !fDbgOptionsP->fIndentString.empty() && !(fDbgOptionsP->fOutputFormat==dbgfmt_html && aPre)) {
1615 // with indent
1616 for (uInt16 n=0; n<fIndent; n++) {
1617 msg+=fDbgOptionsP->fIndentString;
1618 }
1619 }
1620 // add message itself
1621 if (aTextSize)
1622 msg.append(aText,aTextSize);
1623 else
1624 msg.append(aText);
1625 // now output
1626 if (fOutputLoggerP) {
1627 // use parent's output
1628 fOutputLoggerP->fDbgOutP->putLine(msg.c_str(),false); // %%% no forceflush for now
1629 }
1630 else {
1631 // use my own output channel
1632 fDbgOutP->putLine(msg.c_str(),false); // %%% no forceflush for now
1633 }
1634 }
1635} // TDebugLoggerBase::DebugPutLine
1636
1637
1638// TDebugLogger implementation
1639// ---------------------------
1640
1641// constructor
1642TDebugLogger::TDebugLogger(GZones *aGZonesP) :
1643 inherited(aGZonesP)
1644{
1645 #ifdef MULTI_THREAD_SUPPORT1
1646 fMainThreadID=0;
1647 fSubThreadLogs=NULL__null;
1648 fSilentLoggerP=NULL__null;
1649 #endif
1650} // TDebugLogger::TDebugLogger
1651
1652
1653// destructor
1654TDebugLogger::~TDebugLogger()
1655{
1656 #ifdef MULTI_THREAD_SUPPORT1
1657 // remove subthread loggers
1658 TSubThreadLog* subThreadP = fSubThreadLogs;
1659 fSubThreadLogs = NULL__null;
1660 while (subThreadP) {
1661 // delete logger if any
1662 if (subThreadP->fSubThreadLogger) {
1663 SYSYNC_TRYtry {
1664 delete subThreadP->fSubThreadLogger;
1665 }
1666 SYSYNC_CATCH(...)catch(...) {
1667 // nop
1668 SYSYNC_ENDCATCH}
1669 }
1670 TSubThreadLog* delP = subThreadP;
1671 subThreadP = subThreadP->fNext;
1672 delete delP;
1673 }
1674 //
1675 if (fSilentLoggerP) {
1676 delete fSilentLoggerP;
1677 fSilentLoggerP = NULL__null;
1678 }
1679 #endif
1680} // TDebugLogger::~TDebugLogger
1681
1682
1683#ifdef MULTI_THREAD_SUPPORT1
1684
1685void TDebugLogger::setOptions(const TDbgOptions *aDbgOptionsP)
1686{
1687 TDebugLoggerBase::setOptions(aDbgOptionsP);
1688 TSubThreadLog* subThreadP = fSubThreadLogs;
1689 while (subThreadP) {
1690 if (subThreadP->fSubThreadLogger) {
1691 subThreadP->fSubThreadLogger->setOptions(aDbgOptionsP);
1692 }
1693 subThreadP = subThreadP->fNext;
1694 }
1695}
1696
1697/// @brief find (and possibly delete) subthread record
1698/// @param aAndRemove[in] if set, the subthread record will be removed in a thread safe way
1699/// IF AND ONLY IF aThreadID is the calling thread (i.e. only own thread may be removed from the list)!
1700/// Note that the caller must take care of deleting the subthread record
1701TSubThreadLog *TDebugLogger::findSubThread(uInt32 aThreadID, bool aAndRemove)
1702{
1703 TSubThreadLog* subThreadP = fSubThreadLogs;
1704 TSubThreadLog** subThreadLinkPP = &fSubThreadLogs;
1705 while (subThreadP) {
1706 if (subThreadP->fThreadID == aThreadID) {
1707 if (aAndRemove) {
1708 // bridge previous with next in one single assignment (i.e. thread safe)
1709 *subThreadLinkPP = subThreadP->fNext;
1710 }
1711 // return found record (note that it MUST BE DELETED by caller if no longer used)
1712 return subThreadP;
1713 }
1714 subThreadLinkPP = &subThreadP->fNext;
1715 subThreadP = *subThreadLinkPP;
1716 }
1717 return NULL__null; // none found
1718} // TDebugLogger::findSubThread
1719
1720
1721/// @brief find or create logger for subthread
1722TDebugLoggerBase *TDebugLogger::getThreadLogger(bool aCreateNew)
1723{
1724 if (fOutputLoggerP) {
1725 TDebugLoggerBase *logger = fOutputLoggerP->getThreadLogger(aCreateNew);
1726 if (logger)
1727 return logger;
1728 }
1729
1730 if (!fDbgOptionsP || fDbgOptionsP->fSubThreadMode==dbgsubthread_none)
1731 return this; // no options, do not handle subthreads specially
1732 uIntArch threadID = myThreadID();
1733 if (fDbgOptionsP->fSubThreadMode==dbgsubthread_linemix || threadID==fMainThreadID) {
1734 // In line mix and for mainthread - I am the logger for this thread!
1735 return this;
1736 }
1737 TSubThreadLog* subThreadP = findSubThread(threadID);
1738 if (subThreadP) {
1739 // we know this subthread, return its logger
1740 return subThreadP->fSubThreadLogger; // can be NULL if subthread logging is disabled
1741 }
1742 // unknown subthread
1743 if (fMainThreadID==0) {
1744 // no current mainthread, let subthread write to main log
1745 // Note: this makes sure log info possibly trailing the DebugThreadOutputDone()
1746 // also lands in the main log. This is not critical - the only thing that must be
1747 // ensured is that starting new threads is made only with DebugDefineMainThread set.
1748 return this;
1749 }
1750 // new subthread, create entry in list
1751 if (aCreateNew) {
1752 string s;
1753 // create new entry
1754 subThreadP = new TSubThreadLog;
1755 subThreadP->fThreadID=threadID;
1756 subThreadP->fNext=fSubThreadLogs; // link current list behind this new entry
1757 // create logger for the thread (or none)
1758 switch (fDbgOptionsP->fSubThreadMode) {
1759 case dbgsubthread_separate:
1760 // separate file for subthread output
1761 // - create new base logger
1762 subThreadP->fSubThreadLogger = new TDebugLoggerBase(fGZonesP);
1763 // - install output (copy)
1764 subThreadP->fSubThreadLogger->installOutput(fDbgOutP ? fDbgOutP->clone() : NULL__null);
1765 // - same options
1766 subThreadP->fSubThreadLogger->setOptions(getOptions());
1767 // - inherit current mask/enable
1768 subThreadP->fSubThreadLogger->setMask(getMask());
1769 subThreadP->fSubThreadLogger->setEnabled(fDebugEnabled);
1770 // - debug path is same as myself plus Thread ID
1771 subThreadP->fSubThreadLogger->setDebugPath(fDbgPath.c_str());
1772 StringObjPrintf(s,"_%lu",(long unsigned)threadID);
1773 subThreadP->fSubThreadLogger->appendToDebugPath(s.c_str());
1774 break;
1775 case dbgsubthread_suppress:
1776 default:
1777 // no output from subthreads
1778 subThreadP->fSubThreadLogger=NULL__null; // no logger
1779 break;
1780 }
1781 // now activate by linking it at top of list (this is thread safe)
1782 fSubThreadLogs = subThreadP;
1783 // return the logger
1784 return subThreadP->fSubThreadLogger;
1785 }
1786 return NULL__null; // no logger for this thread
1787} // TDebugLogger::getThreadLogger
1788
1789
1790// helper needed for maintaining old DEBUGPRINTFX() macro syntax
1791TDebugLoggerBase &TDebugLogger::setNextMask(uInt32 aDbgMask)
1792{
1793 TDebugLoggerBase *loggerP = getThreadLogger();
1794 if (loggerP) {
1795 // return pointer to loggerbase whose DebugPrintfLastMask() must be called
1796 return loggerP->inherited::setNextMask(aDbgMask);
1797 }
1798 else {
1799 // we have no logger but still need to return something
1800 if (!fSilentLoggerP) {
1801 fSilentLoggerP = new TDebugLoggerBase(fGZonesP);
1802 fSilentLoggerP->setEnabled(false);
1803 }
1804 fSilentLoggerP->setNextMask(DBG_ERROR0x00000002); // must set non-zero to make sure it is NOT output!
1805 return *fSilentLoggerP;
1806 }
1807} // TDebugLoggerBase::setNextMask
1808
1809
1810// output text to debug channel, with checking for subthreads
1811void TDebugLogger::DebugPuts(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aText, stringSize aTextSize, bool aPreFormatted)
1812{
1813 TDebugLoggerBase *loggerP = getThreadLogger();
1814 if (loggerP) loggerP->inherited::DebugPuts(TDBG_LOCATION_ARG aDbgMask,aText,aTextSize,aPreFormatted);
1815} // TDebugLogger::DebugPuts
1816
1817
1818void TDebugLogger::DebugVPrintf(TDBG_LOCATION_PROTO uInt32 aDbgMask, cAppCharP aFormat, va_list aArgs)
1819{
1820 TDebugLoggerBase *loggerP = getThreadLogger();
1821 if (loggerP) loggerP->inherited::DebugVPrintf(TDBG_LOCATION_ARG aDbgMask,aFormat,aArgs);
1822} // TDebugLogger::DebugVPrintf
1823
1824
1825void TDebugLogger::DebugVOpenBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, va_list aArgs)
1826{
1827 TDebugLoggerBase *loggerP = getThreadLogger();
1828 if (loggerP) loggerP->inherited::DebugVOpenBlock(TDBG_LOCATION_ARG aBlockName, aBlockTitle, aCollapsed, aBlockFmt, aArgs);
1829} // TDebugLogger::DebugVOpenBlock
1830
1831
1832void TDebugLogger:: DebugCloseBlock(TDBG_LOCATION_PROTO cAppCharP aBlockName)
1833{
1834 TDebugLoggerBase *loggerP = getThreadLogger();
1835 if (loggerP) loggerP->inherited::DebugCloseBlock(TDBG_LOCATION_ARG aBlockName);
1836} // TDebugLogger::DebugCloseBlock
1837
1838#endif
1839
1840
1841// output all buffered subthread's output in a special subthread Block in the main output
1842void TDebugLogger::DebugShowSubThreadOutput(void)
1843{
1844 #ifdef MULTI_THREAD_SUPPORT1
1845 // nop as long mixed-block mode is not implemented
1846 #endif
1847} // TDebugLogger::DebugShowSubThreadOutput
1848
1849
1850// the calling thread signals that it is done with doing output for now. If the main
1851// thread is doing this and we have bufferandmix mode, the next subthread will be allowed
1852// to write into the output channel until a new main thread gains control via
1853// DebugDefineMainThread();
1854void TDebugLogger::DebugThreadOutputDone(bool aRemoveIt)
1855{
1856 #ifdef MULTI_THREAD_SUPPORT1
1857 uIntArch threadID = myThreadID();
1858 if (threadID==fMainThreadID) {
1859 // current main thread done
1860 fMainThreadID = 0;
1861 }
1862 // for session logs, subthreads are usually left in the list at this time (aRemoveIt==false)
1863 // (as they will get deleted with the session logger later anyway)
1864 if (aRemoveIt) {
1865 TSubThreadLog* tP = findSubThread(threadID,true);
1866 if (tP) {
1867 if (tP->fSubThreadLogger) {
1868 SYSYNC_TRYtry {
1869 delete tP->fSubThreadLogger;
1870 }
1871 SYSYNC_CATCH(...)catch(...) {
1872 // nop
1873 SYSYNC_ENDCATCH}
1874 }
1875 delete tP;
1876 }
1877 }
1878 #endif
1879} // TDebugLogger::DebugThreadOutputDone
1880
1881
1882// Used to regain control as main thread (e.g. for the next request of a session which
1883// possibly occurs from another thread).
1884void TDebugLogger::DebugDefineMainThread(void)
1885{
1886 #ifdef MULTI_THREAD_SUPPORT1
1887 uIntArch threadID = myThreadID();
1888 // if this is already the main thread, no op
1889 if (threadID == fMainThreadID)
1890 return; // nop, done
1891 // thread is not the current main thread
1892 // - search if it is a registered subthread
1893 TSubThreadLog *subThreadP = findSubThread(threadID);
1894 if (fMainThreadID==0) {
1895 // no main thread currently registered
1896 if (subThreadP!=NULL__null) {
1897 // this is not a new thread, but a known subthread, can't get main thread now
1898 return; // no further op
1899 }
1900 else {
1901 // this is not a known subthread, so it can become the main thread
1902 fMainThreadID = threadID;
1903 return; // done
1904 }
1905 }
1906 else {
1907 // cannot become main thread, will be treated as subthread if it generates output
1908 // - no op required
1909 }
1910 #endif
1911} // TDebugLogger::DebugDefineMainThread
1912
1913
1914} // namespace sysync
1915
1916#endif // SYDEBUG
1917
1918// eof
1919