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