AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
exception.hh
Go to the documentation of this file.
1#ifndef _DRAMA2_EXCEPT_H
2#define _DRAMA2_EXCEPT_H
3
21/*
22 * History:
23 08-Jan-2014 - TJF - Original version.
24 30-Sep-2016 - TJF - There were many changes before now.
25 Fix some formatting in Print() and ErsRep().
26 20-Jan-2019 - TJF - Resolve with with the results of what() being
27 rubbish. This required I added the _whatString
28 item and update it each time the value of toString
29 would be changed. This is likely due to what in
30 effect return a c_str() result from a temp.
31 25-May-2021 - TJF - Have now created excepetion.cpp and the implementation
32 of all methods with and complexity which are not
33 templates or others required as inline have been
34 moved to it.
35
36 * The above ID is for Doxygen, this one has the format ACMM is looking for.
37 * "@(#) $Id$"
38 */
39
40#include "drama.h"
41#include "status.h"
42#include "mess.h"
43#include "drama2_err.h"
44#include <string>
45#include <stdio.h>
46#include <stdarg.h>
47#include <string.h>
48#include <execinfo.h> // For backtrace and backtrace_symbols
49#include <sstream> // For ostringstream
50#include <cxxabi.h>
51#include <iostream>
52#include "Ers.h"
53#include <iomanip> // To allow std::hex() to be used.
54#include <vector>
55#include "drama/util.hh"
56
57
66#define DramaTHROW(status_,message_) throw drama::Exception(__func__, __FILE__,__LINE__,(message_), (status_))
67
68// From C++20, we could use std::source_location instead of
69// the macros for these calls. But we want to support back to C++11
70// at this time.
71
72
73
87#define DramaTHROW_S(status_,format_,...) drama::ExceptionThrowSafe(__func__, __FILE__,__LINE__,(status_), (format_), __VA_ARGS__)
88
89
90
91namespace drama
92{
141 class Exception : public std::exception {
142
143 private :
144 // Note line and file are not currently used
145 // through the values are set correctly. It may be appropriate
146 // for methods to be added to access them later.
147 int _lineNum; // Line number exception was thrown from
148 std::string _sourceFile; // Source file exception was thrown from
149 std::string _sourceFunc; // Function exception was thrown from.
150 std::string _origMessage; // Original contextual message
151 StatusType _dramaStatus; // DRAMA Error code.
152 std::ostringstream _message; // Message to be output.
153 std::ostringstream _stackTrace; // Stack trace recorded here.
154 static const unsigned _stackTraceMax = 25; // Max elements in stack trace.
155 std::string _whatString; //Used for result of what() to avoid temp going out of scope.
156
157 static bool _firstReportDone; // We report about the environment variable
158 // that causes more details to be output
159 // on the first report only.
160 bool _alwaysStacktrace = false; // Does we always output the stack trace.
161 /*
162 * Generate the stack track.
163 *
164 * array size is _stackTraceMax, and has been field out
165 * by a call to backtrace(). nSize elements are valid.
166 */
167 void GenerateStackTrace(const int nSize, void *array[]);
168 /*
169 * Support method for GenerateStackTrace.
170 */
171 void AddStackTraceLine(char *stackString);
172
173 public:
180 Exception() : _lineNum(0), _sourceFile("none"),
181 _sourceFunc("none"), _origMessage("none"),
182 _dramaStatus(STATUS__OK) { }
183
184
203 Exception(const std::string func,
204 const std::string &file,
205 const int lineNum,
206 const std::string &message = "",
208 const bool alwaysStacktrace = false);
209
210
226 D2DEPRECATED Exception(
227 bool makeUnique DUNUSED,
228 const std::string func, // Set to __func__
229 const std::string &file, // Set to __FILE__
230 const int lineNum, // Set to __LINE__
231 const StatusType status,
232 const char *format, ...) :
233 Exception(func, file, lineNum, "<<C-Format>", status)
234 {
235 va_list ap;
237 char buffer[200];
238 vsnprintf(buffer, sizeof(buffer), format, ap);
239 _message.str(""); // Clear result of primary constructor.
240 _origMessage = buffer;
241 _message << buffer; // Add the real message required.
242 _whatString = toString();
243 }
244
249 // Needed as _message can't be copied directly.
250 Exception(const Exception &source) :
251 _lineNum(source._lineNum),
252 _sourceFile(source._sourceFile),
253 _sourceFunc(source._sourceFunc),
254 _origMessage(source._origMessage),
255 _dramaStatus(source._dramaStatus),
256 _whatString(source._whatString),
257 _alwaysStacktrace(source._alwaysStacktrace) {
258 _message.str(source._message.str());
259 }
260
266 _lineNum(std::move(source._lineNum)),
267 _sourceFile(std::move(source._sourceFile)),
268 _sourceFunc(std::move(source._sourceFunc)),
269 _origMessage(std::move(source._origMessage)),
270 _dramaStatus(std::move(source._dramaStatus)),
271 _whatString(std::move(source._whatString)),
272 _alwaysStacktrace(source._alwaysStacktrace) {
273
274 // I thought I should have been able to initialize _message above()
275 // using _message(std::move(source._message)) as streams are
276 // are supposed to support move, but this didn't work when tried
277 // with GCC 4.7. So we still use this expensive operation.
278
279 _message.str(source._message.str());
280 _stackTrace.str(source._stackTrace.str());
281 }
282
288 // Needed as _message can't be copied directly.
290
291 if (this == &rhs)
292 return *this;
293
294 this->_sourceFile = rhs._sourceFile;
295 this->_sourceFunc = rhs._sourceFunc;
296 this->_lineNum = rhs._lineNum;
297 this->_origMessage = rhs._origMessage;
298 this->_dramaStatus = rhs._dramaStatus;
299 this->_whatString = rhs._whatString;
300
301 this->_message.str(rhs._message.str()); // Copy in message string.
302 this->_stackTrace.str(rhs._stackTrace.str());
303 this->_alwaysStacktrace = rhs._alwaysStacktrace;
304 return *this;
305 }
311 Exception& operator=(Exception &&rhs) noexcept {
312
313 if (this == &rhs)
314 return *this;
315
316 this->_sourceFile = std::move(rhs._sourceFile);
317 this->_sourceFunc = std::move(rhs._sourceFunc);
318 this->_lineNum = std::move(rhs._lineNum);
319 this->_origMessage = std::move(rhs._origMessage);
320 this->_dramaStatus = std::move(rhs._dramaStatus);
321 this->_whatString = std::move(rhs._whatString);
322
323 // I Think Should be possible, but didn't work in GCC 4.7.1, 4.8.2
324 // this->_message = std::move(rhs._message);
325
326 this->_message.str(rhs._message.str()); // Copy in message string.
327 this->_stackTrace.str(rhs._stackTrace.str());
328
329 this->_alwaysStacktrace = rhs._alwaysStacktrace;
330
331 return *this;
332 }
333
334
335
336
342 virtual std::string toString() const;
343
348 virtual const std::string & getOrigMessage() const {
349 return _origMessage;
350 }
355 virtual int lineNumber() const {
356 return _lineNum;
357 }
363 virtual const std::string & fileName() const {
364 return _sourceFile;
365 }
371 virtual const std::string & function() const {
372 return _sourceFunc;
373 }
381 virtual StatusType dramaStatus() const {
382 return _dramaStatus;
383 }
390 virtual std::string dramaStatusStr() const;
391
401 virtual int statusAsSysExitCode() const {
402 return MessStatusToSysExit(_dramaStatus);
403 }
404
410 void AddErs();
411
412
421 template<class T>
422 Exception & operator << (const T &t) {
423 _message << t;
424 //_message << std::endl << t;
425 _whatString = toString(); // Ensure what string updated.
426 return *this;
427 }
433 virtual std::string getStackTrace() const {
434 return _stackTrace.str();
435 }
436
447 virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const;
448
460 virtual void ErsRep() const;
461
462
468 virtual void ErsOut() const;
469
485 const char* what() const noexcept override {
486 return _whatString.c_str();
488
489
494 void FmtWrite(const char *str);
507 template<typename T, typename... Types>
508 void FmtWrite(const char * format,
509 T value,
510 Types... args) {
511 while (*format)
513 if (*format == '%')
514 {
515 if (*(format + 1) == '%')
516 {
517 ++format;
518 }
519 else
520 {
521 *this << value;
522 FmtWrite(format + 1, args...); // call even when *s == 0 to detect extra arguments
523 return;
524 }
525 }
526 *this << *format++;
527 }
529 "extra arguments provided to drama::ExceptionThrowSafe");
530 }
531
534 virtual ~Exception() {};
536 }; // Class Exception
537
538
539
558 template<typename... Types>
559 void ExceptionThrowSafe[[ noreturn ]] (const std::string func,
560 const std::string &file,
561 const int lineNum,
563 const char * format,
564 Types... args)
565 {
567
568 e.FmtWrite(format, args...);
569
570 throw e;
571
572 }
573
574
575
576
577} // namespace drama
578
579
580
581
590inline std::ostream& operator << (std::ostream &strm, const drama::Exception & e)
591{
592 std::ios::fmtflags oldFlags = strm.flags();
593 strm << e.toString()
594 << std::endl
595 << "DRAMA Status = 0x"
596 << std::hex
597 << e.dramaStatus()
598 << ", "
599 << e.dramaStatusStr();
600
601 strm.flags(oldFlags);
602
603 return strm;
604}
605
606
607#endif /* _DRAMA2_EXCEPT_H */
D2DEPRECATED Exception(bool makeUnique, const std::string func, const std::string &file, const int lineNum, const StatusType status, const char *format,...)
Create an exception using C printf() style string formatting.
Definition exception.hh:253
virtual std::string getStackTrace() const
Return the stack trace created when the exception was created.
Definition exception.hh:460
virtual int lineNumber() const
Returns the source file line number at which the exception occurred.
Definition exception.hh:382
virtual int statusAsSysExitCode() const
Return a system exit code based on the DRAMA Status.
Definition exception.hh:428
virtual void ErsRep() const
Report details of this exception using ERS.
virtual void ErsOut() const
Output a DRAMA ERS report about this exception.
Exception(const std::string func, const std::string &file, const int lineNum, const std::string &message="", const StatusType status=DRAMA2__CPP_ERROR, const bool alwaysStacktrace=false)
Create an Exception.
virtual std::string toString() const
Return the exception string.
virtual const std::string & fileName() const
Returns the name of the C++ source file in which the exception occurred.
Definition exception.hh:390
virtual const std::string & getOrigMessage() const
Returns the exception original message.
Definition exception.hh:375
const char * what() const noexcept override
Get string identifying exception.
Definition exception.hh:512
virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const
Print exception details to a file.
Exception(const Exception &source)
Copy constructor.
Definition exception.hh:277
Exception & operator=(const Exception &rhs)
Assignment operator.
Definition exception.hh:316
void FmtWrite(const char *format, T value, Types... args)
Safe formated write to an exception message string.
Definition exception.hh:535
void FmtWrite(const char *str)
Safe formatted write to an exception message string.
virtual const std::string & function() const
Returns the name of the function in which the exception occurred.
Definition exception.hh:398
void AddErs()
Add the any errors from the current ERS context to the exception.
virtual std::string dramaStatusStr() const
Return the DRAMA Status code converted to a DRAMA.
Exception & operator<<(const T &t)
Add extra information to an exception message.
Definition exception.hh:449
Exception(Exception &&source) noexcept
Move constructor.
Definition exception.hh:292
Exception()
Create an Exception, details empty.
Definition exception.hh:207
virtual StatusType dramaStatus() const
Return the DRAMA Status code associated with the exception.
Definition exception.hh:408
virtual ~Exception()
Virtual Destructor - since we will be inherited.
Definition exception.hh:561
Exception & operator=(Exception &&rhs) noexcept
Move assignment operator.
Definition exception.hh:338
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:168
std::ostream & operator<<(std::ostream &strm, const drama::Exception &e)
drama::Exception stream output operator
Definition exception.hh:617
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:93
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1322
void ExceptionThrowSafe(const std::string func, const std::string &file, const int lineNum, StatusType status, const char *format, Types... args)
Create and throw an exception, variable argument list, Safe formatting of arguments.
Definition exception.hh:586
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:93
DRAMA 2 include file - Utility macros, types etc.