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
69
83#define DramaTHROW_S(status_,format_,...) drama::ExceptionThrowSafe(__func__, __FILE__,__LINE__,(status_), (format_), __VA_ARGS__)
84
85
86
87namespace drama
88{
137 class Exception : public std::exception {
138
139 private :
140 // Note line and file are not currently used
141 // through the values are set correctly. It may be appropiate
142 // for methods to be added to access them later.
143 int _lineNum; // Line number exception was thrown from
144 std::string _sourceFile; // Source file exception was thrown from
145 std::string _sourceFunc; // Function exception was thrown from.
146 std::string _origMessage; // Original contextual message
147 StatusType _dramaStatus; // DRAMA Error code.
148 std::ostringstream _message; // Message to be output.
149 std::ostringstream _stackTrace; // Stack trace recored here.
150 static const unsigned _stackTraceMax = 25; // Max elements in stack trace.
151 std::string _whatString; //Used for result of what() to avoid temp going out of scope.
152
153 static bool _firstReportDone; // We report about the environment variable
154 // that causes more details to be output
155 // on the first report only.
156 bool _alwaysStacktrace = false; // Does we always output the stack trace.
157 /*
158 * Generate the stack track.
159 *
160 * array size is _stackTraceMax, and has been field out
161 * by a call to backtrace(). nSize elements are valid.
162 */
163 void GenerateStackTrace(const int nSize, void *array[]);
164 /*
165 * Support method for GenerateStackTrace.
166 */
167 void AddStackTraceLine(char *stackString);
168
169 public:
176 Exception() : _lineNum(0), _sourceFile("none"),
177 _sourceFunc("none"), _origMessage("none"),
178 _dramaStatus(STATUS__OK) { }
179
180
199 Exception(const std::string func,
200 const std::string &file,
201 const int lineNum,
202 const std::string &message = "",
204 const bool alwaysStacktrace = false);
205
206
222 D2DEPRECATED Exception(
223 bool makeUnique DUNUSED,
224 const std::string func, // Set to __func__
225 const std::string &file, // Set to __FILE__
226 const int lineNum, // Set to __LINE__
227 const StatusType status,
228 const char *format, ...) :
229 Exception(func, file, lineNum, "<<C-Format>", status)
230 {
231 va_list ap;
233 char buffer[200];
234 vsnprintf(buffer, sizeof(buffer), format, ap);
235 _message.str(""); // Clear result of primary constructor.
236 _origMessage = buffer;
237 _message << buffer; // Add the real message required.
238 _whatString = toString();
239 }
240
245 // Needed as _message can't be copied directly.
246 Exception(const Exception &source) :
247 _lineNum(source._lineNum),
248 _sourceFile(source._sourceFile),
249 _sourceFunc(source._sourceFunc),
250 _origMessage(source._origMessage),
251 _dramaStatus(source._dramaStatus),
252 _whatString(source._whatString),
253 _alwaysStacktrace(source._alwaysStacktrace) {
254 _message.str(source._message.str());
255 }
256
262 _lineNum(std::move(source._lineNum)),
263 _sourceFile(std::move(source._sourceFile)),
264 _sourceFunc(std::move(source._sourceFunc)),
265 _origMessage(std::move(source._origMessage)),
266 _dramaStatus(std::move(source._dramaStatus)),
267 _whatString(std::move(source._whatString)),
268 _alwaysStacktrace(source._alwaysStacktrace) {
269
270 // I thought I should have been able to initialize _message above()
271 // using _message(std::move(source._message)) as streams are
272 // are supposed to support move, but this didn't work when tried
273 // with GCC 4.7. So we still use this expensive operation.
274
275 _message.str(source._message.str());
276 _stackTrace.str(source._stackTrace.str());
277 }
278
284 // Needed as _message can't be copied directly.
286
287 if (this == &rhs)
288 return *this;
289
290 this->_sourceFile = rhs._sourceFile;
291 this->_sourceFunc = rhs._sourceFunc;
292 this->_lineNum = rhs._lineNum;
293 this->_origMessage = rhs._origMessage;
294 this->_dramaStatus = rhs._dramaStatus;
295 this->_whatString = rhs._whatString;
296
297 this->_message.str(rhs._message.str()); // Copy in message string.
298 this->_stackTrace.str(rhs._stackTrace.str());
299 this->_alwaysStacktrace = rhs._alwaysStacktrace;
300 return *this;
301 }
307 Exception& operator=(Exception &&rhs) noexcept {
308
309 if (this == &rhs)
310 return *this;
311
312 this->_sourceFile = std::move(rhs._sourceFile);
313 this->_sourceFunc = std::move(rhs._sourceFunc);
314 this->_lineNum = std::move(rhs._lineNum);
315 this->_origMessage = std::move(rhs._origMessage);
316 this->_dramaStatus = std::move(rhs._dramaStatus);
317 this->_whatString = std::move(rhs._whatString);
318
319 // I Think Should be possible, but didn't work in GCC 4.7.1, 4.8.2
320 // this->_message = std::move(rhs._message);
321
322 this->_message.str(rhs._message.str()); // Copy in message string.
323 this->_stackTrace.str(rhs._stackTrace.str());
324
325 this->_alwaysStacktrace = rhs._alwaysStacktrace;
326
327 return *this;
328 }
329
330
331
332
338 virtual std::string toString() const;
339
344 virtual const std::string & getOrigMessage() const {
345 return _origMessage;
346 }
351 virtual int lineNumber() const {
352 return _lineNum;
353 }
359 virtual const std::string & fileName() const {
360 return _sourceFile;
361 }
367 virtual const std::string & function() const {
368 return _sourceFunc;
369 }
377 virtual StatusType dramaStatus() const {
378 return _dramaStatus;
379 }
386 virtual std::string dramaStatusStr() const;
387
397 virtual int statusAsSysExitCode() const {
398 return MessStatusToSysExit(_dramaStatus);
399 }
400
406 void AddErs();
407
408
417 template<class T>
418 Exception & operator << (const T &t) {
419 _message << t;
420 //_message << std::endl << t;
421 _whatString = toString(); // Ensure what string updated.
422 return *this;
423 }
429 virtual std::string getStackTrace() const {
430 return _stackTrace.str();
431 }
432
443 virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const;
444
456 virtual void ErsRep() const;
457
458
464 virtual void ErsOut() const;
465
481 const char* what() const noexcept override {
482 return _whatString.c_str();
484
485
490 void FmtWrite(const char *str);
503 template<typename T, typename... Types>
504 void FmtWrite(const char * format,
505 T value,
506 Types... args) {
507 while (*format)
509 if (*format == '%')
510 {
511 if (*(format + 1) == '%')
512 {
513 ++format;
514 }
515 else
516 {
517 *this << value;
518 FmtWrite(format + 1, args...); // call even when *s == 0 to detect extra arguments
519 return;
520 }
521 }
522 *this << *format++;
523 }
525 "extra arguments provided to drama::ExceptionThrowSafe");
526 }
527
530 virtual ~Exception() {};
532 }; // Class Exception
533
534
535
554 template<typename... Types>
555 void ExceptionThrowSafe[[ noreturn ]] (const std::string func,
556 const std::string &file,
557 const int lineNum,
559 const char * format,
560 Types... args)
561 {
563
564 e.FmtWrite(format, args...);
565
566 throw e;
567
568 }
569
570
571
572
573} // namespace drama
574
575
576
577
586inline std::ostream& operator << (std::ostream &strm, const drama::Exception & e)
587{
588 std::ios::fmtflags oldFlags = strm.flags();
589 strm << e.toString()
590 << std::endl
591 << "DRAMA Status = 0x"
592 << std::hex
593 << e.dramaStatus()
594 << ", "
595 << e.dramaStatusStr();
596
597 strm.flags(oldFlags);
598
599 return strm;
600}
601
602
603#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:249
virtual std::string getStackTrace() const
Return the stack trace created when the exception was created.
Definition exception.hh:456
virtual int lineNumber() const
Returns the source file line number at which the exception occurred.
Definition exception.hh:378
virtual int statusAsSysExitCode() const
Return a system exit code based on the DRAMA Status.
Definition exception.hh:424
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:386
virtual const std::string & getOrigMessage() const
Returns the exception original message.
Definition exception.hh:371
const char * what() const noexcept override
Get string identifying exception.
Definition exception.hh:508
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:273
Exception & operator=(const Exception &rhs)
Assignment operator.
Definition exception.hh:312
void FmtWrite(const char *format, T value, Types... args)
Safe formated write to an exception message string.
Definition exception.hh:531
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:394
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:445
Exception(Exception &&source) noexcept
Move constructor.
Definition exception.hh:288
Exception()
Create an Exception, details empty.
Definition exception.hh:203
virtual StatusType dramaStatus() const
Return the DRAMA Status code associated with the exception.
Definition exception.hh:404
virtual ~Exception()
Virtual Destructor - since we will be inherited.
Definition exception.hh:557
Exception & operator=(Exception &&rhs) noexcept
Move assignment operator.
Definition exception.hh:334
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:164
std::ostream & operator<<(std::ostream &strm, const drama::Exception &e)
drama::Exception stream output operator
Definition exception.hh:613
#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:582
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.