1 /*
2  * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #ifndef ErrorHandling_h
27 #define ErrorHandling_h
28 
29 
30 #include <stdexcept>
31 
32 #include "SourceCodePos.h"
33 #include "tstrings.h"
34 
35 
36 //
37 // Exception handling helpers. Allow transparent exception logging.
38 // Use as follows:
39 //
40 //  void foo () {
41 //      JP_TRY;
42 //
43 //      if (!do_something()) {
44 //          JP_THROW("do_something() failed");
45 //      }
46 //
47 //      JP_CATCH_ALL;
48 //  }
49 //
50 
51 
52 // Logs std::exception caught at 'pos'.
53 void reportError(const SourceCodePos& pos, const std::runtime_error& e);
54 // Logs unknown exception caught at 'pos'.
55 // Assumed to be called from catch (...) {}
56 void reportUnknownError(const SourceCodePos& pos);
57 
58 std::string makeMessage(const std::runtime_error& e, const SourceCodePos& pos);
59 
60 std::string joinErrorMessages(const std::string& a, const std::string& b);
61 
62 std::string lastCRTError();
63 
64 
65 class JpErrorBase {
66 public:
67     virtual const char* rawMessage() const throw() = 0;
68 };
69 
70 
71 template <class Base>
72 class JpError: public JpErrorBase, public Base {
73 public:
JpError(const Base & e,const SourceCodePos & pos)74     JpError(const Base& e, const SourceCodePos& pos):
75                                         Base(e), msg(::makeMessage(e, pos)) {
76     }
77 
throw()78     ~JpError() throw() {
79     }
80 
81     // override Base::what()
what()82     const char* what() const throw() {
83         return msg.c_str();
84     }
85 
86     // override JpErrorBase
rawMessage()87     const char* rawMessage() const throw() {
88         return Base::what();
89     }
90 private:
91     // Assert Base is derived from std::runtime_error
92     enum { isDerivedFromStdException =
93                         sizeof(static_cast<std::runtime_error*>((Base*)0)) };
94 
95     std::string msg;
96 };
97 
98 template <class T>
makeException(const T & obj,const SourceCodePos & p)99 inline JpError<T> makeException(const T& obj, const SourceCodePos& p) {
100     return JpError<T>(obj, p);
101 }
102 
makeException(const std::string & msg,const SourceCodePos & p)103 inline JpError<std::runtime_error> makeException(
104                             const std::string& msg, const SourceCodePos& p) {
105     return JpError<std::runtime_error>(std::runtime_error(msg), p);
106 }
107 
makeException(const tstrings::any & msg,const SourceCodePos & p)108 inline JpError<std::runtime_error> makeException(
109                         const tstrings::any& msg, const SourceCodePos& p) {
110     return makeException(msg.str(), p);
111 }
112 
makeException(std::string::const_pointer msg,const SourceCodePos & p)113 inline JpError<std::runtime_error> makeException(
114                     std::string::const_pointer msg, const SourceCodePos& p) {
115     return makeException(std::string(msg), p);
116 }
117 
118 
119 #define JP_REPORT_ERROR(e)          reportError(JP_SOURCE_CODE_POS, e)
120 #define JP_REPORT_UNKNOWN_ERROR     reportUnknownError(JP_SOURCE_CODE_POS)
121 
122 // Redefine locally in cpp file(s) if need more handling than just reporting
123 #define JP_HANDLE_ERROR(e)          JP_REPORT_ERROR(e)
124 #define JP_HANDLE_UNKNOWN_ERROR     JP_REPORT_UNKNOWN_ERROR
125 
126 
127 #define JP_TRY                              \
128         try                                 \
129         {                                   \
130             do {} while(0)
131 
132 #define JP_DEFAULT_CATCH_EXCEPTIONS         \
133         JP_CATCH_STD_EXCEPTION              \
134         JP_CATCH_UNKNOWN_EXCEPTION
135 
136 #define JP_CATCH_EXCEPTIONS                 \
137         JP_DEFAULT_CATCH_EXCEPTIONS
138 
139 #define JP_CATCH_ALL                        \
140         }                                   \
141         JP_CATCH_EXCEPTIONS                 \
142         do {} while(0)
143 
144 #define JP_CATCH_STD_EXCEPTION              \
145         catch (const std::runtime_error& e) \
146         {                                   \
147             JP_HANDLE_ERROR(e);             \
148         }
149 
150 #define JP_CATCH_UNKNOWN_EXCEPTION          \
151         catch (...)                         \
152         {                                   \
153             JP_HANDLE_UNKNOWN_ERROR;        \
154         }
155 
156 
157 #define JP_THROW(e) throw makeException((e), JP_SOURCE_CODE_POS)
158 
159 #define JP_NO_THROW(expr) \
160     JP_TRY; \
161     expr; \
162     JP_CATCH_ALL
163 
164 #endif // #ifndef ErrorHandling_h
165