1#if defined(CORELIB___NCBIDIAG__HPP)  &&  !defined(CORELIB___NCBIDIAG__INL)
2#define CORELIB___NCBIDIAG__INL
3
4/*  $Id: ncbidiag.inl 627019 2021-03-08 17:25:17Z ivanov $
5 * ===========================================================================
6 *
7 *                            PUBLIC DOMAIN NOTICE
8 *               National Center for Biotechnology Information
9 *
10 *  This software/database is a "United States Government Work" under the
11 *  terms of the United States Copyright Act.  It was written as part of
12 *  the author's official duties as a United States Government employee and
13 *  thus cannot be copyrighted.  This software/database is freely available
14 *  to the public for use. The National Library of Medicine and the U.S.
15 *  Government have not placed any restriction on its use or reproduction.
16 *
17 *  Although all reasonable efforts have been taken to ensure the accuracy
18 *  and reliability of the software and data, the NLM and the U.S.
19 *  Government do not and cannot warrant the performance or results that
20 *  may be obtained by using this software or data. The NLM and the U.S.
21 *  Government disclaim all warranties, express or implied, including
22 *  warranties of performance, merchantability or fitness for any particular
23 *  purpose.
24 *
25 *  Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author:  Denis Vakatov
30 *
31 * File Description:
32 *   NCBI C++ diagnostic API
33 *
34 */
35
36
37/////////////////////////////////////////////////////////////////////////////
38// WARNING -- all the beneath is for INTERNAL "ncbidiag" use only,
39//            and any classes, typedefs and even "extern" functions and
40//            variables declared in this file should not be used anywhere
41//            but inside "ncbidiag.inl" and/or "ncbidiag.cpp"!!!
42/////////////////////////////////////////////////////////////////////////////
43
44
45//////////////////////////////////////////////////////////////////
46// CDiagBuffer
47// (can be accessed only by "CNcbiDiag" and "CDiagRestorer"
48// and created only by GetDiagBuffer())
49//
50
51
52class CDiagBuffer
53{
54    CDiagBuffer(const CDiagBuffer&);
55    CDiagBuffer& operator= (const CDiagBuffer&);
56
57    friend class CDiagContextThreadData;
58    friend class CDiagContext_Extra;
59
60    // Flags
61    friend bool IsSetDiagPostFlag(EDiagPostFlag flag, TDiagPostFlags flags);
62    NCBI_XNCBI_EXPORT
63    friend TDiagPostFlags         SetDiagPostAllFlags(TDiagPostFlags flags);
64    NCBI_XNCBI_EXPORT friend void SetDiagPostFlag(EDiagPostFlag flag);
65    NCBI_XNCBI_EXPORT friend void UnsetDiagPostFlag(EDiagPostFlag flag);
66    NCBI_XNCBI_EXPORT
67    friend TDiagPostFlags         SetDiagTraceAllFlags(TDiagPostFlags flags);
68    NCBI_XNCBI_EXPORT friend void SetDiagTraceFlag(EDiagPostFlag flag);
69    NCBI_XNCBI_EXPORT friend void UnsetDiagTraceFlag(EDiagPostFlag flag);
70    NCBI_XNCBI_EXPORT friend void SetDiagPostPrefix(const char* prefix);
71    NCBI_XNCBI_EXPORT friend void PushDiagPostPrefix(const char* prefix);
72    NCBI_XNCBI_EXPORT friend void PopDiagPostPrefix(void);
73
74    //
75    friend class CNcbiDiag;
76    friend const CNcbiDiag& Reset(const CNcbiDiag& diag);
77    friend const CNcbiDiag& Endm(const CNcbiDiag& diag);
78
79    // Severity
80    NCBI_XNCBI_EXPORT
81    friend EDiagSev SetDiagPostLevel(EDiagSev post_sev);
82    NCBI_XNCBI_EXPORT
83    friend EDiagSev GetDiagPostLevel(void);
84    NCBI_XNCBI_EXPORT
85    friend bool IsVisibleDiagPostLevel(EDiagSev sev);
86    NCBI_XNCBI_EXPORT
87    friend void SetDiagFixedPostLevel(EDiagSev post_sev);
88    NCBI_XNCBI_EXPORT
89    friend bool DisableDiagPostLevelChange(bool disable_change);
90    NCBI_XNCBI_EXPORT
91    friend EDiagSev SetDiagDieLevel(EDiagSev die_sev);
92    NCBI_XNCBI_EXPORT
93    friend EDiagSev GetDiagDieLevel(void);
94    NCBI_XNCBI_EXPORT
95    friend bool IgnoreDiagDieLevel(bool ignore);
96
97    // Others
98    NCBI_XNCBI_EXPORT
99    friend void SetDiagTrace(EDiagTrace how, EDiagTrace dflt);
100    NCBI_XNCBI_EXPORT
101    friend bool GetDiagTrace(void);
102    NCBI_XNCBI_EXPORT friend bool IsDiagStream(const CNcbiOstream* os);
103
104    // Handler
105    NCBI_XNCBI_EXPORT friend void
106    SetDiagHandler(CDiagHandler* handler, bool can_delete);
107    NCBI_XNCBI_EXPORT friend CDiagHandler* GetDiagHandler(bool take_ownership,
108                                                          bool* current_ownership);
109    NCBI_XNCBI_EXPORT friend bool IsSetDiagHandler(void);
110
111    // Error code information
112    NCBI_XNCBI_EXPORT
113    friend void SetDiagErrCodeInfo(CDiagErrCodeInfo* info, bool can_delete);
114    NCBI_XNCBI_EXPORT
115    friend CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership);
116    NCBI_XNCBI_EXPORT
117    friend bool IsSetDiagErrCodeInfo(void);
118
119private:
120    friend class CDiagRestorer;
121    friend class CDiagContext;
122    friend class CDiagCollectGuard;
123
124    const CNcbiDiag*   m_Diag;    // present user
125    CNcbiOstrstream*   m_Stream;  // storage for the diagnostic message
126    IOS_BASE::fmtflags m_InitialStreamFlags;
127    bool               m_InUse;   // Protection against nested posts
128
129    // user-specified string to add to each posted message
130    // (can be constructed from "m_PrefixList" after push/pop operations)
131    string m_PostPrefix;
132
133    // list of prefix strings to compose the "m_PostPrefix" from
134    typedef list<string> TPrefixList;
135    TPrefixList m_PrefixList;
136
137    CDiagBuffer(void);
138
139    //### This is a temporary workaround to allow call the destructor of
140    //### static instance of "CDiagBuffer" defined in GetDiagBuffer()
141public:
142    ~CDiagBuffer(void);
143private:
144    //###
145
146    // formatted output
147    template<class X> void Put(const CNcbiDiag& diag, const X& x) {
148        if ( SetDiag(diag) )
149            (*m_Stream) << x;
150    }
151
152    NCBI_XNCBI_EXPORT
153    void Flush  (void);
154    void PrintMessage(SDiagMessage& mess, const CNcbiDiag& diag);
155    void Reset  (const CNcbiDiag& diag);   // reset content of the diag.message
156    void EndMess(const CNcbiDiag& diag);   // output current diag. message
157    NCBI_XNCBI_EXPORT
158    bool SetDiag(const CNcbiDiag& diag);
159
160    // flush & detach the current user
161    void Detach(const CNcbiDiag* diag);
162
163    // compose the post prefix using "m_PrefixList"
164    void UpdatePrefix(void);
165
166    // the bitwise OR combination of "EDiagPostFlag"
167    // Hidden inside the function to adjust default flags depending on
168    // registry/environment.
169    // inline version
170    static TDiagPostFlags& sx_GetPostFlags(void);
171    // non-inline version
172    NCBI_XNCBI_EXPORT
173    static TDiagPostFlags& s_GetPostFlags(void);
174    // extra flags ORed in for traces
175    static TDiagPostFlags sm_TraceFlags;
176
177    // static members
178    static EDiagSev       sm_PostSeverity;
179    static EDiagSevChange sm_PostSeverityChange;
180                                           // severity level changing status
181    static bool           sm_IgnoreToDie;
182    static EDiagSev       sm_DieSeverity;
183    static EDiagTrace     sm_TraceDefault; // default state of tracing
184    static bool           sm_TraceEnabled; // current state of tracing
185                                           // (enable/disable)
186
187    static bool GetTraceEnabled(void);     // dont access sm_TraceEnabled
188                                           // directly
189    static bool GetTraceEnabledFirstTime(void);
190    static bool GetSeverityChangeEnabledFirstTime(void);
191    // Anything not disabled but also not printable is collectable.
192    static bool SeverityDisabled(EDiagSev sev);
193    static bool SeverityPrintable(EDiagSev sev);
194
195    // call the current diagnostics handler directly
196    static void DiagHandler(SDiagMessage& mess);
197
198    // Symbolic name for the severity levels(used by CNcbiDiag::SeverityName)
199    NCBI_XNCBI_EXPORT
200    static const char* sm_SeverityName[eDiag_Trace+1];
201
202    // Application-wide diagnostic handler
203    static CDiagHandler* sm_Handler;
204    static bool          sm_CanDeleteHandler;
205
206    // Error codes info
207    static CDiagErrCodeInfo* sm_ErrCodeInfo;
208    static bool              sm_CanDeleteErrCodeInfo;
209
210    friend NCBI_XNCBI_EXPORT
211        CDiagContext_Extra g_PostPerf(int                       status,
212                                      double                    timespan,
213                                      SDiagMessage::TExtraArgs& args);
214};
215
216extern CDiagBuffer& GetDiagBuffer(void);
217
218
219///////////////////////////////////////////////////////
220//  CDiagCompileInfo
221
222inline const char* CDiagCompileInfo::GetFile (void) const
223{
224    return m_File;
225}
226
227inline const char* CDiagCompileInfo::GetModule(void) const
228{
229    return m_Module;
230}
231
232inline int CDiagCompileInfo::GetLine(void) const
233{
234    return m_Line;
235}
236
237inline const string& CDiagCompileInfo::GetClass(void) const
238{
239    if (!m_ClassSet  &&  !m_Parsed) {
240        ParseCurrFunctName();
241    }
242    return m_ClassName;
243}
244
245inline const string& CDiagCompileInfo::GetFunction(void) const
246{
247    if (!m_Parsed) {
248        ParseCurrFunctName();
249    }
250    return m_FunctName;
251}
252
253
254///////////////////////////////////////////////////////
255//  CNcbiDiag::
256
257template<class X>
258inline
259const CNcbiDiag& CNcbiDiag::Put(const volatile void*, const X& x) const
260{
261    m_Buffer.Put(*this, x);
262    return *this;
263}
264
265
266inline const CNcbiDiag& CNcbiDiag::operator<< (FIosbaseManip manip) const
267{
268    m_Buffer.Put(*this, manip);
269    return *this;
270}
271
272inline const CNcbiDiag& CNcbiDiag::operator<< (FIosManip manip) const
273{
274    m_Buffer.Put(*this, manip);
275    return *this;
276}
277
278
279inline const CNcbiDiag& CNcbiDiag::SetLine(size_t line) const {
280    m_CompileInfo.SetLine((int)line);
281    return *this;
282}
283
284inline const CNcbiDiag& CNcbiDiag::SetErrorCode(int code, int subcode) const {
285    m_ErrCode = code;
286    m_ErrSubCode = subcode;
287    return *this;
288}
289
290inline EDiagSev CNcbiDiag::GetSeverity(void) const {
291    return m_Severity;
292}
293
294inline const char* CNcbiDiag::GetModule(void) const
295{
296    return m_CompileInfo.GetModule();
297}
298
299inline const char* CNcbiDiag::GetFile(void) const
300{
301    return m_CompileInfo.GetFile();
302}
303
304inline const char* CNcbiDiag::GetClass(void) const
305{
306    return m_CompileInfo.GetClass().c_str();
307}
308
309inline const char* CNcbiDiag::GetFunction(void) const
310{
311    return m_CompileInfo.GetFunction().c_str();
312}
313
314inline size_t CNcbiDiag::GetLine(void) const {
315    return m_CompileInfo.GetLine();
316}
317
318inline int CNcbiDiag::GetErrorCode(void) const {
319    return m_ErrCode;
320}
321
322inline int CNcbiDiag::GetErrorSubCode(void) const {
323    return m_ErrSubCode;
324}
325
326inline TDiagPostFlags CNcbiDiag::GetPostFlags(void) const {
327    return (m_PostFlags & eDPF_Default) ?
328        (m_PostFlags | CDiagBuffer::s_GetPostFlags()) & ~eDPF_Default :
329        m_PostFlags;
330}
331
332inline void CNcbiDiag::SetAllPostFlags(TDiagPostFlags flags) const {
333    m_PostFlags = flags;
334}
335
336inline TDiagPostFlags CNcbiDiag::SetPostFlags(TDiagPostFlags flags) const {
337    return (m_PostFlags = (GetPostFlags() | flags));
338}
339
340inline TDiagPostFlags CNcbiDiag::ResetPostFlags(TDiagPostFlags flags) const {
341    return (m_PostFlags = (GetPostFlags() & ~flags));
342}
343
344inline
345const char* CNcbiDiag::SeverityName(EDiagSev sev) {
346    return CDiagBuffer::sm_SeverityName[sev];
347}
348
349
350///////////////////////////////////////////////////////
351//  ErrCode - class for manipulator ErrCode
352
353inline
354void CNcbiDiag::x_EndMess(void) const
355{
356    m_Buffer.EndMess(*this);
357}
358
359inline
360const CNcbiDiag& CNcbiDiag::Put(const ErrCode*, const ErrCode& err_code) const
361{
362    x_EndMess();
363    return SetErrorCode(err_code.m_Code, err_code.m_SubCode);
364}
365
366inline
367bool operator< (const ErrCode& ec1, const ErrCode& ec2)
368{
369    return (ec1.m_Code == ec2.m_Code)
370        ? (ec1.m_SubCode < ec2.m_SubCode)
371        : (ec1.m_Code < ec2.m_Code);
372}
373
374
375///////////////////////////////////////////////////////
376//  Other CNcbiDiag:: manipulators
377
378inline
379const CNcbiDiag& CNcbiDiag::Put(const Severity*,
380                                const Severity& severity) const
381{
382    x_EndMess();
383    m_Severity = severity.m_Level;
384    return *this;
385}
386
387inline
388const CNcbiDiag& CNcbiDiag::Put(const NCBI_NS_NCBI::SetPostFlags*,
389                                const NCBI_NS_NCBI::SetPostFlags& flags) const
390{
391    x_EndMess();
392    SetPostFlags(flags.m_Flags);
393    return *this;
394}
395
396inline
397const CNcbiDiag& Reset(const CNcbiDiag& diag)  {
398    diag.m_Buffer.Reset(diag);
399    diag.ResetIsMessageFlag();
400    diag.ResetIsConsoleFlag();
401    diag.SetErrorCode(0, 0);
402    return diag;
403}
404
405inline
406const CNcbiDiag& Endm(const CNcbiDiag& diag)  {
407    if ( !diag.m_Buffer.m_Diag
408        && (diag.GetErrorCode() || diag.GetErrorSubCode()) ) {
409        diag.m_Buffer.SetDiag(diag);
410    }
411    diag.m_Buffer.EndMess(diag);
412    return diag;
413}
414
415// No-return version of Endm(), used in ERR_FATAL* set of macros
416NCBI_NORETURN NCBI_XNCBI_EXPORT
417void EndmFatal(const CNcbiDiag& diag);
418
419inline
420const CNcbiDiag& Info(const CNcbiDiag& diag)  {
421    diag.x_EndMess();
422    diag.m_Severity = eDiag_Info;
423    return diag;
424}
425inline
426const CNcbiDiag& Warning(const CNcbiDiag& diag)  {
427    diag.x_EndMess();
428    diag.m_Severity = eDiag_Warning;
429    return diag;
430}
431inline
432const CNcbiDiag& Error(const CNcbiDiag& diag)  {
433    diag.x_EndMess();
434    diag.m_Severity = eDiag_Error;
435    return diag;
436}
437inline
438const CNcbiDiag& Critical(const CNcbiDiag& diag)  {
439    diag.x_EndMess();
440    diag.m_Severity = eDiag_Critical;
441    return diag;
442}
443inline
444const CNcbiDiag& Fatal(const CNcbiDiag& diag)  {
445    diag.x_EndMess();
446    diag.m_Severity = eDiag_Fatal;
447    return diag;
448}
449inline
450const CNcbiDiag& Trace(const CNcbiDiag& diag)  {
451    diag.x_EndMess();
452    diag.m_Severity = eDiag_Trace;
453    return diag;
454}
455inline
456const CNcbiDiag& Message(const CNcbiDiag& diag)  {
457    diag.x_EndMess();
458    diag.m_PostFlags |= eDPF_IsNote;
459    return diag;
460}
461inline
462const CNcbiDiag& Note(const CNcbiDiag& diag) {
463    diag.x_EndMess();
464    diag.m_PostFlags |= eDPF_IsNote;
465    return diag;
466}
467inline
468const CNcbiDiag& Console(const CNcbiDiag& diag)  {
469    diag.x_EndMess();
470    diag.m_PostFlags |= eDPF_IsConsole;
471    return diag;
472}
473
474inline
475const CNcbiDiag& StackTrace (const CNcbiDiag& diag) {
476    CStackTrace stk;
477    diag.Put(NULL,stk);
478    return diag;
479}
480
481
482
483///////////////////////////////////////////////////////
484//  CDiagBuffer::
485
486inline
487void CDiagBuffer::Reset(const CNcbiDiag& diag) {
488    if (&diag == m_Diag) {
489        m_Stream->rdbuf()->PUBSEEKOFF(0, IOS_BASE::beg, IOS_BASE::out);
490    }
491}
492
493inline
494void CDiagBuffer::EndMess(const CNcbiDiag& diag) {
495    if (&diag == m_Diag) {
496        // Flush();
497        Detach(&diag);
498        diag.SetErrorCode(0, 0);
499    }
500}
501
502inline
503void CDiagBuffer::Detach(const CNcbiDiag* diag) {
504    if (diag == m_Diag) {
505        Flush();
506        m_Diag = 0;
507    }
508}
509
510inline
511bool CDiagBuffer::GetTraceEnabled(void) {
512    return (sm_TraceDefault == eDT_Default) ?
513        GetTraceEnabledFirstTime() : sm_TraceEnabled;
514}
515
516
517///////////////////////////////////////////////////////
518//  EDiagPostFlag::
519
520inline
521bool IsSetDiagPostFlag(EDiagPostFlag flag, TDiagPostFlags flags) {
522    if (flags & eDPF_Default)
523        flags |= CDiagBuffer::s_GetPostFlags();
524    return (flags & flag) != 0;
525}
526
527
528///////////////////////////////////////////////////////
529//  CDiagErrCodeInfo::
530
531
532inline
533CDiagErrCodeInfo::CDiagErrCodeInfo(void)
534{
535    return;
536}
537
538
539inline
540CDiagErrCodeInfo::CDiagErrCodeInfo(const string& file_name)
541{
542    if ( !Read(file_name) ) {
543        throw runtime_error
544            ("CDiagErrCodeInfo::  failed to read error descriptions from file "
545             + file_name);
546    }
547}
548
549
550inline
551CDiagErrCodeInfo::CDiagErrCodeInfo(CNcbiIstream& is)
552{
553    if ( !Read(is) ) {
554        throw runtime_error
555            ("CDiagErrCodeInfo::  failed to read error descriptions");
556    }
557}
558
559
560inline
561CDiagErrCodeInfo::~CDiagErrCodeInfo(void)
562{
563    Clear();
564}
565
566
567inline
568void CDiagErrCodeInfo::Clear(void)
569{
570    m_Info.clear();
571}
572
573
574inline
575void CDiagErrCodeInfo::SetDescription
576(const ErrCode&                 err_code,
577 const SDiagErrCodeDescription& description)
578{
579    m_Info[err_code] = description;
580}
581
582
583inline
584bool CDiagErrCodeInfo::HaveDescription(const ErrCode& err_code) const
585{
586    return m_Info.find(err_code) != m_Info.end();
587}
588
589
590/////////////////////////////////////////////////////////////////////////////
591/// MDiagModuleCpp::
592
593/*inline
594const CNcbiDiag& operator<< (const CNcbiDiag&      diag,
595                             const MDiagModuleCpp& module)
596{
597    if(module.m_Module)
598        diag.SetModule(module.m_Module);
599    return diag;
600    }*/
601
602
603/////////////////////////////////////////////////////////////////////////////
604/// MDiagModule::
605
606inline
607MDiagModule::MDiagModule(const char* module)
608    : m_Module(module)
609{
610}
611
612
613inline
614const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagModule& module)
615{
616    return diag.SetModule(module.m_Module);
617}
618
619
620
621/////////////////////////////////////////////////////////////////////////////
622/// MDiagClass::
623
624inline
625MDiagClass::MDiagClass(const char* nclass)
626    : m_Class(nclass)
627{
628}
629
630
631inline
632const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagClass& nclass)
633{
634    return diag.SetClass(nclass.m_Class);
635}
636
637
638
639/////////////////////////////////////////////////////////////////////////////
640/// MDiagFunction::
641
642inline
643MDiagFunction::MDiagFunction(const char* function)
644    : m_Function(function)
645{
646}
647
648
649inline
650const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagFunction& function)
651{
652    return diag.SetFunction(function.m_Function);
653}
654
655
656// The function should not be called directly, use performance guard instead.
657// The 'args' list elements will be moved to the CDiagContext_Extra.
658NCBI_XNCBI_EXPORT
659extern CDiagContext_Extra g_PostPerf(int                       status,
660                                     double                    timespan,
661                                     SDiagMessage::TExtraArgs& args);
662
663#endif /* def CORELIB___NCBIDIAG__HPP  &&  ndef CORELIB___NCBIDIAG__INL */
664