1 //============================================================================== 2 // 3 // This file is part of GPSTk, the GPS Toolkit. 4 // 5 // The GPSTk is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published 7 // by the Free Software Foundation; either version 3.0 of the License, or 8 // any later version. 9 // 10 // The GPSTk is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with GPSTk; if not, write to the Free Software Foundation, 17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 18 // 19 // This software was developed by Applied Research Laboratories at the 20 // University of Texas at Austin. 21 // Copyright 2004-2020, The Board of Regents of The University of Texas System 22 // 23 //============================================================================== 24 25 //============================================================================== 26 // 27 // This software was developed by Applied Research Laboratories at the 28 // University of Texas at Austin, under contract to an agency or agencies 29 // within the U.S. Department of Defense. The U.S. Government retains all 30 // rights to use, duplicate, distribute, disclose, or release this software. 31 // 32 // Pursuant to DoD Directive 523024 33 // 34 // DISTRIBUTION STATEMENT A: This software has been approved for public 35 // release, distribution is unlimited. 36 // 37 //============================================================================== 38 39 /** 40 * @file Exception.hpp 41 * Exceptions for all of GPSTK, including location information 42 */ 43 44 // The unusual include macro below is done this way because xerces 45 // #defines EXCEPTION_HPP in their own exception class header file. 46 #ifndef GPSTK_EXCEPTION_HPP 47 #define GPSTK_EXCEPTION_HPP 48 49 #include <cstdlib> 50 #include <iostream> 51 #include <vector> 52 #include <string> 53 54 namespace gpstk 55 { 56 /** 57 * @defgroup exceptiongroup Exception Classes 58 * These classes are the exceptions that can be thrown in 59 * the library code. Use these in your catch() blocks 60 * and you'll be able to get more information 61 * than what std::exception provides. Use GPSTK_THROW() 62 * and GPSTK_RETHROW() to throw or rethrow these exceptions 63 * to automatically add line and file information to your 64 * exceptions. 65 */ 66 67 /// A class for recording locations (in the source code) of 68 /// exceptions being thrown. 69 class ExceptionLocation 70 { 71 public: 72 /** 73 * Constructor for location information. 74 * @param[in] filename name of source file where exception occurred. 75 * @param[in] funcName name of function where exception occurred. 76 * @param[in] lineNum line of source file where exception occurred. 77 */ ExceptionLocation(const std::string & filename=std::string (),const std::string & funcName=std::string (),const unsigned long & lineNum=0)78 ExceptionLocation(const std::string& filename = std::string(), 79 const std::string& funcName = std::string(), 80 const unsigned long& lineNum = 0) 81 : fileName(filename), functionName(funcName), 82 lineNumber(lineNum) 83 { } 84 85 /** 86 * Destructor. 87 */ ~ExceptionLocation()88 ~ExceptionLocation() {} 89 90 /// Accessor for name of source file where exception occurred. getFileName() const91 std::string getFileName() const 92 { return fileName; } 93 /// Accessor for name of function where exception occurred. getFunctionName() const94 std::string getFunctionName() const 95 { return functionName; } 96 /// Accessor for line of source file where exception occurred. getLineNumber() const97 unsigned long getLineNumber() const 98 { return lineNumber; } 99 100 /** 101 * Debug output function. 102 * @param[in,out] s stream to which debugging information for 103 * this class will be output. 104 */ 105 void dump(std::ostream& s) const; 106 107 /// Dump to a string 108 std::string what() const; 109 110 /** 111 * Output stream operator for ::ExceptionLocation. 112 * This is intended just to dump all the data in the 113 * ::ExceptionLocation to the indicated stream. \warning Warning: It 114 * will _not_ preserve the state of the stream. 115 * @param[in,out] s stream to send ::ExceptionLocation information to. 116 * @param[in] e ::ExceptionLocation to "dump". 117 * @return a reference to the stream \c s. 118 */ 119 friend std::ostream& operator<<( std::ostream& s, 120 const ExceptionLocation& e ); 121 122 private: 123 /// Name of source file where exception occurred. 124 std::string fileName; 125 /// Name of function where exception occurred. 126 std::string functionName; 127 /// Line in source file where exception occurred. 128 unsigned long lineNumber; 129 }; // class ExceptionLocation 130 131 /** 132 * The Exception class is the base class from which all 133 * exception objects thrown in the library are derived. None of 134 * the functions in this class throws exceptions because an 135 * exception has probably already been thrown or is about to be 136 * thrown. Each exception object contains the following: 137 * - A stack of exception message text strings (descriptions). 138 * - An error ID. 139 * - A severity code. 140 * - An error code group. 141 * - Information about where the exception was thrown. 142 * 143 * Exception provides all of the functions required for it and 144 * its derived classes, including functions that operate on the 145 * text strings in the stack. 146 * 147 * @sa exceptiontest.cpp for some examples of how to use this class. 148 * 149 * @ingroup exceptiongroup 150 */ 151 class Exception 152 { 153 public: 154 /// Exception severity classes. 155 enum Severity 156 { 157 unrecoverable, /**< program can not recover from this exception */ 158 recoverable /**< program can recover from this exception */ 159 }; 160 161 /** 162 * Default constructor. 163 * Does nothing. 164 */ 165 Exception(); 166 167 /** 168 * Full constructor for exception. 169 * @param[in] errorText text message detailing exception. 170 * @param[in] errorId error code related to exception e.g. MQ 171 * result code. 172 * @param[in] severity severity of error. 173 */ 174 Exception(const std::string& errorText, 175 const unsigned long& errorId = 0, 176 const Severity& severity = unrecoverable); 177 178 179 /** 180 * Full constructor for exception. 181 * @param[in] errorText text message detailing exception. 182 * @param[in] errorId error code related to exception e.g. MQ 183 * result code. 184 * @param[in] severity severity of error. 185 */ 186 Exception(const char* errorText, 187 const unsigned long& errorId = 0, 188 const Severity& severity = unrecoverable); 189 190 191 /// Copy constructor. 192 Exception(const Exception& exception); 193 194 /// Destructor. ~Exception()195 ~Exception() 196 {}; 197 198 /// Assignment operator. 199 Exception& operator=(const Exception& e); 200 201 /** 202 * Ends the application. Normally, the library only intends 203 * this function to be used internally by the library's 204 * exception-handling macros when the compiler you are using 205 * does not support C++ exception handling. This only occurs 206 * if you define the NO_EXCEPTIONS_SUPPORT macro. 207 */ terminate()208 void terminate() 209 { exit(1); }; 210 211 /// Returns the error ID of the exception. getErrorId() const212 unsigned long getErrorId() const 213 { return errorId; }; 214 215 /** 216 * Sets the error ID to the specified value. 217 * @param[in] errId The identifier you want to associate with 218 * this error. 219 */ setErrorId(const unsigned long & errId)220 Exception& setErrorId(const unsigned long& errId) 221 { errorId = errId; return *this; }; 222 223 /** 224 * Adds the location information to the exception object. The 225 * library captures this information when an exception is 226 * thrown or rethrown. An array of ExceptionLocation objects 227 * is stored in the exception object. 228 * 229 * @param[in] location An IExceptionLocation object containing 230 * the following: 231 * \li Function name 232 * \li File name 233 * \li Line number where the function is called 234 */ 235 Exception& addLocation(const ExceptionLocation& location); 236 237 /** 238 * Returns the ExceptionLocation object at the specified index. 239 * @param[in] index If the index is not valid, a 0 240 * pointer is returned. (well, not really since someone 241 * changed all this bah) 242 */ 243 const ExceptionLocation getLocation(const size_t& index=0) const; 244 245 /// Returns the number of locations stored in the exception 246 /// location array. 247 size_t getLocationCount() const; 248 249 /** 250 * If the thrower (that is, whatever creates the exception) 251 * determines the exception is recoverable, 1 is returned. If 252 * the thrower determines it is unrecoverable, 0 is returned. 253 */ isRecoverable() const254 bool isRecoverable() const 255 { return (severity == recoverable); } 256 257 /** 258 * Sets the severity of the exception. 259 * @param[in] sever Use the enumeration Severity to specify 260 * the severity of the exception. 261 */ setSeverity(const Severity & sever)262 Exception& setSeverity(const Severity& sever) 263 { severity = sever; return *this; }; 264 265 /** 266 * Appends the specified text to the text string on the top 267 * of the exception text stack. 268 * @param[in] errorText The text you want to append. 269 */ 270 Exception& addText(const std::string& errorText); 271 272 /** 273 * Returns an exception text string from the exception text 274 * stack. 275 * 276 * @param[in] index The default index is 0, which is the 277 * top of the stack. If you specify an index which is not 278 * valid, a 0 pointer is returned. 279 */ 280 std::string getText(const size_t& index=0) const; 281 282 /// Returns the number of text strings in the exception text stack. 283 size_t getTextCount() const; 284 285 /// Returns the name of the object's class. getName() const286 std::string getName() const 287 { return "Exception"; }; 288 289 /** 290 * Debug output function. 291 * @param[in] s stream to output debugging information for 292 * this class to. 293 */ 294 void dump(std::ostream& s) const; 295 296 /// Dump to a string 297 std::string what() const; 298 299 /** 300 * Output stream operator for ::Exception. 301 * This is intended just to dump all the data in the ::Exception to 302 * the indicated stream. \warning Warning: It will _not_ preserve 303 * the state of the stream. 304 * @param[in,out] s stream to send ::Exception information to. 305 * @param[in] e ::Exception to "dump". 306 * @return a reference to the stream \c s. */ 307 friend std::ostream& operator<<( std::ostream& s, 308 const Exception& e ); 309 310 protected: 311 /// Error code. 312 unsigned long errorId; 313 /// Stack of exception locations (where it was thrown). 314 std::vector<ExceptionLocation> locations; 315 /// Severity of exception. 316 Severity severity; 317 /// Text stack describing exception condition. 318 std::vector<std::string> text; 319 320 /** 321 * This is the streambuf function that actually outputs the 322 * data to the device. Since all output should be done with 323 * the standard ostream operators, this function should never 324 * be called directly. In the case of this class, the 325 * characters to be output are stored in a buffer and added 326 * to the exception text after each newline. 327 */ 328 int overflow(int c); 329 330 private: 331 /// Buffer for stream output. 332 std::string streamBuffer; 333 }; // class Exception 334 335 336 } // namespace gpstk 337 338 339 /** 340 * Just a comment for the wary. These following macros are quite 341 * useful. They just don't work under gcc 2.96/linux. If you can fix 342 * them I would be quite greatful but I am not holding my breath. For 343 * now, I am just manually putting the code where it needs to be. The 344 * problem seems to be with the __FILE__, __FUNCTION__, LINE__ being 345 * defined in a macro that is in a .hpp file as opposed to the .cpp 346 * file where the code gets used. When you do it you get a segfault. 347 * See the exceptiontest.cpp code in the base/test directory. 348 */ 349 #if defined ( __FUNCTION__ ) 350 #define FILE_LOCATION gpstk::ExceptionLocation(__FILE__, __FUNCTION__, __LINE__) 351 #else 352 #define FILE_LOCATION gpstk::ExceptionLocation(__FILE__, "", __LINE__) 353 #endif 354 355 // For compilers without exceptions, die if you get an exception. 356 #if defined (NO_EXCEPTIONS_SUPPORT) 357 /// A macro for adding location when throwing an gpstk::Exception 358 /// @ingroup exceptiongroup 359 #define GPSTK_THROW(exc) { exc.addLocation(FILE_LOCATION); exc.terminate(); } 360 /// A macro for adding location when rethrowing an gpstk::Exception 361 /// @ingroup exceptiongroup 362 #define GPSTK_RETHROW(exc) { exc.addLocation(FILE_LOCATION); exc.terminate(); } 363 #else 364 /// A macro for adding location when throwing an gpstk::Exception 365 /// @ingroup exceptiongroup 366 #define GPSTK_THROW(exc) { exc.addLocation(FILE_LOCATION); throw exc; } 367 /// A macro for adding location when rethrowing an gpstk::Exception 368 /// @ingroup exceptiongroup 369 #define GPSTK_RETHROW(exc) { exc.addLocation(FILE_LOCATION); throw; } 370 #endif 371 372 /// Provide an "ASSERT" type macro 373 #define GPSTK_ASSERT(CONDITION) if (!(CONDITION)) { \ 374 gpstk::AssertionFailure exc("Assertion failed: " #CONDITION); \ 375 GPSTK_THROW(exc); \ 376 } 377 378 379 /** 380 * A macro for quickly defining a new exception class that inherits from 381 * an gpstk::Exception derived class. Use this to make specific exceptions, 382 * such as the ones defined in this header file. Make sure that all 383 * exceptions have "\@ingroup exceptiongroup" in their comment block 384 * so doxygen knows what to do with them. 385 * 386 * @ingroup exceptiongroup 387 */ 388 #define NEW_EXCEPTION_CLASS(child, parent) \ 389 class child : public parent \ 390 { \ 391 public: \ 392 /** Default constructor. */ \ 393 child() : parent() {} \ 394 /** Copy constructor. */ \ 395 child(const child& a): parent(a) {} \ 396 /** Cast constructor. */ \ 397 child(const gpstk::Exception& a) : parent(a) {}; \ 398 /** \ 399 * Common use constructor. \ 400 * @param[in] a text description of exception condition. \ 401 * @param[in] b error code (default none) \ 402 * @param[in] c severity of exception (default unrecoverable) \ 403 */ \ 404 child(const std::string& a, unsigned long b = 0,\ 405 gpstk::Exception::Severity c = gpstk::Exception::unrecoverable) \ 406 : parent(a, b, c) \ 407 {};\ 408 /** \ 409 * Common use constructor. \ 410 * @param[in] a text description of exception condition. \ 411 * @param[in] b error code (default none) \ 412 * @param[in] c severity of exception (default unrecoverable) \ 413 */ \ 414 child(const char* a, unsigned long b = 0,\ 415 gpstk::Exception::Severity c = gpstk::Exception::unrecoverable) \ 416 : parent(a, b, c) \ 417 {};\ 418 /** Destructor. */ \ 419 ~child() {} \ 420 /** Returns the name of the exception class. */ \ 421 std::string getName() const {return ( # child);} \ 422 /** assignment operator for derived exceptions */ \ 423 child& operator=(const child& kid) \ 424 { parent::operator=(kid); return *this; } \ 425 /** ostream operator for derived exceptions */ \ 426 friend std::ostream& operator<<(std::ostream& s, const child& c) \ 427 { c.dump(s); return s; } \ 428 } 429 430 namespace gpstk 431 { 432 /// Thrown when a function is given a parameter value that it invalid 433 /// @ingroup exceptiongroup 434 NEW_EXCEPTION_CLASS(InvalidParameter, Exception); 435 436 /// Thrown if a function can not satisfy a request 437 /// @ingroup exceptiongroup 438 NEW_EXCEPTION_CLASS(InvalidRequest, Exception); 439 440 /// Thrown when a required condition in a function is not met. 441 /// @ingroup exceptiongroup 442 NEW_EXCEPTION_CLASS(AssertionFailure, Exception); 443 444 /// Thrown if a function makes a request of the OS that can't be satisfied. 445 /// @ingroup exceptiongroup 446 NEW_EXCEPTION_CLASS(AccessError, Exception); 447 448 /// Attempts to access an "array" or other element that doesn't exist 449 /// @ingroup exceptiongroup 450 NEW_EXCEPTION_CLASS(IndexOutOfBoundsException, Exception); 451 452 /// A function was passed an invalid argument 453 /// @ingroup exceptiongroup 454 NEW_EXCEPTION_CLASS(InvalidArgumentException, Exception); 455 456 /// Application's configuration is invalid 457 /// @ingroup exceptiongroup 458 NEW_EXCEPTION_CLASS(ConfigurationException, Exception); 459 460 /// Attempted to open a file that doesn't exist 461 /// @ingroup exceptiongroup 462 NEW_EXCEPTION_CLASS(FileMissingException, Exception); 463 464 /// A problem using a system semaphore 465 /// @ingroup exceptiongroup 466 NEW_EXCEPTION_CLASS(SystemSemaphoreException, Exception); 467 468 /// A problem using a system pipe 469 /// @ingroup exceptiongroup 470 NEW_EXCEPTION_CLASS(SystemPipeException, Exception); 471 472 /// A problem using a system queue 473 /// @ingroup exceptiongroup 474 NEW_EXCEPTION_CLASS(SystemQueueException, Exception); 475 476 /// Unable to allocate memory 477 /// @ingroup exceptiongroup 478 NEW_EXCEPTION_CLASS(OutOfMemory, Exception); 479 480 /// Operation failed because it was unable to locate the requested obj 481 /// @ingroup exceptiongroup 482 NEW_EXCEPTION_CLASS(ObjectNotFound, AccessError); 483 484 /// Attempted to access a null pointer 485 /// @ingroup exceptiongroup 486 NEW_EXCEPTION_CLASS(NullPointerException, Exception); 487 488 /// Attempted to access a unimplemented function 489 /// @ingroup exceptiongroup 490 NEW_EXCEPTION_CLASS(UnimplementedException, Exception); 491 492 } // namespace gpstk 493 #endif 494