ncbidiag.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:42k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbidiag.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:08:57  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.80
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbidiag.cpp,v 1000.4 2004/06/01 19:08:57 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   NCBI C++ diagnostic API
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include <ncbiconf.h>
  42. #include <corelib/ncbidiag.hpp>
  43. #include <corelib/ncbithr.hpp>
  44. #include <corelib/ncbimtx.hpp>
  45. #include <corelib/ncbi_safe_static.hpp>
  46. #include <corelib/ncbiexpt.hpp>
  47. #include <stdlib.h>
  48. #include <time.h>
  49. #include <stack>
  50. #if defined(NCBI_OS_MAC)
  51. #  include <corelib/ncbi_os_mac.hpp>
  52. #endif
  53. BEGIN_NCBI_SCOPE
  54. DEFINE_STATIC_MUTEX(s_DiagMutex);
  55. #if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK)
  56. #include <unistd.h> // for pthread_atfork()
  57. extern "C" {
  58.     static void s_NcbiDiagPreFork(void)
  59.     {
  60.         s_DiagMutex.Lock();
  61.     }
  62.     static void s_NcbiDiagPostFork(void)
  63.     {
  64.         s_DiagMutex.Unlock();
  65.     }
  66. }
  67. #endif
  68. ///////////////////////////////////////////////////////
  69. //  CDiagRecycler::
  70. class CDiagRecycler {
  71. public:
  72.     CDiagRecycler(void)
  73.     {
  74. #if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK)
  75.         pthread_atfork(s_NcbiDiagPreFork,   // before
  76.                        s_NcbiDiagPostFork,  // after in parent
  77.                        s_NcbiDiagPostFork); // after in child
  78. #endif
  79.     }
  80.     ~CDiagRecycler(void)
  81.     {
  82.         SetDiagHandler(0, false);
  83.         SetDiagErrCodeInfo(0, false);
  84.     }
  85. };
  86. static CSafeStaticPtr<CDiagRecycler> s_DiagRecycler;
  87. ///////////////////////////////////////////////////////
  88. //  CDiagBuffer::
  89. #if defined(NDEBUG)
  90. EDiagSev       CDiagBuffer::sm_PostSeverity       = eDiag_Error;
  91. #else
  92. EDiagSev       CDiagBuffer::sm_PostSeverity       = eDiag_Warning;
  93. #endif /* else!NDEBUG */
  94. EDiagSevChange CDiagBuffer::sm_PostSeverityChange = eDiagSC_Unknown;
  95.                                                   // to be set on first request
  96. TDiagPostFlags CDiagBuffer::sm_PostFlags          =
  97.     eDPF_Prefix | eDPF_Severity | eDPF_ErrCode | eDPF_ErrSubCode | 
  98.     eDPF_ErrCodeMessage | eDPF_ErrCodeExplanation | eDPF_ErrCodeUseSeverity;
  99. TDiagPostFlags CDiagBuffer::sm_TraceFlags         = eDPF_Trace;
  100. EDiagSev       CDiagBuffer::sm_DieSeverity        = eDiag_Fatal;
  101. EDiagTrace     CDiagBuffer::sm_TraceDefault       = eDT_Default;
  102. bool           CDiagBuffer::sm_TraceEnabled;     // to be set on first request
  103. const char*    CDiagBuffer::sm_SeverityName[eDiag_Trace+1] = {
  104.     "Info", "Warning", "Error", "Critical", "Fatal", "Trace" };
  105. // Use s_DefaultHandler only for purposes of comparison, as installing
  106. // another handler will normally delete it.
  107. CDiagHandler*      s_DefaultHandler = new CStreamDiagHandler(&NcbiCerr);
  108. CDiagHandler*      CDiagBuffer::sm_Handler = s_DefaultHandler;
  109. bool               CDiagBuffer::sm_CanDeleteHandler = true;
  110. CDiagErrCodeInfo*  CDiagBuffer::sm_ErrCodeInfo = 0;
  111. bool               CDiagBuffer::sm_CanDeleteErrCodeInfo = false;
  112. CDiagBuffer::CDiagBuffer(void)
  113.     : m_Stream(new CNcbiOstrstream)
  114. {
  115.     m_Diag = 0;
  116. }
  117. CDiagBuffer::~CDiagBuffer(void)
  118. {
  119. #if (_DEBUG > 1)
  120.     if (m_Diag  ||  dynamic_cast<CNcbiOstrstream*>(m_Stream)->pcount())
  121.         Abort();
  122. #endif
  123.     delete m_Stream;
  124.     m_Stream = 0;
  125. }
  126. void CDiagBuffer::DiagHandler(SDiagMessage& mess)
  127. {
  128.     if ( CDiagBuffer::sm_Handler ) {
  129.         CMutexGuard LOCK(s_DiagMutex);
  130.         if ( CDiagBuffer::sm_Handler ) {
  131.             mess.m_Prefix = GetDiagBuffer().m_PostPrefix.empty() ?
  132.                 0 : GetDiagBuffer().m_PostPrefix.c_str();
  133.             CDiagBuffer::sm_Handler->Post(mess);
  134.         }
  135.     }
  136. }
  137. bool CDiagBuffer::SetDiag(const CNcbiDiag& diag)
  138. {
  139.     if ( !m_Stream ) {
  140.         return false;
  141.     }
  142.     // Check severity level change status
  143.     if ( sm_PostSeverityChange == eDiagSC_Unknown ) {
  144.         GetSeverityChangeEnabledFirstTime();
  145.     }
  146.     if (diag.GetSeverity() < sm_PostSeverity  ||
  147.         (diag.GetSeverity() == eDiag_Trace  &&  !GetTraceEnabled())) {
  148.         return false;
  149.     }
  150.     if (m_Diag != &diag) {
  151.         if ( dynamic_cast<CNcbiOstrstream*>(m_Stream)->pcount() ) {
  152.             Flush();
  153.         }
  154.         m_Diag = &diag;
  155.     }
  156.     return true;
  157. }
  158. void CDiagBuffer::Flush(void)
  159. {
  160.     if ( !m_Diag )
  161.         return;
  162.     CNcbiOstrstream* ostr = dynamic_cast<CNcbiOstrstream*>(m_Stream);
  163.     EDiagSev sev = m_Diag->GetSeverity();
  164.     if ( ostr->pcount() ) {
  165.         const char* message = ostr->str();
  166.         size_t size = ostr->pcount();
  167.         ostr->rdbuf()->freeze(false);
  168.         TDiagPostFlags flags = m_Diag->GetPostFlags();
  169.         if (sev == eDiag_Trace) {
  170.             flags |= sm_TraceFlags;
  171.         } else if (sev == eDiag_Fatal) {
  172.             // normally only happens once, so might as well pull everything
  173.             // in for the record...
  174.             flags |= sm_TraceFlags | eDPF_Trace;
  175.         }
  176.         string dest;
  177.         if (IsSetDiagPostFlag(eDPF_PreMergeLines, flags)) {
  178.             string src(message,0,size);
  179.             NStr::Replace(NStr::Replace(src,"r",""),"n",";", dest);
  180.             message = dest.c_str();
  181.             size = dest.length();
  182.         }
  183.         SDiagMessage mess
  184.             (sev, message, size,
  185.              m_Diag->GetFile(), m_Diag->GetLine(), flags,
  186.              0, m_Diag->GetErrorCode(), m_Diag->GetErrorSubCode());
  187.         DiagHandler(mess);
  188. #if defined(NCBI_COMPILER_KCC)
  189.         // KCC's implementation of "freeze(false)" makes the ostrstream buffer
  190.         // stuck.  We need to replace the frozen stream with the new one.
  191.         delete ostr;
  192.         m_Stream = new CNcbiOstrstream;
  193. #endif
  194.         Reset(*m_Diag);
  195.     }
  196.     if (sev >= sm_DieSeverity  &&  sev != eDiag_Trace) {
  197.         m_Diag = 0;
  198. #if defined(NCBI_OS_MAC)
  199.         if ( g_Mac_SpecialEnvironment ) {
  200.             throw runtime_error("Application aborted.");
  201.         }
  202. #endif
  203.         Abort();
  204.     }
  205. }
  206. bool CDiagBuffer::GetTraceEnabledFirstTime(void)
  207. {
  208.     CMutexGuard LOCK(s_DiagMutex);
  209.     const char* str = ::getenv(DIAG_TRACE);
  210.     if (str  &&  *str) {
  211.         sm_TraceDefault = eDT_Enable;
  212.     } else {
  213.         sm_TraceDefault = eDT_Disable;
  214.     }
  215.     sm_TraceEnabled = (sm_TraceDefault == eDT_Enable);
  216.     return sm_TraceEnabled;
  217. }
  218. bool CDiagBuffer::GetSeverityChangeEnabledFirstTime(void)
  219. {
  220.     CMutexGuard LOCK(s_DiagMutex);
  221.     if ( sm_PostSeverityChange != eDiagSC_Unknown ) {
  222.         return sm_PostSeverityChange == eDiagSC_Enable;
  223.     }
  224.     const char* str = ::getenv(DIAG_POST_LEVEL);
  225.     EDiagSev sev;
  226.     if (str  &&  *str  &&  CNcbiDiag::StrToSeverityLevel(str, sev)) {
  227.         SetDiagFixedPostLevel(sev);
  228.     } else {
  229.         sm_PostSeverityChange = eDiagSC_Enable;
  230.     }
  231.     return sm_PostSeverityChange == eDiagSC_Enable;
  232. }
  233. void CDiagBuffer::UpdatePrefix(void)
  234. {
  235.     m_PostPrefix.erase();
  236.     ITERATE(TPrefixList, prefix, m_PrefixList) {
  237.         if (prefix != m_PrefixList.begin()) {
  238.             m_PostPrefix += "::";
  239.         }
  240.         m_PostPrefix += *prefix;
  241.     }
  242. }
  243. ///////////////////////////////////////////////////////
  244. //  CDiagMessage::
  245. void SDiagMessage::Write(string& str, TDiagWriteFlags flags) const
  246. {
  247.     CNcbiOstrstream ostr;
  248.     Write(ostr, flags);
  249.     ostr.put('');
  250.     str = ostr.str();
  251.     ostr.rdbuf()->freeze(false);
  252. }
  253. CNcbiOstream& SDiagMessage::Write(CNcbiOstream&   os,
  254.                                   TDiagWriteFlags flags) const
  255. {
  256.     if (IsSetDiagPostFlag(eDPF_MergeLines, m_Flags)) {
  257.         CNcbiOstrstream ostr;
  258.         string src, dest;
  259.         x_Write(ostr, fNoEndl);
  260.         ostr.put('');
  261.         src = ostr.str();
  262.         ostr.rdbuf()->freeze(false);
  263.         NStr::Replace(NStr::Replace(src,"r",""),"n","", dest);
  264.         os << dest;
  265.         if ((flags & fNoEndl) == 0) {
  266.             os << NcbiEndl;
  267.         }
  268.         return os;
  269.     } else {
  270.         return x_Write(os, flags);
  271.     }
  272. }
  273. CNcbiOstream& SDiagMessage::x_Write(CNcbiOstream& os,
  274.                                     TDiagWriteFlags flags) const
  275. {
  276.     // Date & time
  277.     if (IsSetDiagPostFlag(eDPF_DateTime, m_Flags)) {
  278.         static const char timefmt[] = "%D %T ";
  279.         time_t t = time(0);
  280.         char datetime[32];
  281.         struct tm* tm;
  282. #ifdef HAVE_LOCALTIME_R
  283.         struct tm temp;
  284.         localtime_r(&t, &temp);
  285.         tm = &temp;
  286. #else
  287.         tm = localtime(&t);
  288. #endif /*HAVE_LOCALTIME_R*/
  289.         NStr::strftime(datetime, sizeof(datetime), timefmt, tm);
  290.         os << datetime;
  291.     }
  292.     // "<file>"
  293.     bool print_file = (m_File  &&  *m_File  &&
  294.                        IsSetDiagPostFlag(eDPF_File, m_Flags));
  295.     if ( print_file ) {
  296.         const char* x_file = m_File;
  297.         if ( !IsSetDiagPostFlag(eDPF_LongFilename, m_Flags) ) {
  298.             for (const char* s = m_File;  *s;  s++) {
  299.                 if (*s == '/'  ||  *s == '\'  ||  *s == ':')
  300.                     x_file = s + 1;
  301.             }
  302.         }
  303.         os << '"' << x_file << '"';
  304.     }
  305.     // , line <line>
  306.     bool print_line = (m_Line  &&  IsSetDiagPostFlag(eDPF_Line, m_Flags));
  307.     if ( print_line )
  308.         os << (print_file ? ", line " : "line ") << m_Line;
  309.     // :
  310.     if (print_file  ||  print_line)
  311.         os << ": ";
  312.     // Get error code description
  313.     bool have_description = false;
  314.     SDiagErrCodeDescription description;
  315.     if ((m_ErrCode  ||  m_ErrSubCode)  &&
  316.         (IsSetDiagPostFlag(eDPF_ErrCodeMessage, m_Flags)  || 
  317.          IsSetDiagPostFlag(eDPF_ErrCodeExplanation, m_Flags)  ||
  318.          IsSetDiagPostFlag(eDPF_ErrCodeUseSeverity, m_Flags))  &&
  319.          IsSetDiagErrCodeInfo()) {
  320.         CDiagErrCodeInfo* info = GetDiagErrCodeInfo();
  321.         if ( info  && 
  322.              info->GetDescription(ErrCode(m_ErrCode, m_ErrSubCode), 
  323.                                   &description) ) {
  324.             have_description = true;
  325.             if (IsSetDiagPostFlag(eDPF_ErrCodeUseSeverity, m_Flags) && 
  326.                 description.m_Severity != -1 )
  327.                 m_Severity = (EDiagSev)description.m_Severity;
  328.         }
  329.     }
  330.     // <severity>:
  331.     if (IsSetDiagPostFlag(eDPF_Severity, m_Flags)  &&
  332.         (m_Severity != eDiag_Info || !IsSetDiagPostFlag(eDPF_OmitInfoSev)))
  333.         os << CNcbiDiag::SeverityName(m_Severity) << ": ";
  334.     // (<err_code>.<err_subcode>) or (err_text)
  335.     if ((m_ErrCode  ||  m_ErrSubCode || m_ErrText)  &&
  336.         IsSetDiagPostFlag(eDPF_ErrCode, m_Flags)) {
  337.         os << '(';
  338.         if (m_ErrText) {
  339.             os << m_ErrText;
  340.         } else {
  341.             os << m_ErrCode;
  342.             if ( IsSetDiagPostFlag(eDPF_ErrSubCode, m_Flags)) {
  343.                 os << '.' << m_ErrSubCode;
  344.             }
  345.         }
  346.         os << ") ";
  347.     }
  348.     // [<prefix1>::<prefix2>::.....]
  349.     if (m_Prefix  &&  *m_Prefix  &&  IsSetDiagPostFlag(eDPF_Prefix, m_Flags))
  350.         os << '[' << m_Prefix << "] ";
  351.     // <message>
  352.     if (m_BufferLen)
  353.         os.write(m_Buffer, m_BufferLen);
  354.     // <err_code_message> and <err_code_explanation>
  355.     if (have_description) {
  356.         if (IsSetDiagPostFlag(eDPF_ErrCodeMessage, m_Flags) &&
  357.             !description.m_Message.empty())
  358.             os << NcbiEndl << description.m_Message << ' ';
  359.         if (IsSetDiagPostFlag(eDPF_ErrCodeExplanation, m_Flags) &&
  360.             !description.m_Explanation.empty())
  361.             os << NcbiEndl << description.m_Explanation;
  362.     }
  363.     // Endl
  364.     if ((flags & fNoEndl) == 0) {
  365.         os << NcbiEndl;
  366.     }
  367.     return os;
  368. }
  369. ///////////////////////////////////////////////////////
  370. //  CDiagAutoPrefix::
  371. CDiagAutoPrefix::CDiagAutoPrefix(const string& prefix)
  372. {
  373.     PushDiagPostPrefix(prefix.c_str());
  374. }
  375. CDiagAutoPrefix::CDiagAutoPrefix(const char* prefix)
  376. {
  377.     PushDiagPostPrefix(prefix);
  378. }
  379. CDiagAutoPrefix::~CDiagAutoPrefix(void)
  380. {
  381.     PopDiagPostPrefix();
  382. }
  383. ///////////////////////////////////////////////////////
  384. //  EXTERN
  385. static TDiagPostFlags s_SetDiagPostAllFlags(TDiagPostFlags& flags,
  386.                                             TDiagPostFlags  new_flags)
  387. {
  388.     CMutexGuard LOCK(s_DiagMutex);
  389.     TDiagPostFlags prev_flags = flags;
  390.     if (new_flags & eDPF_Default) {
  391.         new_flags |= prev_flags;
  392.         new_flags &= ~eDPF_Default;
  393.     }
  394.     flags = new_flags;
  395.     return prev_flags;
  396. }
  397. static void s_SetDiagPostFlag(TDiagPostFlags& flags, EDiagPostFlag flag)
  398. {
  399.     if (flag == eDPF_Default)
  400.         return;
  401.     CMutexGuard LOCK(s_DiagMutex);
  402.     flags |= flag;
  403. }
  404. static void s_UnsetDiagPostFlag(TDiagPostFlags& flags, EDiagPostFlag flag)
  405. {
  406.     if (flag == eDPF_Default)
  407.         return;
  408.     CMutexGuard LOCK(s_DiagMutex);
  409.     flags &= ~flag;
  410. }
  411. extern TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags)
  412. {
  413.     return s_SetDiagPostAllFlags(CDiagBuffer::sm_PostFlags, flags);
  414. }
  415. extern void SetDiagPostFlag(EDiagPostFlag flag)
  416. {
  417.     s_SetDiagPostFlag(CDiagBuffer::sm_PostFlags, flag);
  418. }
  419. extern void UnsetDiagPostFlag(EDiagPostFlag flag)
  420. {
  421.     s_UnsetDiagPostFlag(CDiagBuffer::sm_PostFlags, flag);
  422. }
  423. extern TDiagPostFlags SetDiagTraceAllFlags(TDiagPostFlags flags)
  424. {
  425.     return s_SetDiagPostAllFlags(CDiagBuffer::sm_TraceFlags, flags);
  426. }
  427. extern void SetDiagTraceFlag(EDiagPostFlag flag)
  428. {
  429.     s_SetDiagPostFlag(CDiagBuffer::sm_TraceFlags, flag);
  430. }
  431. extern void UnsetDiagTraceFlag(EDiagPostFlag flag)
  432. {
  433.     s_UnsetDiagPostFlag(CDiagBuffer::sm_TraceFlags, flag);
  434. }
  435. extern void SetDiagPostPrefix(const char* prefix)
  436. {
  437.     CDiagBuffer& buf = GetDiagBuffer();
  438.     if ( prefix ) {
  439.         buf.m_PostPrefix = prefix;
  440.     } else {
  441.         buf.m_PostPrefix.erase();
  442.     }
  443.     buf.m_PrefixList.clear();
  444. }
  445. extern void PushDiagPostPrefix(const char* prefix)
  446. {
  447.     if (prefix  &&  *prefix) {
  448.         CDiagBuffer& buf = GetDiagBuffer();
  449.         buf.m_PrefixList.push_back(prefix);
  450.         buf.UpdatePrefix();
  451.     }
  452. }
  453. extern void PopDiagPostPrefix(void)
  454. {
  455.     CDiagBuffer& buf = GetDiagBuffer();
  456.     if ( !buf.m_PrefixList.empty() ) {
  457.         buf.m_PrefixList.pop_back();
  458.         buf.UpdatePrefix();
  459.     }
  460. }
  461. extern EDiagSev SetDiagPostLevel(EDiagSev post_sev)
  462. {
  463.     if (post_sev < eDiagSevMin  ||  post_sev > eDiagSevMax) {
  464.         NCBI_THROW(CCoreException, eInvalidArg,
  465.                    "SetDiagPostLevel() -- Severity must be in the range "
  466.                    "[eDiagSevMin..eDiagSevMax]");
  467.     }
  468.     CMutexGuard LOCK(s_DiagMutex);
  469.     EDiagSev sev = CDiagBuffer::sm_PostSeverity;
  470.     if ( CDiagBuffer::sm_PostSeverityChange != eDiagSC_Disable) {
  471.         CDiagBuffer::sm_PostSeverity = post_sev;
  472.     }
  473.     return sev;
  474. }
  475. extern void SetDiagFixedPostLevel(const EDiagSev post_sev)
  476. {
  477.     SetDiagPostLevel(post_sev);
  478.     DisableDiagPostLevelChange();
  479. }
  480. extern bool DisableDiagPostLevelChange(bool disable_change)
  481. {
  482.     CMutexGuard LOCK(s_DiagMutex);
  483.     bool prev_status = (CDiagBuffer::sm_PostSeverityChange == eDiagSC_Enable);
  484.     CDiagBuffer::sm_PostSeverityChange = disable_change ? eDiagSC_Disable : 
  485.                                                           eDiagSC_Enable;
  486.     return prev_status;
  487. }
  488. extern EDiagSev SetDiagDieLevel(EDiagSev die_sev)
  489. {
  490.     if (die_sev < eDiagSevMin  ||  die_sev > eDiag_Fatal) {
  491.         NCBI_THROW(CCoreException, eInvalidArg,
  492.                    "SetDiagDieLevel() -- Severity must be in the range "
  493.                    "[eDiagSevMin..eDiag_Fatal]");
  494.     }
  495.     CMutexGuard LOCK(s_DiagMutex);
  496.     EDiagSev sev = CDiagBuffer::sm_DieSeverity;
  497.     CDiagBuffer::sm_DieSeverity = die_sev;
  498.     return sev;
  499. }
  500. extern void IgnoreDiagDieLevel(bool ignore, EDiagSev* prev_sev)
  501. {
  502.     if (!!ignore != !!prev_sev) {
  503.         NCBI_THROW(CCoreException, eInvalidArg,
  504.                    "IgnoreDiagDieLevel() -- Illegal 'ignore'/'prev_sev' "
  505.                    "combination");
  506.     }
  507.     CMutexGuard LOCK(s_DiagMutex);
  508.     if ( ignore ) {
  509.         *prev_sev = CDiagBuffer::sm_DieSeverity;
  510.         CDiagBuffer::sm_DieSeverity = eDiag_Trace;
  511.     } else {
  512.         CDiagBuffer::sm_DieSeverity = eDiag_Fatal;
  513.         CNcbiDiag diag(eDiag_Info);
  514.     }
  515. }
  516. extern void SetDiagTrace(EDiagTrace how, EDiagTrace dflt)
  517. {
  518.     CMutexGuard LOCK(s_DiagMutex);
  519.     (void) CDiagBuffer::GetTraceEnabled();
  520.     if (dflt != eDT_Default)
  521.         CDiagBuffer::sm_TraceDefault = dflt;
  522.     if (how == eDT_Default)
  523.         how = CDiagBuffer::sm_TraceDefault;
  524.     CDiagBuffer::sm_TraceEnabled = (how == eDT_Enable);
  525. }
  526. extern void SetDiagHandler(CDiagHandler* handler, bool can_delete)
  527. {
  528.     CMutexGuard LOCK(s_DiagMutex);
  529.     if ( CDiagBuffer::sm_CanDeleteHandler )
  530.         delete CDiagBuffer::sm_Handler;
  531.     CDiagBuffer::sm_Handler          = handler;
  532.     CDiagBuffer::sm_CanDeleteHandler = can_delete;
  533. }
  534. extern bool IsSetDiagHandler(void)
  535. {
  536.     return (CDiagBuffer::sm_Handler != s_DefaultHandler);
  537. }
  538. extern CDiagHandler* GetDiagHandler(bool take_ownership)
  539. {
  540.     CMutexGuard LOCK(s_DiagMutex);
  541.     if (take_ownership) {
  542.         _ASSERT(CDiagBuffer::sm_CanDeleteHandler);
  543.         CDiagBuffer::sm_CanDeleteHandler = false;
  544.     }
  545.     return CDiagBuffer::sm_Handler;
  546. }
  547. static void s_TlsDataCleanup(CDiagBuffer* old_value, void* /* cleanup_data */)
  548. {
  549.     delete old_value;
  550. }
  551. static bool s_TlsDestroyed; /* = false */
  552. static void s_TlsObjectCleanup(void* /* ptr */)
  553. {
  554.     s_TlsDestroyed = true;
  555. }
  556. extern CDiagBuffer& GetDiagBuffer(void)
  557. {
  558.     static CSafeStaticRef< CTls<CDiagBuffer> >
  559.         s_DiagBufferTls(s_TlsObjectCleanup);
  560.     // Create and use dummy buffer if all real buffers are gone already
  561.     // (on the application exit)
  562.     if ( s_TlsDestroyed ) {
  563.         static CDiagBuffer s_DiagBuffer;
  564.         return s_DiagBuffer;
  565.     }
  566.     // Create thread-specific diag.buffer (if not created yet),
  567.     // and store it to TLS
  568.     CDiagBuffer* msg_buf = s_DiagBufferTls->GetValue();
  569.     if ( !msg_buf ) {
  570.         msg_buf = new CDiagBuffer;
  571.         s_DiagBufferTls->SetValue(msg_buf, s_TlsDataCleanup);
  572.     }
  573.     return *msg_buf;
  574. }
  575. void CStreamDiagHandler::Post(const SDiagMessage& mess)
  576. {
  577.     if (m_Stream) {
  578.         (*m_Stream) << mess;
  579.         if (m_QuickFlush) {
  580.             (*m_Stream) << NcbiFlush;
  581.         }
  582.     }
  583. }
  584. extern bool IsDiagStream(const CNcbiOstream* os)
  585. {
  586.     CStreamDiagHandler* sdh
  587.         = dynamic_cast<CStreamDiagHandler*>(CDiagBuffer::sm_Handler);
  588.     return (sdh  &&  sdh->m_Stream == os);
  589. }
  590. extern void SetDiagErrCodeInfo(CDiagErrCodeInfo* info, bool can_delete)
  591. {
  592.     CMutexGuard LOCK(s_DiagMutex);
  593.     if ( CDiagBuffer::sm_CanDeleteErrCodeInfo )
  594.         delete CDiagBuffer::sm_ErrCodeInfo;
  595.     CDiagBuffer::sm_ErrCodeInfo = info;
  596.     CDiagBuffer::sm_CanDeleteErrCodeInfo = can_delete;
  597. }
  598. extern bool IsSetDiagErrCodeInfo(void)
  599. {
  600.     return (CDiagBuffer::sm_ErrCodeInfo != 0);
  601. }
  602. extern CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership)
  603. {
  604.     CMutexGuard LOCK(s_DiagMutex);
  605.     if (take_ownership) {
  606.         _ASSERT(CDiagBuffer::sm_CanDeleteErrCodeInfo);
  607.         CDiagBuffer::sm_CanDeleteErrCodeInfo = false;
  608.     }
  609.     return CDiagBuffer::sm_ErrCodeInfo;
  610. }
  611. ///////////////////////////////////////////////////////
  612. //  CNcbiDiag::
  613. CNcbiDiag::CNcbiDiag(EDiagSev sev, TDiagPostFlags post_flags)
  614.     : m_Severity(sev), m_Line(0), m_ErrCode(0), m_ErrSubCode(0),
  615.       m_Buffer(GetDiagBuffer()), m_PostFlags(post_flags)
  616. {
  617.     *m_File = '';
  618. }
  619. CNcbiDiag::CNcbiDiag(const char* file, size_t line,
  620.                      EDiagSev sev, TDiagPostFlags post_flags)
  621.     : m_Severity(sev), m_Line(line), m_ErrCode(0), m_ErrSubCode(0),
  622.       m_Buffer(GetDiagBuffer()), m_PostFlags(post_flags)
  623. {
  624.     SetFile(file);
  625. }
  626. const CNcbiDiag& CNcbiDiag::SetFile(const char* file) const
  627. {
  628.     if (file  &&  *file) {
  629.         strncpy(m_File, file, sizeof(m_File));
  630.         m_File[sizeof(m_File) - 1] = '';
  631.     } else {
  632.         *m_File = '';
  633.     }
  634.     return *this;
  635. }
  636. const CNcbiDiag& CNcbiDiag::operator<< (const CException& ex) const
  637. {
  638.     {
  639.         ostrstream os;
  640.         os << 'n' << "NCBI C++ Exception:" << 'n';
  641.         *this << string(CNcbiOstrstreamToString(os));
  642.     }
  643.     const CException* pex;
  644.     stack<const CException*> pile;
  645.     // invert the order
  646.     for (pex = &ex; pex; pex = pex->GetPredecessor()) {
  647.         pile.push(pex);
  648.     }
  649.     for (; !pile.empty(); pile.pop()) {
  650.         pex = pile.top();
  651.         string text(pex->GetMsg());
  652.         {
  653.             ostrstream os;
  654.             pex->ReportExtra(os);
  655.             if (os.pcount() != 0) {
  656.                 text += " (";
  657.                 text += (string)CNcbiOstrstreamToString(os);
  658.                 text += ')';
  659.             }
  660.         }
  661.         string err_type(pex->GetType());
  662.         err_type += "::";
  663.         err_type += pex->GetErrCodeString();
  664.         SDiagMessage diagmsg(
  665.             eDiag_Error, text.c_str(), text.size(),
  666.             (pex->GetFile()).c_str(), pex->GetLine(),
  667.             GetPostFlags(), 0,0,0,err_type.c_str());
  668.         string report;
  669.         diagmsg.Write(report);
  670.         *this << "    "; // indentation
  671.         *this << report;
  672.     }
  673.     return *this;
  674. }
  675. bool CNcbiDiag::StrToSeverityLevel(const char* str_sev, EDiagSev& sev)
  676. {
  677.     if (!str_sev || !*str_sev) {
  678.         return false;
  679.     } 
  680.     // Digital value
  681.     int nsev = NStr::StringToNumeric(str_sev);
  682.     if (nsev > eDiagSevMax) {
  683.         nsev = eDiagSevMax;
  684.     } else if ( nsev == -1 ) {
  685.         // String value
  686.         for (int s = eDiagSevMin; s <= eDiagSevMax; s++) {
  687.             if (NStr::CompareNocase(CNcbiDiag::SeverityName(EDiagSev(s)),
  688.                                     str_sev) == 0) {
  689.                 nsev = s;
  690.                 break;
  691.             }
  692.         }
  693.     }
  694.     sev = EDiagSev(nsev);
  695.     // Unknown value
  696.     return sev >= eDiagSevMin && sev <= eDiagSevMax;
  697. }
  698. void CNcbiDiag::DiagFatal(const char* file, size_t line,
  699.                           const char* message)
  700. {
  701.     CNcbiDiag(file, line, NCBI_NS_NCBI::eDiag_Fatal) << message << Endm;
  702. }
  703. void CNcbiDiag::DiagTrouble(const char* file, size_t line)
  704. {
  705.     DiagFatal(file, line, "Trouble!");
  706. }
  707. void CNcbiDiag::DiagAssert(const char* file, size_t line,
  708.                            const char* expression)
  709. {
  710.     CNcbiDiag(file, line, NCBI_NS_NCBI::eDiag_Fatal, eDPF_Trace) <<
  711.         "Assertion failed: (" << expression << ')' << Endm;
  712. }
  713. void CNcbiDiag::DiagValidate(const char* file, size_t line,
  714.                              const char* _DEBUG_ARG(expression),
  715.                              const char* message)
  716. {
  717. #ifdef _DEBUG
  718.     if ( xncbi_GetValidateAction() != eValidate_Throw ) {
  719.         DiagAssert(file, line, expression);
  720.     }
  721. #endif
  722.     throw CCoreException(file, (int) line, 0, CCoreException::eCore, message);
  723. }
  724. ///////////////////////////////////////////////////////
  725. //  CDiagRestorer::
  726. CDiagRestorer::CDiagRestorer(void)
  727. {
  728.     CMutexGuard LOCK(s_DiagMutex);
  729.     const CDiagBuffer& buf  = GetDiagBuffer();
  730.     m_PostPrefix            = buf.m_PostPrefix;
  731.     m_PrefixList            = buf.m_PrefixList;
  732.     m_PostFlags             = buf.sm_PostFlags;
  733.     m_PostSeverity          = buf.sm_PostSeverity;
  734.     m_PostSeverityChange    = buf.sm_PostSeverityChange;
  735.     m_DieSeverity           = buf.sm_DieSeverity;
  736.     m_TraceDefault          = buf.sm_TraceDefault;
  737.     m_TraceEnabled          = buf.sm_TraceEnabled;
  738.     m_Handler               = buf.sm_Handler;
  739.     m_CanDeleteHandler      = buf.sm_CanDeleteHandler;
  740.     m_ErrCodeInfo           = buf.sm_ErrCodeInfo;
  741.     m_CanDeleteErrCodeInfo  = buf.sm_CanDeleteErrCodeInfo;
  742.     // avoid premature cleanup
  743.     buf.sm_CanDeleteHandler = false;
  744.     buf.sm_CanDeleteErrCodeInfo = false;
  745. }
  746. CDiagRestorer::~CDiagRestorer(void)
  747. {
  748.     {{
  749.         CMutexGuard LOCK(s_DiagMutex);
  750.         CDiagBuffer& buf          = GetDiagBuffer();
  751.         buf.m_PostPrefix          = m_PostPrefix;
  752.         buf.m_PrefixList          = m_PrefixList;
  753.         buf.sm_PostFlags          = m_PostFlags;
  754.         buf.sm_PostSeverity       = m_PostSeverity;
  755.         buf.sm_PostSeverityChange = m_PostSeverityChange;
  756.         buf.sm_DieSeverity        = m_DieSeverity;
  757.         buf.sm_TraceDefault       = m_TraceDefault;
  758.         buf.sm_TraceEnabled       = m_TraceEnabled;
  759.     }}
  760.     SetDiagHandler(m_Handler, m_CanDeleteHandler);
  761.     SetDiagErrCodeInfo(m_ErrCodeInfo, m_CanDeleteErrCodeInfo);
  762. }
  763. //////////////////////////////////////////////////////
  764. //  internal diag. handler classes for compatibility:
  765. class CCompatDiagHandler : public CDiagHandler
  766. {
  767. public:
  768.     CCompatDiagHandler(FDiagHandler func, void* data, FDiagCleanup cleanup)
  769.         : m_Func(func), m_Data(data), m_Cleanup(cleanup)
  770.         { }
  771.     ~CCompatDiagHandler(void)
  772.         {
  773.             if (m_Cleanup) {
  774.                 m_Cleanup(m_Data);
  775.             }
  776.         }
  777.     virtual void Post(const SDiagMessage& mess) { m_Func(mess); }
  778. private:
  779.     FDiagHandler m_Func;
  780.     void*        m_Data;
  781.     FDiagCleanup m_Cleanup;
  782. };
  783. extern void SetDiagHandler(FDiagHandler func,
  784.                            void*        data,
  785.                            FDiagCleanup cleanup)
  786. {
  787.     SetDiagHandler(new CCompatDiagHandler(func, data, cleanup));
  788. }
  789. class CCompatStreamDiagHandler : public CStreamDiagHandler
  790. {
  791. public:
  792.     CCompatStreamDiagHandler(CNcbiOstream* os, bool quick_flush = true,
  793.                              FDiagCleanup cleanup = 0,
  794.                              void* cleanup_data = 0)
  795.         : CStreamDiagHandler(os, quick_flush),
  796.           m_Cleanup(cleanup), m_CleanupData(cleanup_data)
  797.         {
  798.         }
  799.     ~CCompatStreamDiagHandler(void)
  800.         {
  801.             if (m_Cleanup) {
  802.                 m_Cleanup(m_CleanupData);
  803.             }
  804.         }
  805. private:
  806.     FDiagCleanup m_Cleanup;
  807.     void*        m_CleanupData;
  808. };
  809. extern void SetDiagStream(CNcbiOstream* os, bool quick_flush,
  810.                           FDiagCleanup cleanup, void* cleanup_data)
  811. {
  812.     SetDiagHandler(new CCompatStreamDiagHandler(os, quick_flush,
  813.                                                 cleanup, cleanup_data));
  814. }
  815. //////////////////////////////////////////////////////
  816. //  abort handler
  817. static FAbortHandler s_UserAbortHandler = 0;
  818. extern void SetAbortHandler(FAbortHandler func)
  819. {
  820.     s_UserAbortHandler = func;
  821. }
  822. extern void Abort(void)
  823. {
  824.     // If defined user abort handler then call it 
  825.     if ( s_UserAbortHandler )
  826.         s_UserAbortHandler();
  827.     
  828.     // If don't defined handler or application doesn't still terminated
  829.     // Check environment variable for silent exit
  830.     const char* value = getenv("DIAG_SILENT_ABORT");
  831.     if (value  &&  (*value == 'Y'  ||  *value == 'y'  ||  *value == '1')) {
  832.         ::exit(255);
  833.     }
  834.     else if (value  &&  (*value == 'N'  ||  *value == 'n' || *value == '0')) {
  835.         ::abort();
  836.     }
  837.     else {
  838. #if defined(_DEBUG)
  839.         ::abort();
  840. #else
  841.         ::exit(255);
  842. #endif
  843.     }
  844. }
  845. ///////////////////////////////////////////////////////
  846. //  CDiagErrCodeInfo::
  847. //
  848. SDiagErrCodeDescription::SDiagErrCodeDescription(void)
  849.         : m_Message(kEmptyStr),
  850.           m_Explanation(kEmptyStr),
  851.           m_Severity(-1)
  852. {
  853.     return;
  854. }
  855. bool CDiagErrCodeInfo::Read(const string& file_name)
  856. {
  857.     CNcbiIfstream is(file_name.c_str());
  858.     if ( !is.good() ) {
  859.         return false;
  860.     }
  861.     return Read(is);
  862. }
  863. // Parse string for CDiagErrCodeInfo::Read()
  864. bool s_ParseErrCodeInfoStr(string&          str,
  865.                            const SIZE_TYPE  line,
  866.                            int&             x_code,
  867.                            int&             x_severity,
  868.                            string&          x_message,
  869.                            bool&            x_ready)
  870. {
  871.     list<string> tokens;    // List with line tokens
  872.     try {
  873.         // Get message text
  874.         SIZE_TYPE pos = str.find_first_of(':');
  875.         if (pos == NPOS) {
  876.             x_message = kEmptyStr;
  877.         } else {
  878.             x_message = NStr::TruncateSpaces(str.substr(pos+1));
  879.             str.erase(pos);
  880.         }
  881.         // Split string on parts
  882.         NStr::Split(str, ",", tokens);
  883.         if (tokens.size() < 2) {
  884.             ERR_POST("Error message file parsing: Incorrect file format " 
  885.                      ", line " + NStr::IntToString(line));
  886.             return false;
  887.         }
  888.         // Mnemonic name (skip)
  889.         tokens.pop_front();
  890.         // Error code
  891.         string token = NStr::TruncateSpaces(tokens.front());
  892.         tokens.pop_front();
  893.         x_code = NStr::StringToInt(token);
  894.         // Severity
  895.         if (!tokens.empty()) { 
  896.             token = NStr::TruncateSpaces(tokens.front());
  897.             EDiagSev sev;
  898.             if (CNcbiDiag::StrToSeverityLevel(token.c_str(), sev)) {
  899.                 x_severity = sev;
  900.             } else {
  901.                 ERR_POST(Warning << "Error message file parsing: " 
  902.                          "Incorrect severity level in the verbose " 
  903.                          "message file, line " + NStr::IntToString(line));
  904.             }
  905.         } else {
  906.             x_severity = -1;
  907.         }
  908.     }
  909.     catch (CException& e) {
  910.         ERR_POST(Warning << "Error message file parsing: " << e.GetMsg() <<
  911.                  ", line " + NStr::IntToString(line));
  912.         return false;
  913.     }
  914.     x_ready = true;
  915.     return true;
  916. }
  917.   
  918. bool CDiagErrCodeInfo::Read(CNcbiIstream& is)
  919. {
  920.     string       str;                      // The line being parsed
  921.     SIZE_TYPE    line;                     // # of the line being parsed
  922.     bool         err_ready       = false;  // Error data ready flag 
  923.     int          err_code        = 0;      // First level error code
  924.     int          err_subcode     = 0;      // Second level error code
  925.     string       err_message;              // Short message
  926.     string       err_text;                 // Error explanation
  927.     int          err_severity    = -1;     // Use default severity if  
  928.                                            // has not specified
  929.     int          err_subseverity = -1;     // Use parents severity if  
  930.                                            // has not specified
  931.     for (line = 1;  NcbiGetlineEOL(is, str);  line++) {
  932.         
  933.         // This is a comment or empty line
  934.         if (!str.length()  ||  NStr::StartsWith(str,"#")) {
  935.             continue;
  936.         }
  937.         // Add error description
  938.         if (err_ready  &&  str[0] == '$') {
  939.             if (err_subseverity == -1)
  940.                 err_subseverity = err_severity;
  941.             SetDescription(ErrCode(err_code, err_subcode), 
  942.                 SDiagErrCodeDescription(err_message, err_text,
  943.                                         err_subseverity));
  944.             // Clean
  945.             err_subseverity = -1;
  946.             err_text     = kEmptyStr;
  947.             err_ready    = false;
  948.         }
  949.         // Get error code
  950.         if (NStr::StartsWith(str,"$$")) {
  951.             if (!s_ParseErrCodeInfoStr(str, line, err_code, err_severity, 
  952.                                        err_message, err_ready))
  953.                 continue;
  954.             err_subcode = 0;
  955.         
  956.         } else if (NStr::StartsWith(str,"$^")) {
  957.         // Get error subcode
  958.             s_ParseErrCodeInfoStr(str, line, err_subcode, err_subseverity,
  959.                                   err_message, err_ready);
  960.       
  961.         } else if (err_ready) {
  962.         // Get line of explanation message
  963.             if (!err_text.empty()) {
  964.                 err_text += 'n';
  965.             }
  966.             err_text += str;
  967.         }
  968.     }
  969.     if (err_ready) {
  970.         if (err_subseverity == -1)
  971.             err_subseverity = err_severity;
  972.         SetDescription(ErrCode(err_code, err_subcode), 
  973.             SDiagErrCodeDescription(err_message, err_text,
  974.                                     err_subseverity));
  975.     }
  976.     return true;
  977. }
  978. bool CDiagErrCodeInfo::GetDescription(const ErrCode& err_code, 
  979.                       SDiagErrCodeDescription* description) const
  980. {
  981.     // Find entry
  982.     TInfo::const_iterator find_entry = m_Info.find(err_code);
  983.     if (find_entry == m_Info.end()) {
  984.         return false;
  985.     }
  986.     // Get entry value
  987.     const SDiagErrCodeDescription& entry = find_entry->second;
  988.     if (description) {
  989.         *description = entry;
  990.     }
  991.     return true;
  992. }
  993. END_NCBI_SCOPE
  994. /*
  995.  * ==========================================================================
  996.  * $Log: ncbidiag.cpp,v $
  997.  * Revision 1000.4  2004/06/01 19:08:57  gouriano
  998.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.80
  999.  *
  1000.  * Revision 1.80  2004/05/14 13:59:27  gorelenk
  1001.  * Added include of ncbi_pch.hpp
  1002.  *
  1003.  * Revision 1.79  2004/03/18 20:19:20  gouriano
  1004.  * make it possible to convert multi-line diagnostic message into single-line
  1005.  *
  1006.  * Revision 1.78  2003/11/12 20:30:26  ucko
  1007.  * Make extra flags for severity-trace messages tunable.
  1008.  *
  1009.  * Revision 1.77  2003/11/06 21:40:56  vakatov
  1010.  * A somewhat more natural handling of the 'eDPF_Default' flag -- replace
  1011.  * it by the current global flags, then merge these with other flags (if any)
  1012.  *
  1013.  * Revision 1.76  2003/10/31 19:38:53  lavr
  1014.  * No '' in exception reporting
  1015.  *
  1016.  * Revision 1.75  2003/09/26 15:54:13  vakatov
  1017.  * CNcbiDiag::DiagAssert() -- print everything (trace-like -- file, line, etc.)
  1018.  * in the message
  1019.  *
  1020.  * Revision 1.74  2003/09/17 15:58:29  vasilche
  1021.  * Allow debug abort when:
  1022.  * CObjectException is thrown - env var NCBI_ABORT_ON_COBJECT_THROW=[Yy1],
  1023.  * CNullPointerException is thrown - env var NCBI_ABORT_ON_NULL=[Yy1].
  1024.  * Allow quit abort in debug mode and coredump in release mode:
  1025.  * env var DIAG_SILENT_ABORT=[Yy1Nn0].
  1026.  *
  1027.  * Revision 1.73  2003/05/19 21:12:46  vakatov
  1028.  * CNcbiDiag::DiagValidate() -- get rid of "unused func arg" compilation warning
  1029.  *
  1030.  * Revision 1.72  2003/04/25 20:54:15  lavr
  1031.  * Introduce draft version of IgnoreDiagDieLevel()
  1032.  *
  1033.  * Revision 1.71  2003/03/10 18:57:08  kuznets
  1034.  * iterate->ITERATE
  1035.  *
  1036.  * Revision 1.70  2003/02/21 21:08:57  vakatov
  1037.  * Minor cast to get rid of 64-bit compilation warning
  1038.  *
  1039.  * Revision 1.69  2003/01/13 20:42:50  gouriano
  1040.  * corrected the problem with ostrstream::str(): replaced such calls with
  1041.  * CNcbiOstrstreamToString(os)
  1042.  *
  1043.  * Revision 1.68  2002/09/30 16:35:16  vasilche
  1044.  * Restored mutex lock on fork().
  1045.  *
  1046.  * Revision 1.67  2002/09/24 18:28:20  vasilche
  1047.  * Fixed behavour of CNcbiDiag::DiagValidate() in release mode
  1048.  *
  1049.  * Revision 1.66  2002/09/19 20:05:42  vasilche
  1050.  * Safe initialization of static mutexes
  1051.  *
  1052.  * Revision 1.65  2002/08/20 19:10:39  gouriano
  1053.  * added DiagWriteFlags into SDiagMessage::Write
  1054.  *
  1055.  * Revision 1.64  2002/08/16 15:02:11  ivanov
  1056.  * Added class CDiagAutoPrefix
  1057.  *
  1058.  * Revision 1.63  2002/08/01 18:47:43  ivanov
  1059.  * Added stuff to store and output error verbose messages for error codes
  1060.  *
  1061.  * Revision 1.62  2002/07/25 15:46:08  ivanov
  1062.  * Rollback R1.60
  1063.  *
  1064.  * Revision 1.61  2002/07/25 13:35:05  ivanov
  1065.  * Changed exit code of a faild test
  1066.  *
  1067.  * Revision 1.60  2002/07/15 18:17:24  gouriano
  1068.  * renamed CNcbiException and its descendents
  1069.  *
  1070.  * Revision 1.59  2002/07/10 16:19:00  ivanov
  1071.  * Added CNcbiDiag::StrToSeverityLevel().
  1072.  * Rewrite and rename SetDiagFixedStrPostLevel() -> SetDiagFixedPostLevel()
  1073.  *
  1074.  * Revision 1.58  2002/07/09 16:37:11  ivanov
  1075.  * Added GetSeverityChangeEnabledFirstTime().
  1076.  * Fix usage forced set severity post level from environment variable
  1077.  * to work without NcbiApplication::AppMain()
  1078.  *
  1079.  * Revision 1.57  2002/07/02 18:26:22  ivanov
  1080.  * Added CDiagBuffer::DisableDiagPostLevelChange()
  1081.  *
  1082.  * Revision 1.56  2002/06/27 18:56:16  gouriano
  1083.  * added "title" parameter to report functions
  1084.  *
  1085.  * Revision 1.55  2002/06/26 18:38:04  gouriano
  1086.  * added CNcbiException class
  1087.  *
  1088.  * Revision 1.54  2002/06/18 17:07:12  lavr
  1089.  * Take advantage of NStr:strftime()
  1090.  *
  1091.  * Revision 1.53  2002/05/14 16:47:27  ucko
  1092.  * Conditionalize usage of pthread_atfork, which doesn't seem to exist at
  1093.  * all on FreeBSD.
  1094.  *
  1095.  * Revision 1.52  2002/05/03 14:29:17  ucko
  1096.  * #include <unistd.h> for pthread_atfork(); the other headers do not
  1097.  * necessarily already include it.
  1098.  *
  1099.  * Revision 1.51  2002/04/25 21:49:05  ucko
  1100.  * Made pthread_atfork callbacks extern "C".
  1101.  *
  1102.  * Revision 1.50  2002/04/25 21:29:39  ucko
  1103.  * At Yan Raytselis's suggestion, use pthread_atfork to avoid
  1104.  * inadvertently holding s_DiagMutex across fork.
  1105.  *
  1106.  * Revision 1.49  2002/04/23 19:57:29  vakatov
  1107.  * Made the whole CNcbiDiag class "mutable" -- it helps eliminate
  1108.  * numerous warnings issued by SUN Forte6U2 compiler.
  1109.  * Do not use #NO_INCLASS_TMPL anymore -- apparently all modern
  1110.  * compilers seem to be supporting in-class template methods.
  1111.  *
  1112.  * Revision 1.48  2002/04/16 18:48:42  ivanov
  1113.  * SuppressDiagPopupMessages() moved to "test/test_assert.h"
  1114.  *
  1115.  * Revision 1.47  2002/04/11 19:58:34  ivanov
  1116.  * Added function SuppressDiagPopupMessages()
  1117.  *
  1118.  * Revision 1.46  2002/04/10 14:45:27  ivanov
  1119.  * Abort() moved from static to extern and added to header file
  1120.  *
  1121.  * Revision 1.45  2002/04/01 22:35:22  ivanov
  1122.  * Added SetAbortHandler() function to set user abort handler.
  1123.  * Used call internal function Abort() vice ::abort().
  1124.  *
  1125.  * Revision 1.44  2002/02/07 19:45:54  ucko
  1126.  * Optionally transfer ownership in GetDiagHandler.
  1127.  *
  1128.  * Revision 1.43  2002/02/05 22:01:36  lavr
  1129.  * Minor tweak
  1130.  *
  1131.  * Revision 1.42  2002/01/12 22:16:47  lavr
  1132.  * Eliminated GCC warning: "'%D' yields only 2 digits of year"
  1133.  *
  1134.  * Revision 1.41  2001/12/07 15:27:28  ucko
  1135.  * Switch CDiagRecycler over to current form of SetDiagHandler.
  1136.  *
  1137.  * Revision 1.40  2001/12/03 22:06:31  juran
  1138.  * Use 'special environment' flag to indicate that a fatal error
  1139.  * must throw an exception rather than abort.  (Mac only.)
  1140.  *
  1141.  * Revision 1.39  2001/11/14 15:15:00  ucko
  1142.  * Revise diagnostic handling to be more object-oriented.
  1143.  *
  1144.  * Revision 1.38  2001/10/29 15:16:13  ucko
  1145.  * Preserve default CGI diagnostic settings, even if customized by app.
  1146.  *
  1147.  * Revision 1.37  2001/10/16 23:44:07  vakatov
  1148.  * + SetDiagPostAllFlags()
  1149.  *
  1150.  * Revision 1.36  2001/08/24 13:48:01  grichenk
  1151.  * Prevented some memory leaks
  1152.  *
  1153.  * Revision 1.35  2001/08/09 16:26:11  lavr
  1154.  * Added handling for new eDPF_OmitInfoSev format flag
  1155.  *
  1156.  * Revision 1.34  2001/07/30 14:42:10  lavr
  1157.  * eDiag_Trace and eDiag_Fatal always print as much as possible
  1158.  *
  1159.  * Revision 1.33  2001/07/26 21:29:00  lavr
  1160.  * Remove printing DateTime stamp by default
  1161.  *
  1162.  * Revision 1.32  2001/07/25 19:13:55  lavr
  1163.  * Added date/time stamp for message logging
  1164.  *
  1165.  * Revision 1.31  2001/06/13 23:19:38  vakatov
  1166.  * Revamped previous revision (prefix and error codes)
  1167.  *
  1168.  * Revision 1.30  2001/06/13 20:48:28  ivanov
  1169.  * + PushDiagPostPrefix(), PopPushDiagPostPrefix() - stack post prefix messages.
  1170.  * + ERR_POST_EX, LOG_POST_EX - macros for posting with error codes.
  1171.  * + ErrCode(code[,subcode]) - CNcbiDiag error code manipulator.
  1172.  * + eDPF_ErrCode, eDPF_ErrSubCode - new post flags.
  1173.  *
  1174.  * Revision 1.29  2001/06/05 20:58:16  vakatov
  1175.  * ~CDiagBuffer()::  to check for consistency and call "abort()" only
  1176.  * #if (_DEBUG > 1)
  1177.  *
  1178.  * Revision 1.28  2001/05/17 15:04:59  lavr
  1179.  * Typos corrected
  1180.  *
  1181.  * Revision 1.27  2001/03/30 22:49:22  grichenk
  1182.  * KCC freeze() bug workaround
  1183.  *
  1184.  * Revision 1.26  2001/03/26 21:45:54  vakatov
  1185.  * Made MT-safe (with A.Grichenko)
  1186.  *
  1187.  * Revision 1.25  2001/01/23 23:20:42  lavr
  1188.  * MSVS++ -> MSVC++
  1189.  *
  1190.  * Revision 1.24  2000/11/16 23:52:41  vakatov
  1191.  * Porting to Mac...
  1192.  *
  1193.  * Revision 1.23  2000/10/24 21:51:21  vakatov
  1194.  * [DEBUG] By default, do not print file name and line into the diagnostics
  1195.  *
  1196.  * Revision 1.22  2000/10/24 19:54:46  vakatov
  1197.  * Diagnostics to go to CERR by default (was -- disabled by default)
  1198.  *
  1199.  * Revision 1.21  2000/06/22 22:09:10  vakatov
  1200.  * Fixed:  GetTraceEnabledFirstTime(), sm_TraceDefault
  1201.  *
  1202.  * Revision 1.20  2000/06/11 01:47:28  vakatov
  1203.  * IsDiagSet(0) to return TRUE if the diag stream is unset
  1204.  *
  1205.  * Revision 1.19  2000/06/09 21:22:21  vakatov
  1206.  * IsDiagStream() -- fixed
  1207.  *
  1208.  * Revision 1.18  2000/04/04 22:31:59  vakatov
  1209.  * SetDiagTrace() -- auto-set basing on the application
  1210.  * environment and/or registry
  1211.  *
  1212.  * Revision 1.17  2000/02/18 16:54:07  vakatov
  1213.  * + eDiag_Critical
  1214.  *
  1215.  * Revision 1.16  2000/01/20 16:52:32  vakatov
  1216.  * SDiagMessage::Write() to replace SDiagMessage::Compose()
  1217.  * + operator<<(CNcbiOstream& os, const SDiagMessage& mess)
  1218.  * + IsSetDiagHandler(), IsDiagStream()
  1219.  *
  1220.  * Revision 1.15  1999/12/29 22:30:25  vakatov
  1221.  * Use "exit()" rather than "abort()" in non-#_DEBUG mode
  1222.  *
  1223.  * Revision 1.14  1999/12/29 21:22:30  vakatov
  1224.  * Fixed "delete" to "delete[]"
  1225.  *
  1226.  * Revision 1.13  1999/12/27 19:44:18  vakatov
  1227.  * Fixes for R1.13:
  1228.  * ERR_POST() -- use eDPF_Default rather than eDPF_Trace;  forcibly flush
  1229.  * ("<< Endm") the diag. stream. Get rid of the eDPF_CopyFilename, always
  1230.  * make a copy of the file name.
  1231.  *
  1232.  * Revision 1.12  1999/12/16 17:22:51  vakatov
  1233.  * Fixed "delete" to "delete[]"
  1234.  *
  1235.  * Revision 1.11  1999/09/27 16:23:23  vasilche
  1236.  * Changed implementation of debugging macros (_TRACE, _THROW*, _ASSERT etc),
  1237.  * so that they will be much easier for compilers to eat.
  1238.  *
  1239.  * Revision 1.10  1999/05/27 16:32:26  vakatov
  1240.  * In debug-mode(#_DEBUG), set the default post severity level to
  1241.  * "Warning" (yet, it is "Error" in non-debug mode)
  1242.  *
  1243.  * Revision 1.9  1999/04/30 19:21:04  vakatov
  1244.  * Added more details and more control on the diagnostics
  1245.  * See #ERR_POST, EDiagPostFlag, and ***DiagPostFlag()
  1246.  *
  1247.  * Revision 1.8  1998/12/28 17:56:37  vakatov
  1248.  * New CVS and development tree structure for the NCBI C++ projects
  1249.  *
  1250.  * Revision 1.7  1998/11/06 22:42:41  vakatov
  1251.  * Introduced BEGIN_, END_ and USING_ NCBI_SCOPE macros to put NCBI C++
  1252.  * API to namespace "ncbi::" and to use it by default, respectively
  1253.  * Introduced THROWS_NONE and THROWS(x) macros for the exception
  1254.  * specifications
  1255.  * Other fixes and rearrangements throughout the most of "corelib" code
  1256.  *
  1257.  * Revision 1.6  1998/11/03 22:57:51  vakatov
  1258.  * Use #define'd manipulators(like "NcbiFlush" instead of "flush") to
  1259.  * make it compile and work with new(templated) version of C++ streams
  1260.  *
  1261.  * Revision 1.4  1998/11/03 22:28:35  vakatov
  1262.  * Renamed Die/Post...Severity() to ...Level()
  1263.  *
  1264.  * Revision 1.3  1998/11/03 20:51:26  vakatov
  1265.  * Adaptation for the SunPro compiler glitchs(see conf. #NO_INCLASS_TMPL)
  1266.  *
  1267.  * Revision 1.2  1998/10/30 20:08:37  vakatov
  1268.  * Fixes to (first-time) compile and test-run on MSVC++
  1269.  *
  1270.  * ==========================================================================
  1271.  */