1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2002-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_quit_h)
27 #define octave_quit_h 1
28 
29 #include "octave-config.h"
30 
31 /* The signal header is just needed for the sig_atomic_t type.  */
32 #if defined (__cplusplus)
33 #  include <csignal>
34 #  include <iosfwd>
35 #  include <list>
36 #  include <stdexcept>
37 #  include <string>
38 extern "C" {
39 #else
40 #  include <signal.h>
41 #endif
42 
43 #if defined (__cplusplus)
44 
45 namespace octave
46 {
47   class frame_info
48   {
49   public:
50 
51     frame_info (void) = default;
52 
frame_info(const std::string & file_name,const std::string & fcn_name,int line,int column)53     frame_info (const std::string& file_name, const std::string& fcn_name,
54                 int line, int column)
55       : m_file_name (file_name), m_fcn_name (fcn_name), m_line (line),
56         m_column (column)
57     { }
58 
59     frame_info (const frame_info&) = default;
60 
61     frame_info& operator = (const frame_info&) = default;
62 
63     ~frame_info (void) = default;
64 
file_name(void)65     std::string file_name (void) const { return m_file_name; }
66 
fcn_name(void)67     std::string fcn_name (void) const { return m_fcn_name; }
68 
line(void)69     int line (void) const { return m_line; }
70 
column(void)71     int column (void) const { return m_column; }
72 
73   private:
74 
75     std::string m_file_name;
76 
77     std::string m_fcn_name;
78 
79     int m_line;
80 
81     int m_column;
82   };
83 
84   inline bool operator == (const frame_info& a, const frame_info& b)
85   {
86     return (a.file_name () == b.file_name ()
87             && a.fcn_name () == b.fcn_name ()
88             && a.line () == b.line ()
89             && a.column () == b.column ());
90   }
91 
92   class execution_exception : public std::runtime_error
93   {
94   public:
95 
96     typedef std::list<frame_info> stack_info_type;
97 
98     execution_exception (const std::string& err_type = "error",
99                          const std::string& id = "",
100                          const std::string& message = "unspecified error",
101                          const stack_info_type& stack_info = stack_info_type ())
runtime_error(message)102       : runtime_error (message), m_err_type (err_type), m_id (id),
103         m_message (message), m_stack_info (stack_info)
104     { }
105 
106     execution_exception (const execution_exception&) = default;
107 
108     execution_exception& operator = (const execution_exception&) = default;
109 
110     ~execution_exception (void) = default;
111 
set_err_type(const std::string & et)112     void set_err_type (const std::string& et)
113     {
114       m_err_type = et;
115     }
116 
err_type(void)117     std::string err_type (void) const { return m_err_type; }
118 
119     virtual std::string stack_trace (void) const;
120 
set_identifier(const std::string & id)121     void set_identifier (const std::string& id)
122     {
123       m_id = id;
124     }
125 
identifier(void)126     virtual std::string identifier (void) const { return m_id; }
127 
set_message(const std::string & msg)128     void set_message (const std::string& msg)
129     {
130       m_message = msg;
131     }
132 
message(void)133     std::string message (void) const { return m_message; }
134 
135     // Provided for std::exception interface.
what(void)136     const char * what (void) const noexcept { return m_message.c_str (); }
137 
stack_info(void)138     virtual stack_info_type stack_info (void) const
139     {
140       return m_stack_info;
141     }
142 
set_stack_info(const stack_info_type & stack_info)143     void set_stack_info (const stack_info_type& stack_info)
144     {
145       m_stack_info = stack_info;
146     }
147 
148     virtual void display (std::ostream& os) const;
149 
150   private:
151 
152     std::string m_err_type;
153 
154     std::string m_id;
155 
156     std::string m_message;
157 
158     stack_info_type m_stack_info;
159   };
160 
161   class exit_exception : public std::exception
162   {
163   public:
164 
165     exit_exception (int exit_status = 0, bool safe_to_return = false)
exception()166       : std::exception (), m_exit_status (exit_status),
167         m_safe_to_return (safe_to_return)
168     { }
169 
170     exit_exception (const exit_exception&) = default;
171 
172     exit_exception& operator = (exit_exception&) = default;
173 
174     ~exit_exception (void) = default;
175 
what(void)176     const char * what (void) const noexcept { return "exit exception"; }
177 
exit_status(void)178     int exit_status (void) const { return m_exit_status; }
179 
safe_to_return(void)180     bool safe_to_return (void) const { return m_safe_to_return; }
181 
182   private:
183 
184     int m_exit_status;
185 
186     bool m_safe_to_return;
187   };
188 
189   class interrupt_exception : public std::exception
190   {
191   public:
192 
193     interrupt_exception (void) = default;
194 
195     interrupt_exception (const interrupt_exception&) = default;
196 
197     interrupt_exception& operator = (const interrupt_exception&) = default;
198 
199     ~interrupt_exception (void) = default;
200 
what(void)201     const char * what (void) const noexcept { return "interrupt exception"; }
202   };
203 }
204 
205 #endif
206 
207 // The following enum values are deprecated and will eventually be
208 // removed from Octave, but there seems to be no universally good way
209 // to tag them with an attribute that will generate a warning.
210 
211 enum
212 octave_exception
213 {
214   octave_no_exception = 0,
215   octave_exec_exception = 1,
216   octave_alloc_exception = 3,
217   octave_quit_exception = 4
218 };
219 
220 /*
221   > 0: interrupt pending
222     0: no interrupt pending
223   < 0: handling interrupt
224 */
225 OCTAVE_API extern sig_atomic_t octave_interrupt_state;
226 
227 OCTAVE_DEPRECATED (6, "'octave_exception_state' is an obsolete internal variable; any uses should be removed")
228 OCTAVE_API extern sig_atomic_t octave_exception_state;
229 
230 OCTAVE_API extern volatile sig_atomic_t octave_signal_caught;
231 
232 OCTAVE_API extern void octave_handle_signal (void);
233 
234 OCTAVE_DEPRECATED (6, "use 'throw octave::interrupt_exception' instead")
235 OCTAVE_NORETURN OCTAVE_API extern void octave_throw_interrupt_exception (void);
236 
237 OCTAVE_DEPRECATED (6, "use 'throw octave::execution_exception' instead")
238 OCTAVE_NORETURN OCTAVE_API extern void octave_throw_execution_exception (void);
239 
240 OCTAVE_DEPRECATED (6, "use 'throw std::bad_alloc' instead")
241 OCTAVE_NORETURN OCTAVE_API extern void octave_throw_bad_alloc (void);
242 
243 OCTAVE_DEPRECATED (6, "use 'throw' instead")
244 OCTAVE_API extern void octave_rethrow_exception (void);
245 
246 #if defined (__cplusplus)
247 
octave_quit(void)248 inline void octave_quit (void)
249 {
250   if (octave_signal_caught)
251     {
252       octave_signal_caught = 0;
253       octave_handle_signal ();
254     }
255 };
256 
257 #define OCTAVE_QUIT octave_quit ()
258 
259 #else
260 
261 #define OCTAVE_QUIT                             \
262   do                                            \
263     {                                           \
264       if (octave_signal_caught)                 \
265         {                                       \
266           octave_signal_caught = 0;             \
267           octave_handle_signal ();              \
268         }                                       \
269     }                                           \
270   while (0)
271 #endif
272 
273 /* The following macros are obsolete.  Interrupting immediately by
274    calling siglongjmp or similar from a signal handler is asking for
275    trouble.  Rather than remove them, however, please leave them in
276    place so that old code that uses them will continue to compile.  They
277    are defined to create a dummy do-while block to match the previous
278    definitions.  */
279 
280 #define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE     \
281   do                                                    \
282     {
283 
284 #define END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE       \
285     }                                                   \
286   while (0)
287 
288 #if defined (__cplusplus)
289 
290 /* Likewise, these are obsolete.  They are defined to create a
291    dummy scope to match the previous versions that created a try-catch
292    block.  */
293 
294 #define BEGIN_INTERRUPT_WITH_EXCEPTIONS         \
295   {
296 
297 #define END_INTERRUPT_WITH_EXCEPTIONS           \
298   }
299 
300 #endif
301 
302 #if defined (__cplusplus)
303 }
304 
305 /* These should only be declared for C++ code, and should also be
306    outside of any extern "C" block.  */
307 
308 extern OCTAVE_API void (*octave_signal_hook) (void);
309 extern OCTAVE_API void (*octave_interrupt_hook) (void);
310 
311 OCTAVE_DEPRECATED (6, "'octave_bad_alloc_hook' is obsolete and no longer used")
312 extern OCTAVE_API void (*octave_bad_alloc_hook) (void);
313 
314 #endif
315 
316 #endif
317