1 #ifndef NCBIEXPT__HPP
2 #define NCBIEXPT__HPP
3 
4 /*  $Id: ncbiexpt.hpp 605495 2020-04-11 04:31:07Z lavr $
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  *
32  */
33 
34 /// @file ncbiexpt.hpp
35 /// Defines NCBI C++ exception handling.
36 ///
37 /// Contains support for the NCBI C++ exception handling mechanisms and
38 /// auxiliary ad hoc macros to "catch" certain types of errors, and macros for
39 /// the C++ exception specification.
40 
41 
42 #include <corelib/ncbimisc.hpp>
43 #include <errno.h>
44 #include <string.h>
45 #include <typeinfo>
46 
47 #ifdef NCBI_OS_MSWIN
48 #  include <corelib/ncbi_os_mswin.hpp>
49 #endif
50 
51 /** @addtogroup Exception
52  *
53  * @{
54  */
55 
56 
57 BEGIN_NCBI_SCOPE
58 
59 
60 /// Do not use 'throw' dynamic exception specification for C++11 compilers
61 #if defined(NCBI_USE_THROW_SPEC)  &&  defined(NCBI_HAVE_CXX11)
62 #  undef NCBI_USE_THROW_SPEC
63 #endif
64 
65 /// Define THROWS macros for C++ exception specification.
66 ///
67 /// Define use of C++ exception specification mechanism:
68 ///   "f(void) throw();"       <==  "f(void) THROWS_NONE;"
69 ///   "g(void) throw(e1,e2);"  <==  "f(void) THROWS((e1,e2));"
70 #ifdef NCBI_USE_THROW_SPEC
71 #  define THROWS_NONE throw()
72 #  define THROWS(x)   throw x
73 #else
74 #  define THROWS_NONE
75 #  define THROWS(x)
76 #endif
77 
78 
79 /// ABORT_ON_THROW controls if program should be aborted.
80 #define ABORT_ON_THROW "ABORT_ON_THROW"
81 
82 /// Specify whether to call "abort()" inside the DoThrowTraceAbort().
83 ///
84 /// By default, this feature is not activated unless
85 /// -  environment variable $ABORT_ON_THROW is set (to any value), or
86 /// -  registry value of ABORT_ON_THROW, section DEBUG is set (to any value)
87 NCBI_XNCBI_EXPORT
88 extern void SetThrowTraceAbort(bool abort_on_throw_trace);
89 
90 /// "abort()" the program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
91 NCBI_XNCBI_EXPORT
92 extern void DoThrowTraceAbort(void);
93 
94 /// Print the specified debug message.
95 NCBI_XNCBI_EXPORT
96 extern void DoDbgPrint(const CDiagCompileInfo& info, const char* message);
97 
98 /// Print the specified debug message.
99 NCBI_XNCBI_EXPORT
100 extern void DoDbgPrint(const CDiagCompileInfo& info, const string& message);
101 
102 /// Print the specified debug messages.
103 NCBI_XNCBI_EXPORT
104 extern void DoDbgPrint(const CDiagCompileInfo& info,
105     const char* msg1, const char* msg2);
106 
107 #if defined(_DEBUG)
108 
109 /// Rethrow trace.
110 ///
111 /// Reason for do {...} while in macro definition is to permit a natural
112 /// syntax usage when a user wants to write something like:
113 ///
114 /// if (expression)
115 ///     RETHROW_TRACE;
116 /// else do_something_else;
117 ///
118 /// Example:
119 /// -  RETHROW_TRACE;
120 #  define RETHROW_TRACE                         \
121     do {                                        \
122         _TRACE("EXCEPTION: re-throw");          \
123         NCBI_NS_NCBI::DoThrowTraceAbort();      \
124         throw;                                  \
125     } while(0)
126 
127 
128 /////////////////////////////////
129 // New style throw-trace macros.
130 //
131 
132 BEGIN_NAMESPACE(ncbi_throw_trace);
133 
134 // Helper class for detecting exceptions with what() method defined.
135 template<class T, class = T>
136 struct is_exception : false_type {};
137 template<class T>
138 struct is_exception<T, typename enable_if<
139     is_member_function_pointer<decltype(&T::what)>::value,
140     T>::type> : true_type {};
141 
142 // Helper class for detecting classes with output operator defined.
143 template<class T>
144 struct has_no_output_operator_impl {
145     template<class V> static auto check(const V&) -> decltype(declval<ostream&>() << declval<V>());
146     template<typename> static bool check(...);
147     using type = typename is_same<bool, decltype(check<T>(declval<T>()))>::type;
148 };
149 template<class T>
150 struct has_no_output_operator : has_no_output_operator_impl<T>::type {};
151 template<class T, class = T>
152 struct has_output_operator : false_type {};
153 template<class T>
154 struct has_output_operator<T, typename enable_if<
155     !has_no_output_operator_impl<T>::type::value,
156     T>::type> : true_type {};
157 
158 // Helper class for detecting printable non-exception classes.
159 template<class T, class = T>
160 struct is_printable : false_type {};
161 template<class T>
162 struct is_printable<T, typename enable_if<
163     !is_exception<T>::value &&
164     has_output_operator<T>::value,
165     T>::type> : true_type {};
166 
167 // Helper class for detecting non-printable classes (no what() or output operator).
168 template<class T, class = T>
169 struct is_non_printable : false_type {};
170 template<class T>
171 struct is_non_printable<T, typename enable_if<
172     !is_exception<T>::value && !is_printable<T>::value,
173     T>::type> : true_type {};
174 
175 END_NAMESPACE(ncbi_throw_trace);
176 
177 
178 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)179 typename enable_if<ncbi_throw_trace::is_exception<T>::value, const T&>::type DbgPrintEx(
180     const CDiagCompileInfo& info, const T& t, const char* str)
181 {
182     CNcbiDiag(info, eDiag_Trace) << str << ": " << t.what();
183     DoThrowTraceAbort();
184     return t;
185 }
186 
187 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)188 typename enable_if<ncbi_throw_trace::is_printable<T>::value, const T&>::type DbgPrintEx(
189     const CDiagCompileInfo& info, const T& t, const char* str)
190 {
191     CNcbiDiag(info, eDiag_Trace) << str << ": " << t;
192     DoThrowTraceAbort();
193     return t;
194 }
195 
196 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)197 typename enable_if<ncbi_throw_trace::is_non_printable<T>::value, const T&>::type DbgPrintEx(
198     const CDiagCompileInfo& info, const T& t, const char* str)
199 {
200     CNcbiDiag(info, eDiag_Trace) << str;
201     DoThrowTraceAbort();
202     return t;
203 }
204 
205 // Need overload for non-const char*? See old style DbgPrint() definitions.
206 inline
DbgPrintEx(const CDiagCompileInfo & info,char * str,const char *)207 char* DbgPrintEx(const CDiagCompileInfo& info, char* str, const char*)
208 {
209     CNcbiDiag(info, eDiag_Trace) << str;
210     DoThrowTraceAbort();
211     return str;
212 }
213 
214 inline
DbgPrintEx(const CDiagCompileInfo & info,const char * str,const char *)215 const char* DbgPrintEx(const CDiagCompileInfo& info, const char* str, const char*)
216 {
217     CNcbiDiag(info, eDiag_Trace) << str;
218     DoThrowTraceAbort();
219     return str;
220 }
221 
222 inline
DbgPrintEx(const CDiagCompileInfo & info,const string & str,const char *)223 const string& DbgPrintEx(const CDiagCompileInfo& info, const string& str, const char*)
224 {
225     CNcbiDiag(info, eDiag_Trace) << str;
226     DoThrowTraceAbort();
227     return str;
228 }
229 
230 
231 /// Throw trace.
232 ///
233 /// Combines diagnostic message trace and exception throwing. First the
234 /// diagnostic message is printed, and then exception is thrown.
235 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
236 ///
237 /// - If the argument has what() method defined (is an exception), the
238 ///   method is used for output.
239 /// - If the argument has output operator defined, it's printed using the
240 ///   operator.
241 /// - If the argument is non-printable, it's name is printed.
242 ///
243 /// Example:
244 /// -  THROW_TRACE_SIMPLE("Throw just a string");
245 /// -  THROW_TRACE_SIMPLE(runtime_error("message"));
246 #  define THROW_TRACE_SIMPLE(exception_object) \
247     throw NCBI_NS_NCBI::DbgPrintEx(DIAG_COMPILE_INFO, \
248                                    exception_object, #exception_object)
249 
250 /// Throw trace.
251 ///
252 /// Combines diagnostic message trace and exception throwing. First the
253 /// diagnostic message is printed, and then exception is thrown.
254 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
255 ///
256 /// Arguments can be any class with the specified initialization arguments.
257 ///
258 /// - If the argument has what() method defined (is an exception), the
259 ///   method is used for output.
260 /// - If the argument has output operator defined, it's printed using the
261 ///   operator.
262 /// - If the argument is non-printable, it's name is printed.
263 ///
264 /// Example:
265 /// -  THROW_TRACE_ARGS(runtime_error, "Something is weird...");
266 /// -  THROW_TRACE_ARGS(CParseException, ("Some parse error", 123));
267 /// @sa
268 ///   THROW_TRACE_SIMPLE
269 #  define THROW_TRACE_ARGS(exception_class, ...) \
270     throw NCBI_NS_NCBI::DbgPrintEx(DIAG_COMPILE_INFO, \
271                                    exception_class(__VA_ARGS__), #exception_class)
272 
273 
274 /////////////////////////////////
275 // Old style throw-trace macros.
276 //
277 
278 /// Templated function for printing debug message.
279 ///
280 /// Print debug message for the specified exception type and "abort()" the
281 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
282 template<typename T>
283 inline
DbgPrint(const CDiagCompileInfo & info,const T & e,const char * e_str)284 const T& DbgPrint(const CDiagCompileInfo& info,
285     const T& e, const char* e_str)
286 {
287     DoDbgPrint(info, e_str, e.what());
288     return e;
289 }
290 
291 /// Print debug message for "const char*" object and "abort()" the
292 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
293 inline
DbgPrint(const CDiagCompileInfo & info,const char * e,const char *)294 const char* DbgPrint(const CDiagCompileInfo& info,
295     const char* e, const char*)
296 {
297     DoDbgPrint(info, e);
298     return e;
299 }
300 
301 /// Print debug message for "char*" object and "abort()" the
302 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
303 inline
DbgPrint(const CDiagCompileInfo & info,char * e,const char *)304 char* DbgPrint(const CDiagCompileInfo& info,
305     char* e, const char*)
306 {
307     DoDbgPrint(info, e);
308     return e;
309 }
310 
311 /// Print debug message for "std::string" object and "abort()" the
312 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
313 inline
DbgPrint(const CDiagCompileInfo & info,const string & e,const char *)314 const string& DbgPrint(const CDiagCompileInfo& info,
315     const string& e, const char*)
316 {
317     DoDbgPrint(info, e);
318     return e;
319 }
320 
321 /// Print the specified printable object and "abort()" the program if set by
322 /// SetThrowTraceAbort() or $ABORT_ON_THROW.
323 /// The object must have stream output operator defined.
324 ///
325 /// @sa
326 ///   SetThrowTraceAbort(), DoThrowTraceAbort()
327 template<typename T>
328 inline
DbgPrintP(const CDiagCompileInfo & info,const T & e,const char * e_str)329 const T& DbgPrintP(const CDiagCompileInfo& info, const T& e, const char* e_str)
330 {
331     CNcbiDiag(info, eDiag_Trace) << e_str << ": " << e;
332     DoThrowTraceAbort();
333     return e;
334 }
335 
336 /// Create diagnostic stream for printing specified message and "abort()" the
337 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
338 ///
339 /// @sa
340 ///   DbgPrintP()
341 template<typename T>
342 inline
DbgPrintNP(const CDiagCompileInfo & info,const T & e,const char * e_str)343 const T& DbgPrintNP(const CDiagCompileInfo& info,
344     const T& e,
345     const char* e_str)
346 {
347     DoDbgPrint(info, e_str);
348     return e;
349 }
350 
351 /// Throw trace.
352 ///
353 /// Combines diagnostic message trace and exception throwing. First the
354 /// diagnostic message is printed, and then exception is thrown.
355 ///
356 /// Argument can be a simple string, or an exception object printed using
357 /// what() method.
358 ///
359 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
360 ///
361 /// Example:
362 /// -  THROW0_TRACE("Throw just a string");
363 /// -  THROW0_TRACE(runtime_error("message"));
364 #  define THROW0_TRACE(exception_object) \
365     throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO, \
366                                  exception_object, #exception_object)
367 
368 /// Throw trace.
369 ///
370 /// Combines diagnostic message trace and exception throwing. First the
371 /// diagnostic message is printed, and then exception is thrown.
372 ///
373 /// Argument can be any printable object; that is, any object with a defined
374 /// output operator.
375 ///
376 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
377 ///
378 /// Example:
379 /// -  THROW0p_TRACE(123);
380 /// -  THROW0p_TRACE(complex(1,2));
381 /// @sa
382 ///   THROW0np_TRACE
383 #  define THROW0p_TRACE(exception_object) \
384     throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO, \
385                                   exception_object, #exception_object)
386 
387 /// Throw trace.
388 ///
389 /// Combines diagnostic message trace and exception throwing. First the
390 /// diagnostic message is printed, and then exception is thrown.
391 ///
392 /// Argument can be any object; its name is printed.
393 ///
394 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
395 ///
396 /// Example:
397 /// -  THROW0np_TRACE(vector<char>());
398 /// @sa
399 ///   THROW0p_TRACE
400 #  define THROW0np_TRACE(exception_object) \
401     throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO, \
402                                    exception_object, #exception_object)
403 
404 /// Throw trace.
405 ///
406 /// Combines diagnostic message trace and exception throwing. First the
407 /// diagnostic message is printed, and then exception is thrown.
408 ///
409 /// Arguments can be any exception class with the specified initialization
410 /// argument. The class argument need not be derived from std::exception
411 /// but must have what() method used for output.
412 ///
413 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
414 ///
415 /// Example:
416 /// -  THROW1_TRACE(runtime_error, "Something is weird...");
417 #  define THROW1_TRACE(exception_class, exception_arg) \
418     throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO, \
419                                  exception_class(exception_arg), #exception_class)
420 
421 /// Throw trace.
422 ///
423 /// Combines diagnostic message trace and exception throwing. First the
424 /// diagnostic message is printed, and then exception is thrown.
425 ///
426 /// Arguments can be any exception class with the specified initialization
427 /// argument. The class argument need not be derived from std::exception but
428 /// must have stream output operator defined.
429 ///
430 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
431 ///
432 /// Example:
433 /// -  THROW1p_TRACE(int, 32);
434 /// @sa
435 ///   THROW1np_TRACE
436 #  define THROW1p_TRACE(exception_class, exception_arg) \
437     throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO,    \
438                                   exception_class(exception_arg), #exception_class)
439 
440 /// Throw trace.
441 ///
442 /// Combines diagnostic message trace and exception throwing. First the
443 /// diagnostic message is printed, and then exception is thrown.
444 ///
445 /// Arguments can be any exception class with the specified initialization
446 /// argument. The class argument need not be derived from std::exception,
447 /// class name is printed.
448 ///
449 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
450 ///
451 /// Example:
452 /// -  THROW1np_TRACE(CUserClass, "argument");
453 #  define THROW1np_TRACE(exception_class, exception_arg) \
454     throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO,    \
455                                    exception_class(exception_arg), #exception_class)
456 
457 /// Throw trace.
458 ///
459 /// Combines diagnostic message trace and exception throwing. First the
460 /// diagnostic message is printed, and then exception is thrown.
461 ///
462 /// Arguments can be any exception class with the specified initialization
463 /// argument. The class argument need not be derived from std::exception
464 /// but must have what() method used for output.
465 ///
466 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
467 ///
468 /// Similar to THROW1_TRACE except that the exception class can have multiple
469 /// initialization arguments instead of just one.
470 ///
471 /// Example:
472 /// -  THROW_TRACE(bad_alloc, ());
473 /// -  THROW_TRACE(runtime_error, ("Something is weird..."));
474 /// -  THROW_TRACE(CParseException, ("Some parse error", 123));
475 /// @sa
476 ///   THROW1_TRACE
477 #  define THROW_TRACE(exception_class, exception_args) \
478     throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO,    \
479                                  exception_class exception_args, #exception_class)
480 
481 /// Throw trace.
482 ///
483 /// Combines diagnostic message trace and exception throwing. First the
484 /// diagnostic message is printed, and then exception is thrown.
485 ///
486 /// Arguments can be any exception class with the specified initialization
487 /// argument. The class argument need not be derived from std::exception but
488 /// must have stream output operator defined.
489 ///
490 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
491 ///
492 /// Similar to THROW1p_TRACE except that the exception class can have multiple
493 /// initialization arguments instead of just one.
494 ///
495 /// Example:
496 /// - THROWp_TRACE(complex, (2, 3));
497 /// @sa
498 ///   THROW1p_TRACE
499 #  define THROWp_TRACE(exception_class, exception_args) \
500     throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO,    \
501                                   exception_class exception_args, #exception_class)
502 
503 /// Throw trace.
504 ///
505 /// Combines diagnostic message trace and exception throwing. First the
506 /// diagnostic message is printed, and then exception is thrown.
507 ///
508 /// Arguments can be any exception class with the specified initialization
509 /// argument. The class argument need not be derived from std::exception,
510 /// class name is printed.
511 ///
512 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
513 ///
514 /// Similar to THROW1np_TRACE except that the exception class can have multiple
515 /// initialization arguments instead of just one.
516 ///
517 /// Example:
518 /// -  THROWnp_TRACE(CUserClass, (arg1, arg2));
519 #  define THROWnp_TRACE(exception_class, exception_args) \
520     throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO,    \
521                                    exception_class exception_args, #exception_class)
522 
523 
524 #else  /* _DEBUG */
525 
526 // Release-mode versions of the above macros: no trace logging, and no abort().
527 
528 #  define RETHROW_TRACE                                     \
529     throw
530 
531 #  define THROW_TRACE_SIMPLE(exception_object)              \
532     throw exception_object
533 #  define THROW_TRACE_ARGS(exception_class, ...)            \
534     throw exception_class(__VA_ARGS__)
535 
536 #  define THROW0_TRACE(exception_object)                    \
537     throw exception_object
538 #  define THROW0p_TRACE(exception_object)                   \
539     throw exception_object
540 #  define THROW0np_TRACE(exception_object)                  \
541     throw exception_object
542 #  define THROW1_TRACE(exception_class, exception_arg)      \
543     throw exception_class(exception_arg)
544 #  define THROW1p_TRACE(exception_class, exception_arg)     \
545     throw exception_class(exception_arg)
546 #  define THROW1np_TRACE(exception_class, exception_arg)    \
547     throw exception_class(exception_arg)
548 #  define THROW_TRACE(exception_class, exception_args)      \
549     throw exception_class exception_args
550 #  define THROWp_TRACE(exception_class, exception_args)     \
551     throw exception_class exception_args
552 #  define THROWnp_TRACE(exception_class, exception_args)    \
553     throw exception_class exception_args
554 
555 #endif  /* else!_DEBUG */
556 
557 
558 /// Standard handling of "exception"-derived exceptions.
559 /// This macro is deprecated - use *_X or *_XX variant instead of it.
560 #define STD_CATCH(message)                                    \
561     catch (NCBI_NS_STD::exception& e) {                       \
562         NCBI_NS_NCBI::CNcbiDiag()                             \
563             << NCBI_NS_NCBI::Error                            \
564             << "[" << message << "] Exception: " << e.what(); \
565     }
566 
567 /// Standard handling of "exception"-derived exceptions; catches non-standard
568 /// exceptions and generates "unknown exception" for all other exceptions.
569 /// This macro is deprecated - use *_X or *_XX variant instead of it.
570 #define STD_CATCH_ALL(message)                                \
571     STD_CATCH(message)                                        \
572     catch (...) {                                             \
573         NCBI_NS_NCBI::CNcbiDiag()                             \
574            << NCBI_NS_NCBI::Error                             \
575            << "[" << message << "] Unknown exception";        \
576     }
577 
578 /// Catch CExceptions as well
579 /// This macro is deprecated - use *_X or *_XX variant instead of it.
580 #define NCBI_CATCH(message)                                   \
581     catch (NCBI_NS_NCBI::CException& e) {                     \
582         NCBI_REPORT_EXCEPTION(message, e);                    \
583     }                                                         \
584     STD_CATCH(message)
585 
586 /// This macro is deprecated - use *_X or *_XX variant instead of it.
587 #define NCBI_CATCH_ALL(message)                               \
588     catch (NCBI_NS_NCBI::CException& e) {                     \
589         NCBI_REPORT_EXCEPTION(message, e);                    \
590     }                                                         \
591     STD_CATCH_ALL(message)
592 
593 
594 /// Standard handling of "exception"-derived exceptions
595 /// with default error code and given error subcode placed in diagnostics.
596 /// Default error code is used and error subcode checking for correctness
597 /// is made in same way as in ERR_POST_X macro.
598 ///
599 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_X
600 #define STD_CATCH_X(err_subcode, message)                     \
601     STD_CATCH_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
602 
603 /// Standard handling of "exception"-derived exceptions; catches non-standard
604 /// exceptions and generates "unknown exception" for all other exceptions.
605 /// With default error code and given error subcode placed in diagnostics
606 ///
607 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
608 #define STD_CATCH_ALL_X(err_subcode, message)                 \
609     STD_CATCH_ALL_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
610 
611 /// Catch CExceptions as well
612 /// with default error code and given error subcode placed in diagnostics
613 ///
614 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
615 #define NCBI_CATCH_X(err_subcode, message)                    \
616     NCBI_CATCH_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
617 
618 /// @sa STD_CATCH_ALL_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
619 #define NCBI_CATCH_ALL_X(err_subcode, message)                \
620     NCBI_CATCH_ALL_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
621 
622 /// Standard handling of "exception"-derived exceptions
623 /// with given error code name and given error subcode placed in diagnostics
624 ///
625 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
626 #define STD_CATCH_XX(err_name, err_subcode, message)                 \
627     catch (NCBI_NS_STD::exception& e) {                              \
628         NCBI_CHECK_ERR_SUBCODE_X_NAME(err_name, err_subcode);        \
629         NCBI_NS_NCBI::CNcbiDiag()                                    \
630             << ErrCode(NCBI_ERRCODE_X_NAME(err_name), err_subcode)   \
631             << NCBI_NS_NCBI::Error                                   \
632             << "[" << message << "] Exception: " << e.what();        \
633     }
634 
635 /// Standard handling of "exception"-derived exceptions; catches non-standard
636 /// exceptions and generates "unknown exception" for all other exceptions.
637 /// With given error code name and given error subcode placed in diagnostics
638 ///
639 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
640 #define STD_CATCH_ALL_XX(err_name, err_subcode, message)             \
641     STD_CATCH_XX(err_name, err_subcode, message)                     \
642     catch (...) {                                                    \
643         NCBI_NS_NCBI::CNcbiDiag()                                    \
644            << ErrCode(NCBI_ERRCODE_X_NAME(err_name), err_subcode)    \
645            << NCBI_NS_NCBI::Error                                    \
646            << "[" << message << "] Unknown exception";               \
647     }
648 
649 /// Catch CExceptions as well
650 /// with given error code name and given error subcode placed in diagnostics
651 ///
652 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
653 #define NCBI_CATCH_XX(err_name, err_subcode, message)                 \
654     catch (NCBI_NS_NCBI::CException& e) {                             \
655         NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, message, e);  \
656     }                                                                 \
657     STD_CATCH_XX(err_name, err_subcode, message)
658 
659 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
660 #define NCBI_CATCH_ALL_XX(err_name, err_subcode, message)             \
661     catch (NCBI_NS_NCBI::CException& e) {                             \
662         NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, message, e);  \
663     }                                                                 \
664     STD_CATCH_ALL_XX(err_name, err_subcode, message)
665 
666 
667 /////////////////////////////////////////////////////////////////////////////
668 // CException: useful macros
669 
670 /// Format message using iostreams library.
671 /// This macro returns an object convertible to std::string.
672 #define FORMAT(message) \
673     NCBI_NS_NCBI::CNcbiOstrstreamToString(static_cast<NCBI_NS_NCBI::CNcbiOstrstream&>(NCBI_NS_NCBI::CNcbiOstrstream().flush() << message))
674 
675 
676 /// Create an exception instance to be thrown later, given the exception
677 /// class, previous exception pointer, error code and message string.
678 #define NCBI_EXCEPTION_VAR_EX(name, prev_exception_ptr,              \
679                               exception_class, err_code, message)    \
680     exception_class name(DIAG_COMPILE_INFO,                          \
681         prev_exception_ptr, exception_class::err_code, (message))
682 
683 /// Create an instance of the exception to be thrown later.
684 #define NCBI_EXCEPTION_VAR(name, exception_class, err_code, message) \
685     NCBI_EXCEPTION_VAR_EX(name, 0, exception_class, err_code, message)
686 
687 /// Throw an existing exception object
688 #define NCBI_EXCEPTION_THROW(exception_var)                          \
689     throw (exception_var)
690 
691 #define NCBI_EXCEPTION_EMPTY_NAME
692 
693 /// Generic macro to make an exception, given the exception class,
694 /// error code and message string.
695 #define NCBI_EXCEPTION(exception_class, err_code, message)           \
696     NCBI_EXCEPTION_VAR(NCBI_EXCEPTION_EMPTY_NAME,                    \
697                        exception_class, err_code, message)
698 
699 /// Generic macro to throw an exception, given the exception class,
700 /// error code and message string.
701 /// The err_code argument may include manipulators to set additional
702 /// options, e.g. eMyErrCode | Console | Severity(eDiag_Info). In any
703 /// case the error code value must be the first in the combination.
704 #define NCBI_THROW(exception_class, err_code, message)                  \
705     do {                                                                \
706         USING_SCOPE(NCBI_NS_NCBI::ncbi_ex_manip);                       \
707         NCBI_EXCEPTION_THROW(NCBI_EXCEPTION(exception_class, err_code,  \
708                                             message));                  \
709     } while (0)
710 
711 /// Throw a quick-and-dirty runtime exception of type 'CException' with
712 /// the given error message and error code 'eUnknown'.
713 /// This macro is intended for use only in stand-alone applications.
714 /// Library APIs should properly declare their specific exception types.
715 #define NCBI_USER_THROW(message) \
716     NCBI_THROW(NCBI_NS_NCBI::CException, eUnknown, message)
717 
718 /// The same as NCBI_THROW but with message processed as output to ostream.
719 #define NCBI_THROW_FMT(exception_class, err_code, message)      \
720     NCBI_THROW(exception_class, err_code, FORMAT(message))
721 
722 /// Throw a "user exception" with message processed as output to ostream.
723 /// See NCBI_USER_THROW for details.
724 #define NCBI_USER_THROW_FMT(message)                            \
725     NCBI_THROW_FMT(NCBI_NS_NCBI::CException, eUnknown, message)
726 
727 /// Generic macro to make an exception, given the exception class,
728 /// previous exception, error code and message string.
729 #define NCBI_EXCEPTION_EX(prev_exception, exception_class, err_code, message) \
730     NCBI_EXCEPTION_VAR_EX(NCBI_EXCEPTION_EMPTY_NAME, &(prev_exception), \
731                           exception_class, err_code, message)
732 
733 /// Generic macro to re-throw an exception.
734 /// The err_code argument may include manipulators to set additional
735 /// options, e.g. eMyErrCode | Console | Severity(eDiag_Info). In any
736 /// case the error code value must be the first in the combination.
737 #define NCBI_RETHROW(prev_exception, exception_class, err_code, message) \
738     do {                                                                \
739         USING_SCOPE(NCBI_NS_NCBI::ncbi_ex_manip);                       \
740         throw NCBI_EXCEPTION_EX(prev_exception, exception_class,        \
741                                 err_code, message);                     \
742     } while (0)
743 
744 /// The same as NCBI_RETHROW but with message processed as output to ostream.
745 #define NCBI_RETHROW_FMT(prev_exception, exception_class, err_code, message) \
746     NCBI_RETHROW(prev_exception, exception_class, err_code, FORMAT(message))
747 
748 /// Generic macro to re-throw the same exception.
749 #define NCBI_RETHROW_SAME(prev_exception, message)                \
750     do { prev_exception.AddBacklog(DIAG_COMPILE_INFO, message,    \
751                                    prev_exception.GetSeverity()); \
752     throw; }  while (0)
753 
754 /// Generate a report on the exception.
755 #define NCBI_REPORT_EXCEPTION(title, ex)                        \
756     NCBI_NS_NCBI::CExceptionReporter::ReportDefault             \
757         (DIAG_COMPILE_INFO, title, ex, NCBI_NS_NCBI::eDPF_Default)
758 
759 /// Generate a report on the exception with default error code and
760 /// given subcode.
761 #define NCBI_REPORT_EXCEPTION_X(err_subcode, title, ex)                 \
762     NCBI_REPORT_EXCEPTION_XX(NCBI_USE_ERRCODE_X, err_subcode, title, ex)
763 
764 /// Generate a report on the exception with default error code and
765 /// given subcode.
766 #define NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, title, ex)   \
767     NCBI_CHECK_ERR_SUBCODE_X_NAME(err_name, err_subcode);            \
768     NCBI_NS_NCBI::CExceptionReporter::ReportDefaultEx                \
769     (NCBI_ERRCODE_X_NAME(err_name), err_subcode,                     \
770      DIAG_COMPILE_INFO, title, ex, NCBI_NS_NCBI::eDPF_Default)
771 
772 
773 /////////////////////////////////////////////////////////////////////////////
774 // CException
775 
776 // Forward declaration of CExceptionReporter.
777 class CExceptionReporter;
778 
779 
780 // Base helper class for passing options to exceptions.
781 class CExceptionArgs_Base
782 {
783 public:
784     typedef int      TErrCodeVal;
785     typedef int      TFlags;
786     typedef EDiagSev TSeverity;
787 
CExceptionArgs_Base(void)788     CExceptionArgs_Base(void) :
789         m_ErrCode(0), m_Flags(0),
790         m_Severity(eDiag_Error), m_Retriable(eRetriable_Unknown)
791     {}
792 
SetErrCodeVal(TErrCodeVal err_code)793     void SetErrCodeVal(TErrCodeVal err_code) { m_ErrCode = err_code; }
GetErrCodeVal(void) const794     TErrCodeVal GetErrCodeVal(void) const { return m_ErrCode; }
795 
SetFlags(TFlags flags)796     void SetFlags(TFlags flags) { m_Flags = flags; }
GetFlags(void) const797     TFlags GetFlags(void) const { return m_Flags; }
798 
SetSeverity(TSeverity severity)799     void SetSeverity(TSeverity severity) { m_Severity = severity; }
GetSeverity(void) const800     TSeverity GetSeverity(void) const { return m_Severity; }
801 
SetModule(const string & module)802     void SetModule(const string& module) { m_Module = module; }
GetModule(void) const803     const string& GetModule(void) const { return m_Module; }
IsSetModule(void) const804     bool IsSetModule(void) const { return !m_Module.empty(); }
805 
SetRetriable(ERetriable retriable)806     void SetRetriable(ERetriable  retriable) { m_Retriable = retriable; }
GetRetriable(void) const807     ERetriable GetRetriable(void) const { return m_Retriable; }
808 
809 private:
810     TErrCodeVal m_ErrCode;
811     TFlags      m_Flags;
812     TSeverity   m_Severity;
813     string      m_Module;
814     ERetriable  m_Retriable;
815 };
816 
817 
818 class CExceptionArgsManip
819 {
820 public:
~CExceptionArgsManip(void)821     virtual ~CExceptionArgsManip(void) {}
822 
823     virtual void operator()(CExceptionArgs_Base& args) const = 0;
824 };
825 
826 typedef void (*FExceptionArgsManip)(CExceptionArgs_Base&);
827 
828 /// Manipulator function wrapper.
829 class CExceptionArgsManip_Wrapper : public CExceptionArgsManip
830 {
831 public:
CExceptionArgsManip_Wrapper(FExceptionArgsManip f)832     CExceptionArgsManip_Wrapper(FExceptionArgsManip f) : m_Func(f) { }
833 
operator ()(CExceptionArgs_Base & args) const834     void operator()(CExceptionArgs_Base& args) const { (*m_Func)(args); }
835 
836 private:
837     FExceptionArgsManip m_Func;
838 };
839 
840 
841 template<class TErrCode>
842 class CExceptionArgs : public CExceptionArgs_Base
843 {
844 public:
CExceptionArgs(TErrCode err_code)845     CExceptionArgs(TErrCode err_code) { SetErrCodeVal(err_code); }
846 
GetErrCode(void) const847     TErrCode GetErrCode(void) const { return TErrCode(GetErrCodeVal()); }
848 
operator |(const CExceptionArgsManip & manip)849     CExceptionArgs<TErrCode>& operator|(const CExceptionArgsManip& manip)
850     {
851         manip(*this);
852         return *this;
853     }
854 
operator |(const CExceptionArgsManip_Wrapper & manip)855     CExceptionArgs<TErrCode>& operator|(const CExceptionArgsManip_Wrapper& manip)
856     {
857         manip(*this);
858         return *this;
859     }
860 };
861 
862 
863 /////////////////////////////////////////////////////////////////////////////
864 ///
865 /// CException --
866 ///
867 /// Define an extended exception class based on the C+++ std::exception.
868 ///
869 /// CException inherits its basic functionality from std::exception and
870 /// defines additional generic error codes for applications, and error
871 /// reporting capabilities.
872 
873 class CRequestContextRef;
874 class CRequestContext;
875 
876 class NCBI_XNCBI_EXPORT CException : public std::exception
877 {
878 public:
879     /// Error types that an application can generate.
880     ///
881     /// Each derived class has its own error codes and their interpretations.
882     /// Define two generic error codes "eInvalid" and "eUnknown" to be used
883     /// by all NCBI applications.
884     enum EErrCode {
885         eInvalid = -1, ///< To be used ONLY as a return value;
886                        ///< please, NEVER throw an exception with this code.
887         eUnknown = 0   ///< Unknown exception.
888     };
889     typedef int TErrCode;
890 
891     /// Miscellaneous generic hints, flags and attributes
892     enum EFlags {
893         /// Mark the exception with this flag if the exception is supposed
894         /// to be extra-visible, such as to go to a console or a dialog
895         /// that's looked at by the end user. Naturally, the message should be
896         /// clear and informative enough to be actually helpful for the user.
897         /// If such "console" exception is passed to the diagnostic (e.g.
898         /// "ERR_POST(ex);", then the posting will be automatically marked as
899         /// "console" too (so it'll work as "ERR_POST(Console << ex);").
900         fConsole = (1 << 0)
901     };
902     typedef int TFlags;  //< Bit-wise OR of "EFlags"
903 
904     /// Constructor.
905     ///
906     /// When throwing an exception initially, "prev_exception" must be 0.
907     CException(const CDiagCompileInfo& info,
908                const CException* prev_exception,
909                EErrCode err_code,
910                const string& message,
911                EDiagSev severity = eDiag_Error,
912                TFlags flags = 0);
913 
914     CException(const CDiagCompileInfo& info,
915                const CException* prev_exception,
916                const CExceptionArgs<EErrCode>& args,
917                const string& message);
918 
919     /// Copy constructor.
920     CException(const CException& other);
921 
922     /// Add a message to backlog (to re-throw the same exception then).
923     void AddBacklog(const CDiagCompileInfo& info,
924                     const string& message,
925                     EDiagSev severity = eDiag_Error);
926 
927     void AddPrevious(const CException* prev_exception);
928     void AddToMessage(const string& add_msg);
929 
930     /// Polymorphically (re)throw an exception whose exact type is
931     /// uncertain.
932     ///
933     /// NB: for best results, *EVERY* concrete derived class in the
934     /// hierarchy must implement its *OWN* version of Throw().  (Using
935     /// NCBI_EXCEPTION_DEFAULT or a related macro will take care of
936     /// this for you.)
937     ///
938     /// Simply invoking the throw keyword with no arguments is a
939     /// better option when available (within a catch block), but there
940     /// are circumstances in which it is not.
941     NCBI_NORETURN virtual void Throw(void) const;
942 
943     // ---- Reporting --------------
944 
945     /// Standard report (includes full backlog).
946     virtual const char* what(void) const throw();
947 
948     /// Report the exception.
949     ///
950     /// Report the exception using "reporter" exception reporter.
951     /// If "reporter" is not specified (value 0), then use the default
952     /// reporter as set with CExceptionReporter::SetDefault.
953     void Report(const CDiagCompileInfo& info,
954                 const string& title, CExceptionReporter* reporter = 0,
955                 TDiagPostFlags flags = eDPF_Exception) const;
956 
957     /// Report this exception only.
958     ///
959     /// Report as a string this exception only. No backlog is attached.
960     string ReportThis(TDiagPostFlags flags = eDPF_Exception) const;
961 
962     /// Report all exceptions.
963     ///
964     /// Report as a string all exceptions. Include full backlog.
965     string ReportAll (TDiagPostFlags flags = eDPF_Exception) const;
966 
967     /// Report "standard" attributes.
968     ///
969     /// Report "standard" attributes (file, line, type, err.code, user message)
970     /// into the "out" stream (this exception only, no backlog).
971     void ReportStd(ostream& out, TDiagPostFlags flags = eDPF_Exception) const;
972 
973     /// Report "non-standard" attributes.
974     ///
975     /// Report "non-standard" attributes (those of derived class) into the
976     /// "out" stream.
977     virtual void ReportExtra(ostream& out) const;
978 
979     /// Get the saved stack trace if available or NULL.
980     const CStackTrace* GetStackTrace(void) const;
981 
982     /// Enable background reporting.
983     ///
984     /// If background reporting is enabled, then calling what() or ReportAll()
985     /// would also report exception to the default exception reporter.
986     /// @return
987     ///   The previous state of the flag.
988     static bool EnableBackgroundReporting(bool enable);
989 
990     /// Set severity level for saving and printing stack trace
991     static void SetStackTraceLevel(EDiagSev level);
992 
993     /// Get current severity level for saving and printing stack trace
994     static EDiagSev GetStackTraceLevel(void);
995 
996     // ---- Attributes ---------
997 
998     /// Get exception severity.
GetSeverity(void) const999     EDiagSev GetSeverity(void) const { return m_Severity; }
1000 
1001     /// Set exception severity.
1002     CException& SetSeverity(EDiagSev severity);
1003 
1004     /// Get class name as a string.
1005     virtual const char* GetType(void) const;
1006 
1007     /// Get error code interpreted as text.
1008     virtual const char* GetErrCodeString(void) const;
1009 
1010     /// Get file name used for reporting.
GetFile(void) const1011     const string& GetFile(void) const { return m_File; }
1012 
1013     /// Set module name used for reporting.
SetModule(const string & module)1014     void SetModule(const string& module) { m_Module = module; }
1015 
1016     /// Get module name used for reporting.
GetModule(void) const1017     const string& GetModule(void) const { return m_Module; }
1018 
1019     /// Set class name used for reporting.
SetClass(const string & nclass)1020     void SetClass(const string& nclass) { m_Class = nclass; }
1021 
1022     /// Get class name used for reporting.
GetClass(void) const1023     const string& GetClass(void) const { return m_Class; }
1024 
1025     /// Set function name used for reporting.
SetFunction(const string & function)1026     void SetFunction(const string& function) { m_Function = function; }
1027 
1028     /// Get function name used for reporting.
GetFunction(void) const1029     const string& GetFunction(void) const { return m_Function; }
1030 
1031     /// Get line number where error occurred.
GetLine(void) const1032     int GetLine(void) const { return m_Line; }
1033 
1034     /// Get error code.
1035     TErrCode GetErrCode(void) const;
1036 
1037     /// Get message string.
1038     const string& GetMsg(void) const;
1039 
1040     /// Get "previous" exception from the backlog.
GetPredecessor(void) const1041     const CException* GetPredecessor(void) const { return m_Predecessor; }
1042 
1043     /// Check if exception has main text in the chain
HasMainText(void) const1044     bool HasMainText(void) const { return m_MainText; }
1045 
1046     /// Destructor.
1047     virtual ~CException(void) throw();
1048 
1049     /// Check if the flag is set
IsSetFlag(EFlags flag) const1050     bool IsSetFlag(EFlags flag) const { return (m_Flags & flag) != 0; }
1051 
1052     /// Set flag (add to other flags)
SetFlag(EFlags flag)1053     CException& SetFlag(EFlags flag) { m_Flags |= flag; return *this; }
1054 
1055     /// Unset flag (other flags are left as is)
UnsetFlag(EFlags flag)1056     CException& UnsetFlag(EFlags flag) { m_Flags &= ~flag; return *this; }
1057 
1058     /// Get the request context in which the exception was thrown.
1059     CRequestContext& GetRequestContext(void) const;
1060 
1061     /// Set the info about ability to retry an action caused the exception
SetRetriable(ERetriable retriable)1062     void       SetRetriable(ERetriable retriable)  { m_Retriable = retriable; }
1063 
1064     /// Retrieve info about ability to retry an action caused the exception
GetRetriable(void) const1065     virtual ERetriable GetRetriable(void)  const   { return m_Retriable; }
1066 
1067 protected:
1068     /// Constructor for derived classes
1069     CException(const CDiagCompileInfo& info,
1070                const CException* prev_exception,
1071                const string& message,
1072                EDiagSev severity = eDiag_Error,
1073                TFlags flags = 0);
1074     /// Constructor with no arguments.
1075     ///
1076     /// Required in case of multiple inheritance.
1077     CException(void);
1078 
1079     /// Helper method for reporting to the system debugger.
1080     virtual void x_ReportToDebugger(void) const;
1081 
1082     /// Helper method for cloning the exception.
1083     virtual const CException* x_Clone(void) const;
1084 
1085     /// Helper method for initializing exception data.
1086     virtual void x_Init(const CDiagCompileInfo& info,
1087                         const string&           message,
1088                         const CException*       prev_exception,
1089                         EDiagSev                severity);
1090 
1091     /// Process additional arguments. Derived classes may need
1092     /// to cast args to CExceptionArgs<CDerivedException::EErrCode>.
1093     virtual void x_InitArgs(const CExceptionArgs_Base& args);
1094 
1095     /// Helper method for copying exception data.
1096     virtual void x_Assign(const CException& src);
1097 
1098     /// Helper method for assigning error code.
1099     virtual void x_AssignErrCode(const CException& src);
1100 
1101     /// Helper method for initializing error code.
1102     virtual void x_InitErrCode(CException::EErrCode err_code);
1103 
1104     /// Helper method for getting error code.
x_GetErrCode(void) const1105     virtual int  x_GetErrCode(void) const { return m_ErrCode; }
1106 
1107     /// Get and store current stack trace.
1108     void x_GetStackTrace(void);
1109 
1110     /// Warn if Throw() will end up slicing its invocant.
1111     void x_ThrowSanityCheck(const type_info& expected_type,
1112                             const char* human_name) const;
1113 
1114 private:
1115     EDiagSev    m_Severity;          ///< Severity level for the exception
1116     string      m_File;              ///< File     to report on
1117     int         m_Line;              ///< Line number
1118     int         m_ErrCode;           ///< Error code
1119     string      m_Msg;               ///< Message string
1120     string      m_Module;            ///< Module   to report on
1121     string      m_Class;             ///< Class    to report on
1122     string      m_Function;          ///< Function to report on
1123 
1124     mutable string m_What;           ///< What type of exception
1125     typedef const CException* TExceptionPtr;
1126     mutable TExceptionPtr m_Predecessor; ///< Previous exception
1127 
1128     mutable bool m_InReporter;       ///< Reporter flag
1129     mutable bool m_MainText;         ///< Exception has main text
1130     static  bool sm_BkgrEnabled;     ///< Background reporting enabled flag
1131 
1132     unique_ptr<CStackTrace> m_StackTrace; ///< Saved stack trace
1133 
1134     TFlags       m_Flags;            ///< Flags, hints, attributes
1135 
1136     ERetriable   m_Retriable;        ///< In some cases it is known for sure if
1137                                      ///< an action caused the exception can be
1138                                      ///< tried again or not. This member holds
1139                                      ///< this information.
1140 
1141     unique_ptr<CRequestContextRef> m_RequestContext;
1142 
1143     /// Private assignment operator to prohibit assignment.
1144     CException& operator= (const CException&);
1145 };
1146 
1147 
1148 /// Exception manipulators. Can be combined with error code using operator|().
1149 
1150 BEGIN_SCOPE(ncbi_ex_manip)
1151 
1152 template<class TErrCode>
1153 CExceptionArgs<TErrCode> operator|(TErrCode                   err_code,
1154                                    const CExceptionArgsManip& manip)
1155 {
1156     CExceptionArgs<TErrCode> args(err_code);
1157     manip(args);
1158     return args;
1159 }
1160 
1161 
1162 template<class TErrCode>
operator |(TErrCode err_code,const CExceptionArgsManip_Wrapper & manip)1163 CExceptionArgs<TErrCode> operator|(TErrCode                           err_code,
1164                                    const CExceptionArgsManip_Wrapper& manip)
1165 {
1166     CExceptionArgs<TErrCode> args(err_code);
1167     manip(args);
1168     return args;
1169 }
1170 
1171 
1172 inline
Console(CExceptionArgs_Base & args)1173 void Console(CExceptionArgs_Base& args)
1174 {
1175     args.SetFlags(args.GetFlags() | CException::fConsole);
1176 }
1177 
1178 inline
Trace(CExceptionArgs_Base & args)1179 void Trace(CExceptionArgs_Base& args)
1180 {
1181     args.SetSeverity(eDiag_Trace);
1182 }
1183 
1184 inline
Info(CExceptionArgs_Base & args)1185 void Info(CExceptionArgs_Base& args)
1186 {
1187     args.SetSeverity(eDiag_Info);
1188 }
1189 
1190 inline
Warning(CExceptionArgs_Base & args)1191 void Warning(CExceptionArgs_Base& args)
1192 {
1193     args.SetSeverity(eDiag_Warning);
1194 }
1195 
1196 inline
Error(CExceptionArgs_Base & args)1197 void Error(CExceptionArgs_Base& args)
1198 {
1199     args.SetSeverity(eDiag_Error);
1200 }
1201 
1202 inline
Critical(CExceptionArgs_Base & args)1203 void Critical(CExceptionArgs_Base& args)
1204 {
1205     args.SetSeverity(eDiag_Critical);
1206 }
1207 
1208 inline
Fatal(CExceptionArgs_Base & args)1209 void Fatal(CExceptionArgs_Base& args)
1210 {
1211     args.SetSeverity(eDiag_Fatal);
1212 }
1213 
1214 
1215 /// Module manipulator
1216 
1217 class Module : public CExceptionArgsManip
1218 {
1219 public:
Module(const string & module)1220     Module(const string& module) : m_Module(module) {}
Module(const char * module)1221     Module(const char* module) : m_Module(module) {}
~Module(void)1222     virtual ~Module(void) {}
1223 
operator ()(CExceptionArgs_Base & args) const1224     virtual void operator()(CExceptionArgs_Base& args) const
1225     {
1226         args.SetModule(m_Module);
1227     }
1228 
1229 private:
1230     string m_Module;
1231 };
1232 
1233 
1234 /// Retriable manipulator
1235 
1236 class Retriable : public CExceptionArgsManip
1237 {
1238 public:
Retriable(ERetriable retriable)1239     Retriable(ERetriable  retriable) : m_Retriable(retriable) {}
~Retriable(void)1240     virtual ~Retriable(void) {}
1241 
operator ()(CExceptionArgs_Base & args) const1242     virtual void operator()(CExceptionArgs_Base& args) const
1243     {
1244         args.SetRetriable(m_Retriable);
1245     }
1246 
1247 private:
1248     ERetriable  m_Retriable;
1249 };
1250 
1251 
END_SCOPE(ncbi_ex_manip) const1252 END_SCOPE(ncbi_ex_manip)
1253 
1254 
1255 /// Return valid pointer to uppermost derived class only if "from" is _really_
1256 /// the object of the desired type.
1257 ///
1258 /// Do not cast to intermediate types (return NULL if such cast is attempted).
1259 template <class TTo, class TFrom>
1260 const TTo* UppermostCast(const TFrom& from)
1261 {
1262     return typeid(from) == typeid(TTo) ? dynamic_cast<const TTo*>(&from) : 0;
1263 }
1264 
1265 #define NCBI_EXCEPTION_DEFAULT_THROW(exception_class) \
1266     NCBI_NORETURN virtual void Throw(void) const override \
1267     { \
1268         this->x_ThrowSanityCheck(typeid(exception_class), #exception_class); \
1269         throw *this; \
1270     }
1271 
1272 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1273     exception_class(const exception_class& other) \
1274        : base_class(other) \
1275     { \
1276         this->x_Assign(other); \
1277     } \
1278 public: \
1279     virtual ~exception_class(void) throw() {} \
1280     virtual const char* GetType(void) const override {return #exception_class;} \
1281     typedef int TErrCode; \
1282     TErrCode GetErrCode(void) const \
1283     { \
1284         return typeid(*this) == typeid(exception_class) ? \
1285             (TErrCode) this->x_GetErrCode() : \
1286             (TErrCode) CException::eInvalid; \
1287     } \
1288     NCBI_EXCEPTION_DEFAULT_THROW(exception_class) \
1289 protected: \
1290     exception_class(void) {} \
1291     virtual const CException* x_Clone(void) const override \
1292     { \
1293         return new exception_class(*this); \
1294     } \
1295 
1296 
1297 /// Helper macro for default exception implementation.
1298 /// @sa
1299 ///   NCBI_EXCEPTION_DEFAULT
1300 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(exception_class, base_class) \
1301     { \
1302         x_Init(info, message, prev_exception, severity); \
1303         x_InitErrCode((CException::EErrCode) err_code); \
1304     } \
1305     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1306 private: \
1307     /* for the sake of semicolon at the end of macro...*/ \
1308     static void xx_unused_##exception_class(void)
1309 
1310 
1311 /// To help declare new exception class.
1312 ///
1313 /// This can be used ONLY if the derived class does not have any additional
1314 /// (non-standard) data members.
1315 #define NCBI_EXCEPTION_DEFAULT(exception_class, base_class)             \
1316 public:                                                                 \
1317     exception_class(const CDiagCompileInfo& info,                       \
1318         const CException* prev_exception, EErrCode err_code,            \
1319         const string& message, EDiagSev severity = eDiag_Error)         \
1320         : base_class(info, prev_exception, (message), severity, 0)      \
1321     {                                                                   \
1322         x_Init(info, message, prev_exception, severity);                \
1323         x_InitErrCode((CException::EErrCode) err_code);                 \
1324     }                                                                   \
1325     exception_class(const CDiagCompileInfo& info,                       \
1326         const CException* prev_exception,                               \
1327         const CExceptionArgs<EErrCode>& args,                           \
1328         const string& message)                                          \
1329         : base_class(info, prev_exception, (message),                   \
1330           args.GetSeverity(), 0)                                        \
1331     {                                                                   \
1332         x_Init(info, message, prev_exception, args.GetSeverity());      \
1333         x_InitArgs(args);                                               \
1334         x_InitErrCode((CException::EErrCode) args.GetErrCode());        \
1335     }                                                                   \
1336 protected: \
1337     exception_class(const CDiagCompileInfo& info,                       \
1338         const CException* prev_exception,                               \
1339         const string& message,                                          \
1340         EDiagSev severity, CException::TFlags flags)                    \
1341         : base_class(info, prev_exception, (message), severity, flags)  \
1342     {                                                                   \
1343     }                                                                   \
1344 public: \
1345     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class,       \
1346         base_class)                                                     \
1347 private:                                                                \
1348     /* for the sake of semicolon at the end of macro...*/               \
1349     static void xx_unused_##exception_class(void)
1350 
1351 
1352 /// Helper macro added to support templatized exceptions.
1353 ///
1354 /// GCC starting from 3.2.2 warns about implicit typenames - this macro fixes
1355 /// the warning.
1356 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL(exception_class, base_class) \
1357     { \
1358         this->x_Init(info, message, prev_exception, severity); \
1359         this->x_InitErrCode((typename CException::EErrCode) err_code); \
1360     } \
1361     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class)
1362 
1363 
1364 /// Helper macro added to support errno based templatized exceptions.
1365 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(exception_class, base_class) \
1366     { \
1367         this->x_Init(info, message, prev_exception, severity); \
1368         this->x_InitErrCode((typename CException::EErrCode) err_code); \
1369     } \
1370     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1371 public: \
1372     virtual const char* GetErrCodeString(void) const override \
1373     { \
1374         switch (GetErrCode()) { \
1375         case CParent::eErrno: return "eErrno"; \
1376         default:              return CException::GetErrCodeString(); \
1377         } \
1378     }
1379 
1380 
1381 
1382 /// Do not use virtual base classes in exception declaration at all,
1383 /// because in this case derived class should initialize all base
1384 /// classes directly, that is not convenient and hard to control.
1385 ///
1386 /// @deprecated
1387 ///
1388 #define EXCEPTION_VIRTUAL_BASE
1389 
1390 
1391 
1392 /////////////////////////////////////////////////////////////////////////////
1393 ///
1394 /// CExceptionReporter --
1395 ///
1396 /// Define exception reporter.
1397 
1398 class NCBI_XNCBI_EXPORT CExceptionReporter
1399 {
1400 public:
1401     /// Constructor.
1402     CExceptionReporter(void);
1403 
1404     /// Destructor.
1405     virtual ~CExceptionReporter(void);
1406 
1407     /// Set default reporter.
1408     static void SetDefault(const CExceptionReporter* handler);
1409 
1410     /// Get default reporter.
1411     static const CExceptionReporter* GetDefault(void);
1412 
1413     /// Enable/disable using default reporter.
1414     ///
1415     /// @return
1416     ///   Previous state of this flag.
1417     static bool EnableDefault(bool enable);
1418 
1419     /// Report exception using default reporter.
1420     static void ReportDefault(const CDiagCompileInfo& info,
1421                               const string& title, const std::exception& ex,
1422                               TDiagPostFlags flags = eDPF_Exception);
1423 
1424     /// Report exception using default reporter and particular error code and
1425     /// subcode when writing to diagnostics.
1426     static void ReportDefaultEx(int err_code, int err_subcode,
1427                                 const CDiagCompileInfo& info,
1428                                 const string& title, const std::exception& ex,
1429                                 TDiagPostFlags flags = eDPF_Exception);
1430 
1431     /// Report CException with _this_ reporter
1432     virtual void Report(const char* file, int line,
1433                         const string& title, const CException& ex,
1434                         TDiagPostFlags flags = eDPF_Exception) const = 0;
1435 private:
1436     static const CExceptionReporter* sm_DefHandler; ///< Default handler
1437     static bool                      sm_DefEnabled; ///< Default enable flag
1438 };
1439 
1440 
1441 
1442 /////////////////////////////////////////////////////////////////////////////
1443 ///
1444 /// CExceptionReporterStream --
1445 ///
1446 /// Define exception reporter stream.
1447 
1448 class NCBI_XNCBI_EXPORT CExceptionReporterStream : public CExceptionReporter
1449 {
1450 public:
1451     /// Constructor.
1452     CExceptionReporterStream(ostream& out);
1453 
1454     /// Destructor.
1455     virtual ~CExceptionReporterStream(void);
1456 
1457     /// Report specified exception on output stream.
1458     virtual void Report(const char* file, int line,
1459                         const string& title, const CException& ex,
1460                         TDiagPostFlags flags = eDPF_Exception) const;
1461 private:
1462     ostream& m_Out;   ///< Output stream
1463 };
1464 
1465 
1466 
1467 /////////////////////////////////////////////////////////////////////////////
1468 ///
1469 /// CCoreException --
1470 ///
1471 /// Define corelib exception.  CCoreException inherits its basic
1472 /// functionality from CException and defines additional error codes for
1473 /// applications.
1474 
1475 class NCBI_XNCBI_EXPORT CCoreException : EXCEPTION_VIRTUAL_BASE public CException
1476 {
1477 public:
1478     /// Error types that  corelib can generate.
1479     ///
1480     /// These generic error conditions can occur for corelib applications.
1481     enum EErrCode {
1482         eCore,          ///< Generic corelib error
1483         eNullPtr,       ///< Null pointer error
1484         eDll,           ///< Dll error
1485         eDiagFilter,    ///< Illegal syntax of the diagnostics filter string
1486         eInvalidArg     ///< Invalid argument error
1487     };
1488 
1489     /// Translate from the error code value to its string representation.
1490     virtual const char* GetErrCodeString(void) const override;
1491 
1492     // Standard exception boilerplate code.
1493     NCBI_EXCEPTION_DEFAULT(CCoreException, CException);
1494 };
1495 
1496 
1497 /////////////////////////////////////////////////////////////////////////////
1498 ///
1499 /// CInvalidParamException --
1500 ///
1501 /// Exception to report configuration or command line parameter errors
1502 /// (external error sources as opposed to CCoreException::eInvalidArg).
1503 
1504 class NCBI_XNCBI_EXPORT CInvalidParamException : public CException
1505 {
1506 public:
1507     enum EErrCode {
1508         eUndefined = 1,         ///< Parameter is missing/undefined
1509         eInvalidCharacter       ///< Parameter value contains invalid character
1510     };
1511 
1512     /// Translate from an error code value to its string representation.
1513     virtual const char* GetErrCodeString(void) const override;
1514 
1515     // Standard exception boilerplate code.
1516     NCBI_EXCEPTION_DEFAULT(CInvalidParamException, CException);
1517 };
1518 
1519 
1520 // Some implementations return char*, so strict compilers may refuse
1521 // to let them satisfy TErrorStr without a wrapper.  However, they
1522 // don't all agree on what form the wrapper should take. :-/
1523 NCBI_XNCBI_EXPORT
1524 extern const char* Ncbi_strerror(int errnum);
1525 
1526 #ifdef NCBI_COMPILER_GCC
NcbiErrnoCode(void)1527 inline int         NcbiErrnoCode(void)      { return errno; }
NcbiErrnoStr(int errnum)1528 inline const char* NcbiErrnoStr(int errnum) { return ::strerror(errnum); }
1529 #  define NCBI_ERRNO_CODE_WRAPPER NCBI_NS_NCBI::NcbiErrnoCode
1530 #  define NCBI_ERRNO_STR_WRAPPER  NCBI_NS_NCBI::NcbiErrnoStr
1531 #else
1532 class CErrnoAdapt
1533 {
1534 public:
GetErrCode(void)1535     static int GetErrCode(void)
1536         { return errno; }
GetErrCodeString(int errnum)1537     static const char* GetErrCodeString(int errnum)
1538         {
1539             return Ncbi_strerror(errnum);
1540         }
1541 };
1542 #  define NCBI_ERRNO_CODE_WRAPPER NCBI_NS_NCBI::CErrnoAdapt::GetErrCode
1543 #  define NCBI_ERRNO_STR_WRAPPER  NCBI_NS_NCBI::CErrnoAdapt::GetErrCodeString
1544 #endif
1545 
1546 // MS Windows API errors
1547 #ifdef NCBI_OS_MSWIN
1548 class NCBI_XNCBI_EXPORT CLastErrorAdapt
1549 {
1550 public:
GetErrCode(void)1551     static int GetErrCode(void)
1552         { return GetLastError(); }
1553     static const char* GetErrCodeString(int errnum);
1554 };
1555 #  define NCBI_LASTERROR_CODE_WRAPPER \
1556     NCBI_NS_NCBI::CLastErrorAdapt::GetErrCode
1557 #  define NCBI_LASTERROR_STR_WRAPPER  \
1558     NCBI_NS_NCBI::CLastErrorAdapt::GetErrCodeString
1559 #endif
1560 
1561 
1562 /////////////////////////////////////////////////////////////////////////////
1563 // Auxiliary exception classes:
1564 //   CErrnoException
1565 //   CErrnoException_Win
1566 //   CParseException
1567 //
1568 
1569 /// Define function type for "error code" function.
1570 typedef int (*TErrorCode)(void);
1571 
1572 /// Define function type for "error str" function.
1573 typedef const char* (*TErrorStr)(int errnum);
1574 
1575 
1576 /////////////////////////////////////////////////////////////////////////////
1577 ///
1578 /// CErrnoTemplExceptionEx --
1579 ///
1580 /// Define template class for easy generation of Errno-like exception classes.
1581 
1582 template <class TBase,
1583           TErrorCode PErrCode=NCBI_ERRNO_CODE_WRAPPER,
1584           TErrorStr  PErrStr=NCBI_ERRNO_STR_WRAPPER >
1585 class CErrnoTemplExceptionEx : EXCEPTION_VIRTUAL_BASE public TBase
1586 {
1587 public:
1588     /// Error type that an application can generate.
1589     enum EErrCode {
1590         eErrno          ///< Error code
1591     };
1592 
1593     /// Translate from the error code value to its string representation.
GetErrCodeString(void) const1594     virtual const char* GetErrCodeString(void) const override
1595     {
1596         switch (GetErrCode()) {
1597         case eErrno: return "eErrno";
1598         default:     return CException::GetErrCodeString();
1599         }
1600     }
1601 
1602 public:
1603     /// Copy constructor.
CErrnoTemplExceptionEx(const CErrnoTemplExceptionEx<TBase,PErrCode,PErrStr> & other)1604     CErrnoTemplExceptionEx(
1605         const CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>& other)
1606         : TBase(other)
1607     {
1608         m_Errno = other.m_Errno;
1609         this->x_Assign(other);
1610     }
1611 
1612     /// Destructor.
~CErrnoTemplExceptionEx(void)1613     virtual ~CErrnoTemplExceptionEx(void) throw() {}
1614 
1615     /// Report error number on stream.
ReportExtra(ostream & out) const1616     virtual void ReportExtra(ostream& out) const override
1617     {
1618         out << "errno = " << m_Errno <<  ": " << PErrStr(m_Errno);
1619     }
1620 
1621     // Attributes.
1622 
1623     /// Get type of class.
GetType(void) const1624     virtual const char* GetType(void) const override
1625         { return "CErrnoTemplException"; }
1626 
1627     typedef int TErrCode;
1628     /// Get error code.
1629 
GetErrCode(void) const1630     TErrCode GetErrCode(void) const
1631     {
1632         return typeid(*this) ==
1633             typeid(CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>) ?
1634                (TErrCode) this->x_GetErrCode() :
1635                (TErrCode) CException::eInvalid;
1636     }
1637 
1638     /// Get error number.
GetErrno(void) const1639     int GetErrno(void) const throw() { return m_Errno; }
1640 
1641 protected:
1642     /// Constructor (with errno only).
1643     /// It is unable to get correct error code after all base constructors initialization,
1644     /// that can reset it, so error code should be provided as parameter.
CErrnoTemplExceptionEx(const CDiagCompileInfo & info,const CException * prev_exception,const string & message,int errnum,EDiagSev severity=eDiag_Error,CException::TFlags flags=0)1645     CErrnoTemplExceptionEx(const CDiagCompileInfo& info,
1646                            const CException* prev_exception,
1647                            const string& message,
1648                            int errnum, EDiagSev severity = eDiag_Error,
1649                            CException::TFlags flags = 0)
1650           : TBase(info, prev_exception, message, severity, flags),
1651             m_Errno(errnum)
1652     {
1653         this->x_Init(info, message, prev_exception, severity);
1654     }
1655     /// Default constructor.
CErrnoTemplExceptionEx(void)1656     CErrnoTemplExceptionEx(void) { m_Errno = PErrCode(); }
1657 
1658 
1659     /// Helper clone method.
x_Clone(void) const1660     virtual const CException* x_Clone(void) const override
1661     {
1662         return new CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>(*this);
1663     }
1664 
1665 private:
1666     int m_Errno;  ///< Error number
1667 };
1668 
1669 
1670 
1671 /////////////////////////////////////////////////////////////////////////////
1672 ///
1673 /// CErrnoTemplException --
1674 ///
1675 /// Define template class for easy generation of Errno-like exception classes.
1676 
1677 template<class TBase> class CErrnoTemplException :
1678     public CErrnoTemplExceptionEx<TBase,
1679                                   NCBI_ERRNO_CODE_WRAPPER,
1680                                   NCBI_ERRNO_STR_WRAPPER>
1681 {
1682 public:
1683     /// Parent class type.
1684     typedef CErrnoTemplExceptionEx<TBase, NCBI_ERRNO_CODE_WRAPPER, NCBI_ERRNO_STR_WRAPPER> CParent;
1685 
1686     /// Constructor.
1687     CErrnoTemplException<TBase>(const CDiagCompileInfo&    info,
1688                                 const CException*          prev_exception,
1689                                 typename CParent::EErrCode err_code,
1690                                 const string&              message,
1691                                 EDiagSev                   severity = eDiag_Error)
1692         : CParent(info, prev_exception, message, NCBI_ERRNO_CODE_WRAPPER(), severity, 0)
1693     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(CErrnoTemplException<TBase>, CParent)
1694 
1695 protected:
1696     CErrnoTemplException<TBase>(const CDiagCompileInfo&    info,
1697                                 const CException*          prev_exception,
1698                                 const string&              message,
1699                                 EDiagSev                   severity,
1700                                 CException::TFlags         flags)
1701         : CParent(info, prev_exception, message, NCBI_ERRNO_CODE_WRAPPER(), severity, flags) {
1702     }
1703 };
1704 
1705 
1706 #ifdef NCBI_OS_MSWIN
1707 template<class TBase> class CErrnoTemplException_Win :
1708     public CErrnoTemplExceptionEx<TBase,
1709                                   NCBI_LASTERROR_CODE_WRAPPER,
1710                                   NCBI_LASTERROR_STR_WRAPPER>
1711 {
1712 public:
1713     /// Parent class type.
1714     typedef CErrnoTemplExceptionEx<TBase, NCBI_LASTERROR_CODE_WRAPPER, NCBI_LASTERROR_STR_WRAPPER> CParent;
1715 
1716     /// Constructor.
1717     CErrnoTemplException_Win<TBase>(const CDiagCompileInfo&    info,
1718                                     const CException*          prev_exception,
1719                                     typename CParent::EErrCode err_code,
1720                                     const string&              message,
1721                                     EDiagSev                   severity = eDiag_Error)
1722         : CParent(info, prev_exception, message, NCBI_LASTERROR_CODE_WRAPPER(), severity, 0)
1723     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(CErrnoTemplException_Win<TBase>, CParent)
1724 
1725 protected:
1726     CErrnoTemplException_Win<TBase>(const CDiagCompileInfo&    info,
1727                                     const CException*          prev_exception,
1728                                     const string&              message,
1729                                     EDiagSev                   severity,
1730                                     CException::TFlags         flags)
1731         : CParent(info, prev_exception, message, NCBI_LASTERROR_CODE_WRAPPER(), severity, flags) {
1732     }
1733 };
1734 #endif
1735 
1736 /////////////////////////////////////////////////////////////////////////////
1737 
1738 
1739 /// Create an instance of the exception with one additional parameter.
1740 #define NCBI_EXCEPTION2_VAR(name, exception_class, err_code, message, extra) \
1741     exception_class name(DIAG_COMPILE_INFO, 0,                               \
1742     exception_class::err_code, (message), (extra) )
1743 
1744 /// Generic macro to make an exception with one additional parameter,
1745 /// given the exception class, error code and message string.
1746 #define NCBI_EXCEPTION2(exception_class, err_code, message, extra)   \
1747     NCBI_EXCEPTION2_VAR(NCBI_EXCEPTION_EMPTY_NAME,                   \
1748     exception_class, err_code, message, extra)
1749 
1750 /// Throw exception with extra parameter.
1751 ///
1752 /// Required to throw exceptions with one additional parameter
1753 /// (e.g. positional information for CParseException).
1754 #define NCBI_THROW2(exception_class, err_code, message, extra) \
1755     throw NCBI_EXCEPTION2(exception_class, err_code, message, extra)
1756 
1757 /// Re-throw exception with extra parameter.
1758 ///
1759 /// Required to re-throw exceptions with one additional parameter
1760 /// (e.g. positional information for CParseException).
1761 #define NCBI_RETHROW2(prev_exception,exception_class,err_code,message,extra) \
1762     throw exception_class(DIAG_COMPILE_INFO, \
1763         &(prev_exception), exception_class::err_code, (message), (extra))
1764 
1765 
1766 /// Define exception default with one additional parameter.
1767 ///
1768 /// Required to define exception default with one additional parameter
1769 /// (e.g. derived from CParseException).
1770 #define NCBI_EXCEPTION_DEFAULT2(exception_class, base_class, extra_type) \
1771 public: \
1772     exception_class(const CDiagCompileInfo &info, \
1773         const CException* prev_exception, \
1774         EErrCode err_code,const string& message, \
1775         extra_type extra_param, EDiagSev severity = eDiag_Error) \
1776         : base_class(info, prev_exception, \
1777             (message), extra_param, severity, 0) \
1778     NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(exception_class, base_class)
1779 
1780 END_NCBI_SCOPE
1781 
1782 
1783 /* @} */
1784 
1785 #endif  /* NCBIEXPT__HPP */
1786