1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-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 (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29
30 #include <cstdarg>
31 #include <cstdlib>
32 #include <cstring>
33
34 #include <algorithm>
35 #include <iomanip>
36 #include <iostream>
37 #include <sstream>
38 #include <string>
39
40 #include "quit.h"
41
42 #include "bp-table.h"
43 #include "builtin-defun-decls.h"
44 #include "defun.h"
45 #include "error.h"
46 #include "input.h"
47 #include "interpreter-private.h"
48 #include "interpreter.h"
49 #include "oct-map.h"
50 #include "octave.h"
51 #include "ov-usr-fcn.h"
52 #include "ov.h"
53 #include "ovl.h"
54 #include "pager.h"
55 #include "pt-eval.h"
56 #include "unwind-prot.h"
57 #include "utils.h"
58 #include "variables.h"
59
60 static std::string
format_message(const char * fmt,va_list args)61 format_message (const char *fmt, va_list args)
62 {
63 if (! fmt)
64 return "";
65
66 std::ostringstream output_buf;
67
68 octave::vformat (output_buf, fmt, args);
69
70 return output_buf.str ();
71 }
72
73 OCTAVE_NORETURN
74 static void
error_1(octave::execution_exception & e,const char * id,const char * fmt,va_list args)75 error_1 (octave::execution_exception& e, const char *id, const char *fmt,
76 va_list args)
77 {
78 octave::error_system& es = octave::__get_error_system__ ("error_1");
79
80 es.error_1 (e, id, fmt, args);
81 }
82
83 OCTAVE_NORETURN
84 static void
error_1(const char * id,const char * fmt,va_list args)85 error_1 (const char *id, const char *fmt, va_list args)
86 {
87 octave::error_system& es = octave::__get_error_system__ ("error_1");
88
89 es.error_1 (id, fmt, args);
90 }
91
92 static int
check_state(const std::string & state)93 check_state (const std::string& state)
94 {
95 // -1: not found
96 // 0: found, "off"
97 // 1: found, "on"
98 // 2: found, "error"
99
100 if (state == "off")
101 return 0;
102 else if (state == "on")
103 return 1;
104 else if (state == "error")
105 return 2;
106 else
107 return -1;
108 }
109
110 static void
vwarning(const char * id,const char * fmt,va_list args)111 vwarning (const char *id, const char *fmt, va_list args)
112 {
113 octave::error_system& es = octave::__get_error_system__ ("warning");
114
115 es.vwarning (id, fmt, args);
116 }
117
118 static void
defun_usage_message(const char * fmt,...)119 defun_usage_message (const char *fmt, ...)
120 {
121 va_list args;
122 va_start (args, fmt);
123 error_1 ("", fmt, args);
124 va_end (args);
125 }
126
127 typedef void (*error_fun)(const char *, const char *, ...);
128
129 static std::string
handle_message(error_fun f,const char * id,const char * msg,const octave_value_list & args,bool have_fmt)130 handle_message (error_fun f, const char *id, const char *msg,
131 const octave_value_list& args, bool have_fmt)
132 {
133 std::string retval;
134
135 std::string tmpstr;
136
137 if (args.length () > 0)
138 {
139 octave_value arg;
140
141 if (have_fmt)
142 {
143 octave_value_list tmp = Fsprintf (args, 1);
144 arg = tmp(0);
145 }
146 else
147 arg = args(0);
148
149 if (arg.is_defined ())
150 {
151 if (arg.isempty ())
152 return retval;
153 else if (arg.is_string ())
154 {
155 tmpstr = arg.string_value (); // 2-stage assignment required
156 msg = tmpstr.c_str (); // in order to generate pointer
157 // to valid memory.
158 }
159 }
160 }
161
162 // Ugh.
163
164 std::size_t len = strlen (msg);
165
166 if (len > 0)
167 {
168 if (msg[len - 1] == '\n')
169 {
170 if (len > 1)
171 {
172 std::string tmp_msg (msg, len - 1);
173 f (id, "%s\n", tmp_msg.c_str ());
174 retval = tmp_msg;
175 }
176 }
177 else
178 {
179 f (id, "%s", msg);
180 retval = msg;
181 }
182 }
183
184 return retval;
185 }
186
187 // Determine whether the first argument to error or warning function
188 // should be handled as the message identifier or as the format string.
189
190 static bool
maybe_extract_message_id(const std::string & caller,const octave_value_list & args,octave_value_list & nargs,std::string & id)191 maybe_extract_message_id (const std::string& caller,
192 const octave_value_list& args,
193 octave_value_list& nargs,
194 std::string& id)
195 {
196 nargs = args;
197 id = "";
198
199 int nargin = args.length ();
200
201 bool have_fmt = nargin > 1;
202
203 if (nargin > 0)
204 {
205 std::string arg1 = args(0).string_value ();
206
207 // For compatibility with Matlab, an identifier must contain ':',
208 // but not at the beginning or the end, and it must not contain '%'
209 // (even if it is not a valid conversion operator) or whitespace.
210
211 if (arg1.find_first_of ("% \f\n\r\t\v") == std::string::npos
212 && arg1.find (':') != std::string::npos
213 && arg1[0] != ':'
214 && arg1.back () != ':')
215 {
216 if (nargin > 1)
217 {
218 id = arg1;
219
220 nargs.resize (nargin-1);
221
222 for (int i = 1; i < nargin; i++)
223 nargs(i-1) = args(i);
224 }
225 else
226 nargs(0) = "call to " + caller
227 + " with message identifier '" + arg1
228 + "' requires message";
229 }
230 }
231
232 return have_fmt;
233 }
234
235 namespace octave
236 {
237 static octave_scalar_map
init_warning_options(const std::string & state)238 init_warning_options (const std::string& state)
239 {
240 octave_scalar_map initw;
241
242 initw.setfield ("identifier", "all");
243 initw.setfield ("state", state);
244
245 return initw;
246 }
247
248 static octave_map
init_error_stack(interpreter & interp)249 init_error_stack (interpreter& interp)
250 {
251 tree_evaluator& tw = interp.get_evaluator ();
252
253 return tw.empty_backtrace ();
254 }
255
error_system(interpreter & interp)256 error_system::error_system (interpreter& interp)
257 : m_interpreter (interp),
258 m_debug_on_error (false),
259 m_debug_on_caught (false),
260 m_debug_on_warning (false),
261 m_discard_warning_messages (false),
262 m_beep_on_error (false),
263 m_backtrace_on_warning (true),
264 m_verbose_warning (false),
265 m_quiet_warning (false),
266 m_warning_options (init_warning_options ("on")),
267 m_last_error_message (),
268 m_last_warning_message (),
269 m_last_warning_id (),
270 m_last_error_id (),
271 m_last_error_stack (init_error_stack (interp))
272 {
273 initialize_default_warning_state ();
274 }
275
276 octave_value
debug_on_error(const octave_value_list & args,int nargout)277 error_system::debug_on_error (const octave_value_list& args, int nargout)
278 {
279 return set_internal_variable (m_debug_on_error, args, nargout,
280 "debug_on_error");
281 }
282
283 octave_value
debug_on_caught(const octave_value_list & args,int nargout)284 error_system::debug_on_caught (const octave_value_list& args, int nargout)
285 {
286 return set_internal_variable (m_debug_on_caught, args, nargout,
287 "debug_on_caught");
288 }
289
290 octave_value
debug_on_warning(const octave_value_list & args,int nargout)291 error_system::debug_on_warning (const octave_value_list& args, int nargout)
292 {
293 return set_internal_variable (m_debug_on_warning, args, nargout,
294 "debug_on_warning");
295 }
296
297 octave_value
discard_warning_messages(const octave_value_list & args,int nargout)298 error_system::discard_warning_messages (const octave_value_list& args,
299 int nargout)
300 {
301 return set_internal_variable (m_discard_warning_messages, args, nargout,
302 "discard_warning_messages");
303 }
304
305 octave_value
beep_on_error(const octave_value_list & args,int nargout)306 error_system::beep_on_error (const octave_value_list& args, int nargout)
307 {
308 return set_internal_variable (m_beep_on_error, args, nargout,
309 "beep_on_error");
310 }
311
312 octave_value
backtrace_on_warning(const octave_value_list & args,int nargout)313 error_system::backtrace_on_warning (const octave_value_list& args,
314 int nargout)
315 {
316 return set_internal_variable (m_backtrace_on_warning, args, nargout,
317 "backtrace_on_warning");
318 }
319
320 octave_value
verbose_warning(const octave_value_list & args,int nargout)321 error_system::verbose_warning (const octave_value_list& args, int nargout)
322 {
323 return set_internal_variable (m_verbose_warning, args, nargout,
324 "verbose_warning");
325 }
326
327 octave_value
quiet_warning(const octave_value_list & args,int nargout)328 error_system::quiet_warning (const octave_value_list& args, int nargout)
329 {
330 return set_internal_variable (m_quiet_warning, args, nargout,
331 "quiet_warning");
332 }
333
334 octave_value
last_error_message(const octave_value_list & args,int nargout)335 error_system::last_error_message (const octave_value_list& args, int nargout)
336 {
337 return set_internal_variable (m_last_error_message, args, nargout,
338 "last_error_message");
339 }
340
341 octave_value
last_warning_message(const octave_value_list & args,int nargout)342 error_system::last_warning_message (const octave_value_list& args,
343 int nargout)
344 {
345 return set_internal_variable (m_last_warning_message, args, nargout,
346 "last_warning_message");
347 }
348
349 octave_value
last_warning_id(const octave_value_list & args,int nargout)350 error_system::last_warning_id (const octave_value_list& args, int nargout)
351 {
352 return set_internal_variable (m_last_warning_id, args, nargout,
353 "last_warning_id");
354 }
355
356 octave_value
last_error_id(const octave_value_list & args,int nargout)357 error_system::last_error_id (const octave_value_list& args, int nargout)
358 {
359 return set_internal_variable (m_last_error_id, args, nargout,
360 "last_error_id");
361 }
362
363 // Use static fields for the best efficiency.
364 // NOTE: C++0x will allow these two to be merged into one.
365 static const char *bt_fieldnames[] =
366 { "file", "name", "line", "column", nullptr };
367
368 static const octave_fields bt_fields (bt_fieldnames);
369
370 octave_map
make_stack_map(const std::list<octave::frame_info> & frames)371 error_system::make_stack_map (const std::list<octave::frame_info>& frames)
372 {
373 std::size_t nframes = frames.size ();
374
375 octave_map retval (dim_vector (nframes, 1), bt_fields);
376
377 Cell& file = retval.contents (0);
378 Cell& name = retval.contents (1);
379 Cell& line = retval.contents (2);
380 Cell& column = retval.contents (3);
381
382 bool have_column = false;
383
384 octave_idx_type k = 0;
385
386 for (const auto& frm : frames)
387 {
388 file(k) = frm.file_name ();
389 name(k) = frm.fcn_name ();
390 line(k) = frm.line ();
391 int c = frm.column ();
392 if (c > 0)
393 {
394 have_column = true;
395 column(k) = c;
396 }
397
398 k++;
399 }
400
401 if (! have_column)
402 retval.rmfield ("column");
403
404 return retval;
405 }
406
407 std::list<octave::frame_info>
make_stack_frame_list(const octave_map & stack)408 error_system::make_stack_frame_list (const octave_map& stack)
409 {
410 std::list<octave::frame_info> frames;
411
412 Cell file = stack.contents ("file");
413 Cell name = stack.contents ("name");
414 Cell line = stack.contents ("line");
415 Cell column;
416 bool have_column = false;
417 if (stack.contains ("column"))
418 {
419 have_column = true;
420 column = stack.contents ("column");
421 }
422
423 octave_idx_type nel = name.numel ();
424
425 for (octave_idx_type i = 0; i < nel; i++)
426 frames.push_back (octave::frame_info (file(i).string_value (),
427 name(i).string_value (),
428 line(i).int_value (),
429 (have_column
430 ? column(i).int_value () : -1)));
431
432 return frames;
433 }
434
435 // For given warning ID, return 0 if warnings are disabled, 1 if
436 // enabled, and 2 if the given ID should be an error instead of a
437 // warning.
438
warning_enabled(const std::string & id)439 int error_system::warning_enabled (const std::string& id)
440 {
441 int retval = 0;
442
443 int all_state = -1;
444 int id_state = -1;
445
446 octave_map opts = warning_options ();
447
448 octave_idx_type nel = opts.numel ();
449
450 if (nel > 0)
451 {
452 Cell identifier = opts.contents ("identifier");
453 Cell state = opts.contents ("state");
454
455 bool all_found = false;
456 bool id_found = false;
457
458 for (octave_idx_type i = 0; i < nel; i++)
459 {
460 octave_value ov = identifier(i);
461 std::string ovs = ov.string_value ();
462
463 if (! all_found && ovs == "all")
464 {
465 all_state = check_state (state(i).string_value ());
466
467 if (all_state >= 0)
468 all_found = true;
469 }
470
471 if (! id_found && ovs == id)
472 {
473 id_state = check_state (state(i).string_value ());
474
475 if (id_state >= 0)
476 id_found = true;
477 }
478
479 if (all_found && id_found)
480 break;
481 }
482 }
483
484 // If "all" is not present, assume warnings are enabled.
485 if (all_state == -1)
486 all_state = 1;
487
488 if (all_state == 0)
489 {
490 if (id_state >= 0)
491 retval = id_state;
492 }
493 else if (all_state == 1)
494 {
495 if (id_state == 0 || id_state == 2)
496 retval = id_state;
497 else
498 retval = all_state;
499 }
500 else if (all_state == 2)
501 {
502 if (id_state == 0)
503 retval= id_state;
504 else
505 retval = all_state;
506 }
507
508 return retval;
509 }
510
vusage(const char * id,const char * fmt,va_list args)511 void error_system::vusage (const char *id, const char *fmt, va_list args)
512 {
513 std::string str_id = id ? id : "";
514 std::string message = format_message (fmt, args);
515
516 throw_error ("usage", id, message);
517 }
518
vwarning(const char * name,const char * id,const char * fmt,va_list args)519 void error_system::vwarning (const char *name, const char *id,
520 const char *fmt, va_list args)
521 {
522 flush_stdout ();
523
524 std::string base_msg = format_message (fmt, args);
525 std::string msg_string;
526
527 if (name)
528 msg_string = std::string (name) + ": ";
529
530 msg_string += base_msg;
531
532 bool fmt_suppresses_backtrace = false;
533 std::size_t fmt_len = (fmt ? strlen (fmt) : 0);
534 fmt_suppresses_backtrace = (fmt_len > 0 && fmt[fmt_len-1] == '\n');
535
536 if (! fmt_suppresses_backtrace)
537 msg_string += '\n';
538
539 last_warning_id (id);
540 last_warning_message (base_msg);
541
542 if (discard_warning_messages ())
543 return;
544
545 tree_evaluator& tw = m_interpreter.get_evaluator ();
546
547 bool in_user_code = tw.in_user_code ();
548
549 if (! quiet_warning ())
550 {
551 octave_diary << msg_string;
552 std::cerr << msg_string;
553
554 if (! fmt_suppresses_backtrace && in_user_code
555 && backtrace_on_warning ()
556 && ! discard_warning_messages ())
557 {
558 std::string bt_msg = tw.backtrace_message ();
559
560 if (! bt_msg.empty ())
561 bt_msg = "warning: called from\n" + bt_msg;
562
563 octave_diary << bt_msg << std::endl;
564 std::cerr << bt_msg << std::endl;
565 }
566 }
567
568 bp_table& bptab = tw.get_bp_table ();
569
570 if ((m_interpreter.interactive ()
571 || application::forced_interactive ())
572 && debug_on_warning () && in_user_code && bptab.debug_on_warn (id))
573 {
574 unwind_protect frame;
575
576 frame.protect_var (m_debug_on_warning);
577 m_debug_on_warning = false;
578
579 tw.enter_debugger ();
580 }
581 }
582
error_1(execution_exception & e,const char * id,const char * fmt,va_list args)583 void error_system::error_1 (execution_exception& e, const char *id,
584 const char *fmt, va_list args)
585 {
586 e.set_identifier (id);
587 e.set_message (format_message (fmt, args));
588
589 throw_error (e);
590 }
591
error_1(const char * id,const char * fmt,va_list args)592 void error_system::error_1 (const char *id, const char *fmt,
593 va_list args)
594 {
595 std::string message = format_message (fmt, args);
596
597 std::list<frame_info> stack_info;
598
599 throw_error ("error", id, message);
600 }
601
vwarning(const char * id,const char * fmt,va_list args)602 void error_system::vwarning (const char *id, const char *fmt, va_list args)
603 {
604 int warn_opt = warning_enabled (id);
605
606 if (warn_opt == 2)
607 {
608 // Handle this warning as an error.
609
610 error_1 (id, fmt, args);
611 }
612 else if (warn_opt == 1)
613 vwarning ("warning", id, fmt, args);
614 }
615
rethrow_error(const std::string & id,const std::string & msg,const octave_map & stack)616 void error_system::rethrow_error (const std::string& id,
617 const std::string& msg,
618 const octave_map& stack)
619 {
620 std::list<frame_info> stack_info;
621
622 execution_exception e ("error", id, msg, stack_info);
623
624 if (! stack.isempty ()
625 && ! (stack.contains ("file") && stack.contains ("name")
626 && stack.contains ("line")))
627 error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'");
628
629 if (! stack.isempty ())
630 e.set_stack_info (make_stack_frame_list (stack));
631
632 throw_error (e);
633 }
634
vpanic(const char * fmt,va_list args)635 void error_system::vpanic (const char *fmt, va_list args)
636 {
637 // Is there any point in trying to write the panic message to the
638 // diary?
639
640 std::cerr << "panic: " << format_message (fmt, args) << std::endl;
641
642 abort ();
643 }
644
panic(const char * fmt,...)645 void error_system::panic (const char *fmt, ...)
646 {
647 va_list args;
648 va_start (args, fmt);
649 vpanic (fmt, args);
650 va_end (args);
651 }
652
warning_query(const std::string & id_arg)653 octave_scalar_map error_system::warning_query (const std::string& id_arg)
654 {
655 octave_scalar_map retval;
656
657 std::string id = id_arg;
658
659 if (id == "last")
660 id = last_warning_id ();
661
662 octave_map opts = warning_options ();
663
664 Cell ident = opts.contents ("identifier");
665 Cell state = opts.contents ("state");
666
667 octave_idx_type nel = ident.numel ();
668
669 assert (nel != 0);
670
671 bool found = false;
672
673 std::string val;
674
675 for (octave_idx_type i = 0; i < nel; i++)
676 {
677 if (ident(i).string_value () == id)
678 {
679 val = state(i).string_value ();
680 found = true;
681 break;
682 }
683 }
684
685 if (! found)
686 {
687 for (octave_idx_type i = 0; i < nel; i++)
688 {
689 if (ident(i).string_value () == "all")
690 {
691 val = state(i).string_value ();
692 found = true;
693 break;
694 }
695 }
696 }
697
698 // The warning state "all" is always supposed to remain in the list,
699 // so we should always find a state, either explicitly or by using the
700 // state for "all".
701
702 assert (found);
703
704 retval.assign ("identifier", id);
705 retval.assign ("state", val);
706
707 return retval;
708 }
709
default_warning_state(void)710 std::string error_system::default_warning_state (void)
711 {
712 std::string retval = "on";
713
714 octave_map opts = warning_options ();
715
716 Cell ident = opts.contents ("identifier");
717 Cell state = opts.contents ("state");
718
719 octave_idx_type nel = ident.numel ();
720
721 for (octave_idx_type i = 0; i < nel; i++)
722 {
723 if (ident(i).string_value () == "all")
724 {
725 retval = state(i).string_value ();
726 break;
727 }
728 }
729
730 return retval;
731 }
732
display_warning_options(std::ostream & os)733 void error_system::display_warning_options (std::ostream& os)
734 {
735 octave_map opts = warning_options ();
736
737 Cell ident = opts.contents ("identifier");
738 Cell state = opts.contents ("state");
739
740 octave_idx_type nel = ident.numel ();
741
742 std::string all_state = default_warning_state ();
743
744 if (all_state == "on")
745 os << "By default, warnings are enabled.";
746 else if (all_state == "off")
747 os << "By default, warnings are disabled.";
748 else if (all_state == "error")
749 os << "By default, warnings are treated as errors.";
750 else
751 panic_impossible ();
752
753 if (nel > 1)
754 os << "\n\n";
755
756 // The state for all is always supposed to be first in the list.
757
758 for (octave_idx_type i = 1; i < nel; i++)
759 {
760 std::string tid = ident(i).string_value ();
761 std::string tst = state(i).string_value ();
762
763 os << std::setw (7) << tst << " " << tid << "\n";
764 }
765
766 os << std::endl;
767 }
768
set_warning_option(const std::string & state,const std::string & ident)769 void error_system::set_warning_option (const std::string& state,
770 const std::string& ident)
771 {
772 std::string all_state = default_warning_state ();
773
774 if (state != "on" && state != "off" && state != "error")
775 error ("invalid warning state: %s", state.c_str ());
776
777 octave_map opts = warning_options ();
778
779 Cell tid = opts.contents ("identifier");
780 Cell tst = opts.contents ("state");
781
782 octave_idx_type nel = tid.numel ();
783
784 for (octave_idx_type i = 0; i < nel; i++)
785 {
786 if (tid(i).string_value () == ident)
787 {
788 // We found it in the current list of options. If the state
789 // for "all" is same as arg1, we can simply remove the item
790 // from the list.
791
792 if (state == all_state && ident != "all")
793 {
794 for (i = i + 1; i < nel; i++)
795 {
796 tid(i-1) = tid(i);
797 tst(i-1) = tst(i);
798 }
799
800 tid.resize (dim_vector (1, nel-1));
801 tst.resize (dim_vector (1, nel-1));
802 }
803 else
804 tst(i) = state;
805
806 opts.clear ();
807
808 opts.assign ("identifier", tid);
809 opts.assign ("state", tst);
810
811 warning_options (opts);
812
813 return;
814 }
815 }
816
817 // The option wasn't already in the list. Append it.
818
819 tid.resize (dim_vector (1, nel+1));
820 tst.resize (dim_vector (1, nel+1));
821
822 tid(nel) = ident;
823 tst(nel) = state;
824
825 opts.clear ();
826
827 opts.assign ("identifier", tid);
828 opts.assign ("state", tst);
829
830 warning_options (opts);
831 }
832
disable_warning(const std::string & id)833 void error_system::disable_warning (const std::string& id)
834 {
835 set_warning_option ("off", id);
836 }
837
initialize_default_warning_state(void)838 void error_system::initialize_default_warning_state (void)
839 {
840 warning_options (init_warning_options ("on"));
841
842 // Most people will want to have the following disabled.
843
844 disable_warning ("Octave:array-as-logical");
845 disable_warning ("Octave:array-to-scalar");
846 disable_warning ("Octave:array-to-vector");
847 disable_warning ("Octave:imag-to-real");
848 disable_warning ("Octave:language-extension");
849 disable_warning ("Octave:missing-semicolon");
850 disable_warning ("Octave:neg-dim-as-zero");
851 disable_warning ("Octave:separator-insert");
852 disable_warning ("Octave:single-quote-string");
853 disable_warning ("Octave:str-to-num");
854 disable_warning ("Octave:mixed-string-concat");
855 disable_warning ("Octave:variable-switch-label");
856 }
857
interpreter_try(unwind_protect & frame)858 void error_system::interpreter_try (unwind_protect& frame)
859 {
860 frame.protect_var (m_debug_on_error);
861 m_debug_on_error = false;
862
863 frame.protect_var (m_debug_on_warning);
864 m_debug_on_warning = false;
865
866 // Leave debug_on_caught as it was, so errors in try/catch are still
867 // caught.
868 }
869
throw_error(const std::string & err_type,const std::string & id,const std::string & message,const std::list<frame_info> & stack_info_arg)870 void error_system::throw_error (const std::string& err_type,
871 const std::string& id,
872 const std::string& message,
873 const std::list<frame_info>& stack_info_arg)
874 {
875 std::list<frame_info> stack_info = stack_info_arg;
876
877 if (stack_info.empty ())
878 {
879 tree_evaluator& tw = m_interpreter.get_evaluator ();
880
881 stack_info = tw.backtrace_info ();
882
883 // Print the error message only if it is different from the
884 // previous one; makes the output more concise and readable.
885
886 stack_info.unique ();
887 }
888
889 execution_exception ex (err_type, id, message, stack_info);
890
891 throw_error (ex);
892 }
893
throw_error(execution_exception & ex)894 void error_system::throw_error (execution_exception& ex)
895 {
896 throw ex;
897 }
898
save_exception(const execution_exception & e)899 void error_system::save_exception (const execution_exception& e)
900 {
901 last_error_id (e.identifier ());
902 std::string message = e.message ();
903 std::string xmsg
904 = (message.size () > 0 && message.back () == '\n'
905 ? message.substr (0, message.size () - 1) : message);
906 last_error_message (xmsg);
907 last_error_stack (make_stack_map (e.stack_info ()));
908 }
909
display_exception(const execution_exception & e,std::ostream & os) const910 void error_system::display_exception (const execution_exception& e,
911 std::ostream& os) const
912 {
913 if (m_beep_on_error)
914 os << "\a";
915
916 e.display (octave_diary);
917 e.display (os);
918 }
919 }
920
921 void
vmessage(const char * name,const char * fmt,va_list args)922 vmessage (const char *name, const char *fmt, va_list args)
923 {
924 std::string message;
925
926 if (name)
927 message = std::string (name) + ": ";
928
929 message += format_message (fmt, args);
930
931 octave_diary << message << std::endl;
932 std::cerr << message << std::endl;
933 }
934
935 void
message(const char * name,const char * fmt,...)936 message (const char *name, const char *fmt, ...)
937 {
938 va_list args;
939 va_start (args, fmt);
940 vmessage (name, fmt, args);
941 va_end (args);
942 }
943
944 void
vusage_with_id(const char * id,const char * fmt,va_list args)945 vusage_with_id (const char *id, const char *fmt, va_list args)
946 {
947 octave::error_system& es = octave::__get_error_system__ ("warning_enabled");
948
949 es.vusage (id, fmt, args);
950 }
951
952 void
usage_with_id(const char * id,const char * fmt,...)953 usage_with_id (const char *id, const char *fmt, ...)
954 {
955 va_list args;
956 va_start (args, fmt);
957 vusage_with_id (id, fmt, args);
958 va_end (args);
959 }
960
961 void
verror(const char * fmt,va_list args)962 verror (const char *fmt, va_list args)
963 {
964 error_1 ("", fmt, args);
965 }
966
967 void
error(const char * fmt,...)968 error (const char *fmt, ...)
969 {
970 va_list args;
971 va_start (args, fmt);
972 verror (fmt, args);
973 va_end (args);
974 }
975
976 void
verror(octave::execution_exception & e,const char * fmt,va_list args)977 verror (octave::execution_exception& e, const char *fmt, va_list args)
978 {
979 error_1 (e, "", fmt, args);
980 }
981
982 void
error(octave::execution_exception & e,const char * fmt,...)983 error (octave::execution_exception& e, const char *fmt, ...)
984 {
985 va_list args;
986 va_start (args, fmt);
987 verror (e, fmt, args);
988 va_end (args);
989 }
990
991 void
verror_with_cfn(const char * fmt,va_list args)992 verror_with_cfn (const char *fmt, va_list args)
993 {
994 error_1 ("", fmt, args);
995 }
996
997 void
error_with_cfn(const char * fmt,...)998 error_with_cfn (const char *fmt, ...)
999 {
1000 va_list args;
1001 va_start (args, fmt);
1002 verror_with_cfn (fmt, args);
1003 va_end (args);
1004 }
1005
1006 void
verror_with_id(const char * id,const char * fmt,va_list args)1007 verror_with_id (const char *id, const char *fmt, va_list args)
1008 {
1009 error_1 (id, fmt, args);
1010 }
1011
1012 void
error_with_id(const char * id,const char * fmt,...)1013 error_with_id (const char *id, const char *fmt, ...)
1014 {
1015 va_list args;
1016 va_start (args, fmt);
1017 verror_with_id (id, fmt, args);
1018 va_end (args);
1019 }
1020
1021 void
verror_with_id_cfn(const char * id,const char * fmt,va_list args)1022 verror_with_id_cfn (const char *id, const char *fmt, va_list args)
1023 {
1024 error_1 (id, fmt, args);
1025 }
1026
1027 void
error_with_id_cfn(const char * id,const char * fmt,...)1028 error_with_id_cfn (const char *id, const char *fmt, ...)
1029 {
1030 va_list args;
1031 va_start (args, fmt);
1032 verror_with_id_cfn (id, fmt, args);
1033 va_end (args);
1034 }
1035
warning_enabled(const std::string & id)1036 int warning_enabled (const std::string& id)
1037 {
1038 octave::error_system& es = octave::__get_error_system__ ("warning_enabled");
1039
1040 return es.warning_enabled (id);
1041 }
1042
1043 void
vwarning(const char * fmt,va_list args)1044 vwarning (const char *fmt, va_list args)
1045 {
1046 vwarning ("", fmt, args);
1047 }
1048
1049 void
warning(const char * fmt,...)1050 warning (const char *fmt, ...)
1051 {
1052 va_list args;
1053 va_start (args, fmt);
1054 vwarning (fmt, args);
1055 va_end (args);
1056 }
1057
1058 void
vwarning_with_id(const char * id,const char * fmt,va_list args)1059 vwarning_with_id (const char *id, const char *fmt, va_list args)
1060 {
1061 vwarning (id, fmt, args);
1062 }
1063
1064 void
warning_with_id(const char * id,const char * fmt,...)1065 warning_with_id (const char *id, const char *fmt, ...)
1066 {
1067 va_list args;
1068 va_start (args, fmt);
1069 vwarning (id, fmt, args);
1070 va_end (args);
1071 }
1072
1073 void
vparse_error(const char * fmt,va_list args)1074 vparse_error (const char *fmt, va_list args)
1075 {
1076 error_1 ("", fmt, args);
1077 }
1078
1079 void
parse_error(const char * fmt,...)1080 parse_error (const char *fmt, ...)
1081 {
1082 va_list args;
1083 va_start (args, fmt);
1084 vparse_error (fmt, args);
1085 va_end (args);
1086 }
1087
1088 void
vparse_error_with_id(const char * id,const char * fmt,va_list args)1089 vparse_error_with_id (const char *id, const char *fmt, va_list args)
1090 {
1091 error_1 (id, fmt, args);
1092 }
1093
1094 void
parse_error_with_id(const char * id,const char * fmt,...)1095 parse_error_with_id (const char *id, const char *fmt, ...)
1096 {
1097 va_list args;
1098 va_start (args, fmt);
1099 vparse_error_with_id (id, fmt, args);
1100 va_end (args);
1101 }
1102
1103 OCTAVE_NORETURN
1104 void
vpanic(const char * fmt,va_list args)1105 vpanic (const char *fmt, va_list args)
1106 {
1107 octave::error_system& es = octave::__get_error_system__ ("vpanic");
1108
1109 es.vpanic (fmt, args);
1110 }
1111
1112 OCTAVE_NORETURN
1113 void
panic(const char * fmt,...)1114 panic (const char *fmt, ...)
1115 {
1116 va_list args;
1117 va_start (args, fmt);
1118 vpanic (fmt, args);
1119 va_end (args);
1120 }
1121
1122 void
defun_usage_message(const std::string & msg)1123 defun_usage_message (const std::string& msg)
1124 {
1125 defun_usage_message ("%s", msg.c_str ());
1126 }
1127
1128 DEFMETHOD (rethrow, interp, args, ,
1129 doc: /* -*- texinfo -*-
1130 @deftypefn {} {} rethrow (@var{err})
1131 Reissue a previous error as defined by @var{err}.
1132
1133 @var{err} is a structure that must contain at least the @qcode{"message"}
1134 and @qcode{"identifier"} fields. @var{err} can also contain a field
1135 @qcode{"stack"} that gives information on the assumed location of the
1136 error. Typically @var{err} is returned from @code{lasterror}.
1137 @seealso{lasterror, lasterr, error}
1138 @end deftypefn */)
1139 {
1140 if (args.length () != 1)
1141 print_usage ();
1142
1143 const octave_scalar_map err = args(0).scalar_map_value ();
1144
1145 if (! (err.contains ("message") && err.contains ("identifier")))
1146 error ("rethrow: ERR struct must contain the fields 'message' and 'identifier'");
1147
1148 std::string msg = err.contents ("message").string_value ();
1149 std::string id = err.contents ("identifier").string_value ();
1150
1151 octave_map err_stack = octave::init_error_stack (interp);
1152
1153 if (err.contains ("stack"))
1154 err_stack = err.contents ("stack").xmap_value ("ERR.STACK must be a struct");
1155
1156 octave::error_system& es = interp.get_error_system ();
1157
1158 es.rethrow_error (id, msg, err_stack);
1159
1160 return ovl ();
1161 }
1162
1163 DEFMETHOD (error, interp, args, ,
1164 doc: /* -*- texinfo -*-
1165 @deftypefn {} {} error (@var{template}, @dots{})
1166 @deftypefnx {} {} error (@var{id}, @var{template}, @dots{})
1167 Display an error message and stop m-file execution.
1168
1169 Format the optional arguments under the control of the template string
1170 @var{template} using the same rules as the @code{printf} family of
1171 functions (@pxref{Formatted Output}) and print the resulting message
1172 on the @code{stderr} stream. The message is prefixed by the character
1173 string @samp{error: }.
1174
1175 Calling @code{error} also sets Octave's internal error state such that
1176 control will return to the top level without evaluating any further
1177 commands. This is useful for aborting from functions or scripts.
1178
1179 If the error message does not end with a newline character, Octave will
1180 print a traceback of all the function calls leading to the error. For
1181 example, given the following function definitions:
1182
1183 @example
1184 @group
1185 function f () g (); end
1186 function g () h (); end
1187 function h () nargin == 1 || error ("nargin != 1"); end
1188 @end group
1189 @end example
1190
1191 @noindent
1192 calling the function @code{f} will result in a list of messages that
1193 can help you to quickly find the exact location of the error:
1194
1195 @example
1196 @group
1197 f ()
1198 error: nargin != 1
1199 error: called from:
1200 error: h at line 1, column 27
1201 error: g at line 1, column 15
1202 error: f at line 1, column 15
1203 @end group
1204 @end example
1205
1206 If the error message ends in a newline character, Octave will print the
1207 message but will not display any traceback messages as it returns
1208 control to the top level. For example, modifying the error message
1209 in the previous example to end in a newline causes Octave to only print
1210 a single message:
1211
1212 @example
1213 @group
1214 function h () nargin == 1 || error ("nargin != 1\n"); end
1215 f ()
1216 error: nargin != 1
1217 @end group
1218 @end example
1219
1220 A null string ("") input to @code{error} will be ignored and the code
1221 will continue running as if the statement were a NOP@. This is for
1222 compatibility with @sc{matlab}. It also makes it possible to write code
1223 such as
1224
1225 @example
1226 @group
1227 err_msg = "";
1228 if (CONDITION 1)
1229 err_msg = "CONDITION 1 found";
1230 elseif (CONDITION2)
1231 err_msg = "CONDITION 2 found";
1232 @dots{}
1233 endif
1234 error (err_msg);
1235 @end group
1236 @end example
1237
1238 @noindent
1239 which will only stop execution if an error has been found.
1240
1241 Implementation Note: For compatibility with @sc{matlab}, escape
1242 sequences in @var{template} (e.g., @qcode{"@xbackslashchar{}n"} =>
1243 newline) are processed regardless of whether @var{template} has been defined
1244 with single quotes, as long as there are two or more input arguments. To
1245 disable escape sequence expansion use a second backslash before the sequence
1246 (e.g., @qcode{"@xbackslashchar{}@xbackslashchar{}n"}) or use the
1247 @code{regexptranslate} function.
1248 @seealso{warning, lasterror}
1249 @end deftypefn */)
1250 {
1251
1252 int nargin = args.length ();
1253
1254 if (nargin == 0)
1255 print_usage ();
1256
1257 octave_value retval;
1258
1259 std::string id;
1260 std::string message;
1261 std::list<octave::frame_info> stack_info;
1262
1263 bool have_fmt = false;
1264
1265 if (nargin == 1 && args(0).isstruct ())
1266 {
1267 // empty struct is not an error. return and resume calling function.
1268 if (args(0).isempty ())
1269 return retval;
1270
1271 octave_scalar_map m = args(0).scalar_map_value ();
1272
1273 // empty struct is not an error. return and resume calling function.
1274 if (m.nfields () == 0)
1275 return retval;
1276
1277 if (m.contains ("message"))
1278 {
1279 octave_value c = m.getfield ("message");
1280
1281 if (c.is_string ())
1282 message = c.string_value ();
1283 }
1284
1285 if (m.contains ("identifier"))
1286 {
1287 octave_value c = m.getfield ("identifier");
1288
1289 if (c.is_string ())
1290 id = c.string_value ();
1291 }
1292
1293 if (m.contains ("stack"))
1294 {
1295 octave_value c = m.getfield ("stack");
1296
1297 if (c.isstruct ())
1298 stack_info
1299 = octave::error_system::make_stack_frame_list (c.map_value ());
1300 }
1301 }
1302 else
1303 {
1304 octave_value_list nargs = args;
1305
1306 have_fmt = maybe_extract_message_id ("error", args, nargs, id);
1307
1308 if (nargs.length () == 0)
1309 message = "unspecified error";
1310 else
1311 {
1312 octave_value arg;
1313
1314 if (have_fmt)
1315 {
1316 octave_value_list tmp = Fsprintf (nargs, 1);
1317 arg = tmp(0);
1318 }
1319 else
1320 arg = nargs(0);
1321
1322 if (arg.is_defined ())
1323 {
1324 if (arg.isempty ())
1325 message = "";
1326 else if (arg.is_string ())
1327 message = arg.string_value ();
1328 }
1329 }
1330 }
1331
1332 if (message.empty ())
1333 return retval;
1334
1335 octave::error_system& es = interp.get_error_system ();
1336
1337 es.throw_error ("error", id, message, stack_info);
1338
1339 return retval;
1340 }
1341
1342 DEFMETHOD (warning, interp, args, nargout,
1343 doc: /* -*- texinfo -*-
1344 @deftypefn {} {} warning (@var{template}, @dots{})
1345 @deftypefnx {} {} warning (@var{id}, @var{template}, @dots{})
1346 @deftypefnx {} {} warning ("on", @var{id})
1347 @deftypefnx {} {} warning ("off", @var{id})
1348 @deftypefnx {} {} warning ("error", @var{id})
1349 @deftypefnx {} {} warning ("query", @var{id})
1350 @deftypefnx {} {} warning (@var{state}, @var{id}, "local")
1351 @deftypefnx {} {} warning (@var{warning_struct})
1352 @deftypefnx {} {@var{warning_struct} =} warning (@dots{})
1353 @deftypefnx {} {} warning (@var{state}, @var{mode})
1354
1355 Display a warning message or control the behavior of Octave's warning system.
1356
1357 The first call form uses a template @var{template} and optional additional
1358 arguments to display a message on the @code{stderr} stream. The message is
1359 formatted using the same rules as the @code{printf} family of functions
1360 (@pxref{Formatted Output}) and prefixed by the character string
1361 @w{@samp{warning: }}. You should use this function when you want to notify the
1362 user of an unusual condition, but only when it makes sense for your program to
1363 go on. For example:
1364
1365 @example
1366 @group
1367 warning ("foo: maybe something wrong here");
1368 @end group
1369 @end example
1370
1371 If the warning message does not end with a newline character, Octave will
1372 print a traceback of all the function calls leading to the warning. If the
1373 warning message does end in a newline character, Octave will suppress the
1374 traceback messages as it returns control to the top level. For more details
1375 and examples, see @ref{XREFerror,,error}.
1376
1377 The optional warning identifier @var{id} allows users to enable or disable
1378 warnings tagged by this identifier. A message identifier is a string of the
1379 form @qcode{"NAMESPACE:WARNING-NAME"}. Octave's own warnings use the
1380 @qcode{"Octave"} namespace (@pxref{XREFwarning_ids,,warning_ids}). For
1381 example:
1382
1383 @example
1384 @group
1385 warning ("MyNameSpace:check-something",
1386 "foo: maybe something wrong here");
1387 @end group
1388 @end example
1389
1390 The second call form is meant to change and/or query the state of warnings.
1391 The first input argument must be a string @var{state} (@qcode{"on"},
1392 @qcode{"off"}, @qcode{"error"}, or @qcode{"query"}) followed by an optional
1393 warning identifier @var{id} or @qcode{"all"} (default).
1394
1395 The optional output argument @var{warning_struct} is a structure or structure
1396 array with fields @qcode{"state"} and @qcode{"identifier"}. The @var{state}
1397 argument may have the following values:
1398
1399 @table @asis
1400 @item @qcode{"on"}|@qcode{"off"}:
1401 Enable or disable the display of warnings identified by @var{id} and optionally
1402 return their previous state @var{stout}.
1403
1404 @item @qcode{"error"}:
1405 Turn warnings identified by @var{id} into errors and optionally return their
1406 previous state @var{stout}.
1407
1408 @item @qcode{"query"}:
1409 Return the current state of warnings identified by @var{id}.
1410 @end table
1411
1412 A structure or structure array @var{warning_struct}, with fields
1413 @qcode{"state"} and @qcode{"identifier"}, may be given as an input to achieve
1414 equivalent results. The following example shows how to temporarily disable a
1415 warning and then restore its original state:
1416
1417 @example
1418 @group
1419 loglog (-1:10);
1420 ## Disable the previous warning and save its original state
1421 [~, id] = lastwarn ();
1422 warnstate = warning ("off", id);
1423 loglog (-1:10);
1424 ## Restore its original state
1425 warning (warnstate);
1426 @end group
1427 @end example
1428
1429 If a final argument @qcode{"local"} is provided then the warning state will be
1430 set temporarily until the end of the current function. Changes to warning
1431 states that are set locally affect the current function and all functions
1432 called from the current scope. The previous warning state is restored on
1433 return from the current function. The @qcode{"local"} option is ignored if
1434 used in the top-level workspace.
1435
1436 With no input argument @code{warning ()} is equivalent to
1437 @code{warning ("query", "all")} except that in the absence of an output
1438 argument, the state of warnings is displayed on @code{stderr}.
1439
1440 The level of verbosity of the warning system may also be controlled by two
1441 modes @var{mode}:
1442
1443 @table @asis
1444 @item @qcode{"backtrace"}:
1445 enable/disable the display of the stack trace after the warning message
1446
1447 @item @qcode{"verbose"}:
1448 enable/disable the display of additional information after the warning message
1449 @end table
1450
1451 In this case the @var{state} argument may only be @qcode{"on"} or
1452 @qcode{"off"}.
1453
1454 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
1455 @var{template} (e.g., @qcode{"@xbackslashchar{}n"} => newline) are processed
1456 regardless of whether @var{template} has been defined with single quotes, as
1457 long as there are two or more input arguments. To disable escape sequence
1458 expansion use a second backslash before the sequence (e.g.,
1459 @qcode{"@xbackslashchar{}@xbackslashchar{}n"}) or use the
1460 @code{regexptranslate} function.
1461 @seealso{warning_ids, lastwarn, error}
1462 @end deftypefn */)
1463 {
1464 octave_value retval;
1465
1466 int nargin = args.length ();
1467 bool done = false;
1468
1469 octave::error_system& es = interp.get_error_system ();
1470
1471 if (nargin > 0 && args.all_strings_p ())
1472 {
1473 string_vector argv = args.make_argv ("warning");
1474
1475 std::string arg1 = argv[1];
1476 std::transform (arg1.begin (), arg1.end (), arg1.begin (), tolower);
1477 std::string arg2 = "all";
1478 std::string arg2_lc = "all";
1479
1480 if (nargin >= 2)
1481 {
1482 arg2 = argv[2];
1483 arg2_lc = arg2;
1484 std::transform (arg2_lc.begin (), arg2_lc.end (), arg2_lc.begin (),
1485 tolower);
1486 }
1487
1488 if (arg1 == "on" || arg1 == "off" || arg1 == "error")
1489 {
1490 // Prepare output structure
1491 octave_map old_warning_options;
1492 if (arg2_lc == "all")
1493 old_warning_options = es.warning_options ();
1494 else
1495 old_warning_options = octave_map (es.warning_query (arg2));
1496
1497 if (nargin == 3)
1498 {
1499 std::string arg3_lc = argv[3];
1500 std::transform (arg3_lc.begin (), arg3_lc.end (),
1501 arg3_lc.begin (), tolower);
1502 if (arg3_lc == "local" && ! interp.at_top_level ())
1503 {
1504 octave_scalar_map val = es.warning_query (arg2);
1505
1506 octave_value curr_state = val.contents ("state");
1507
1508 // FIXME: this might be better with a dictionary object.
1509
1510 octave::tree_evaluator& tw = interp.get_evaluator ();
1511
1512 octave_value curr_warning_states
1513 = tw.get_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES);
1514
1515 octave_map m;
1516
1517 if (curr_warning_states.is_defined ())
1518 m = curr_warning_states.map_value ();
1519 else
1520 {
1521 string_vector fields (2);
1522
1523 fields(0) = "identifier";
1524 fields(1) = "state";
1525
1526 m = octave_map (dim_vector (0, 1), fields);
1527 }
1528
1529 Cell ids = m.contents ("identifier");
1530 Cell states = m.contents ("state");
1531
1532 octave_idx_type nel = states.numel ();
1533 bool found = false;
1534 octave_idx_type i;
1535 for (i = 0; i < nel; i++)
1536 {
1537 std::string id = ids(i).string_value ();
1538
1539 if (id == arg2)
1540 {
1541 states(i) = curr_state;
1542 found = true;
1543 break;
1544 }
1545 }
1546
1547 if (! found)
1548 {
1549 m.resize (dim_vector (nel+1, 1));
1550
1551 ids.resize (dim_vector (nel+1, 1));
1552 states.resize (dim_vector (nel+1, 1));
1553
1554 ids(nel) = arg2;
1555 states(nel) = curr_state;
1556 }
1557
1558 m.contents ("identifier") = ids;
1559 m.contents ("state") = states;
1560
1561 tw.set_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES, m);
1562
1563 // Now ignore the "local" argument and continue to
1564 // handle the current setting.
1565 nargin--;
1566 }
1567 }
1568
1569 if (nargin >= 2 && arg2_lc == "all")
1570 {
1571 // If "all" is explicitly given as ID.
1572
1573 octave_map tmp;
1574 int is_error = (arg1 == "error");
1575
1576 Cell id (1, 1 + 2*is_error);
1577 Cell st (1, 1 + 2*is_error);
1578
1579 id(0) = "all";
1580 st(0) = arg1;
1581
1582 // Since internal Octave functions are not compatible,
1583 // and "all"=="error" causes any "on" to throw an error,
1584 // turning all warnings into errors should disable
1585 // Octave:language-extension.
1586
1587 if (is_error)
1588 {
1589 id(1) = "Octave:language-extension";
1590 st(1) = "off";
1591
1592 id(2) = "Octave:single-quote-string";
1593 st(2) = "off";
1594 }
1595
1596 tmp.assign ("identifier", id);
1597 tmp.assign ("state", st);
1598
1599 es.warning_options (tmp);
1600
1601 done = true;
1602 }
1603 else if (arg2_lc == "backtrace")
1604 {
1605 if (arg1 != "error")
1606 {
1607 es.backtrace_on_warning (arg1 == "on");
1608 done = true;
1609 }
1610 }
1611 else if (arg2_lc == "debug")
1612 {
1613 if (arg1 != "error")
1614 {
1615 es.debug_on_warning (arg1 == "on");
1616 done = true;
1617 }
1618 }
1619 else if (arg2_lc == "verbose")
1620 {
1621 if (arg1 != "error")
1622 {
1623 es.verbose_warning (arg1 == "on");
1624 done = true;
1625 }
1626 }
1627 else if (arg2_lc == "quiet")
1628 {
1629 if (arg1 != "error")
1630 {
1631 es.quiet_warning (arg1 == "on");
1632 done = true;
1633 }
1634 }
1635 else
1636 {
1637 if (arg2_lc == "last")
1638 arg2 = es.last_warning_id ();
1639
1640 es.set_warning_option (arg1, arg2);
1641
1642 done = true;
1643 }
1644
1645 if (done && nargout > 0)
1646 retval = old_warning_options;
1647 }
1648 else if (arg1 == "query")
1649 {
1650 if (arg2_lc == "all")
1651 retval = es.warning_options ();
1652 else if (arg2_lc == "backtrace" || arg2_lc == "debug"
1653 || arg2_lc == "verbose" || arg2_lc == "quiet")
1654 {
1655 octave_scalar_map tmp;
1656 tmp.assign ("identifier", arg2_lc);
1657 if (arg2_lc == "backtrace")
1658 tmp.assign ("state", es.backtrace_on_warning () ? "on" : "off");
1659 else if (arg2_lc == "debug")
1660 tmp.assign ("state", es.debug_on_warning () ? "on" : "off");
1661 else if (arg2_lc == "verbose")
1662 tmp.assign ("state", es.verbose_warning () ? "on" : "off");
1663 else
1664 tmp.assign ("state", es.quiet_warning () ? "on" : "off");
1665
1666 retval = tmp;
1667 }
1668 else
1669 retval = es.warning_query (arg2);
1670
1671 done = true;
1672 }
1673 }
1674 else if (nargin == 0)
1675 {
1676 if (nargout > 0)
1677 retval = es.warning_options ();
1678 else
1679 es.display_warning_options (octave_stdout);
1680
1681 done = true;
1682 }
1683 else if (nargin == 1)
1684 {
1685 octave_value arg = args(0);
1686
1687 octave_map old_warning_options;
1688
1689 if (arg.isstruct ())
1690 {
1691 octave_map m = arg.map_value ();
1692
1693 if (! m.contains ("identifier") || ! m.contains ("state"))
1694 error ("warning: STATE structure must have fields 'identifier' and 'state'");
1695
1696 // Simply step through the struct elements one at a time.
1697
1698 Cell ident = m.contents ("identifier");
1699 Cell state = m.contents ("state");
1700
1701 octave_idx_type nel = ident.numel ();
1702
1703 // Prepare output structure
1704 old_warning_options = octave_map (m);
1705 Cell oldstate (state);
1706
1707 for (octave_idx_type i = 0; i < nel; i++)
1708 {
1709 std::string tid = ident(i).string_value ();
1710 oldstate(i) = es.warning_query (tid).getfield ("state");
1711 }
1712 old_warning_options.setfield ("state", oldstate);
1713
1714 // Set new values
1715 for (octave_idx_type i = 0; i < nel; i++)
1716 {
1717 std::string tst = state(i).string_value ();
1718 std::string tid = ident(i).string_value ();
1719
1720 es.set_warning_option (tst, tid);
1721 }
1722
1723 done = true;
1724
1725 if (nargout > 0)
1726 retval = old_warning_options;
1727 }
1728 }
1729
1730 if (! done)
1731 {
1732 octave_value_list nargs = args;
1733
1734 std::string id;
1735
1736 bool have_fmt = maybe_extract_message_id ("warning", args, nargs, id);
1737
1738 std::string prev_msg = es.last_warning_message ();
1739
1740 std::string curr_msg = handle_message (warning_with_id, id.c_str (),
1741 "unspecified warning", nargs,
1742 have_fmt);
1743
1744 if (nargout > 0)
1745 retval = prev_msg;
1746 }
1747
1748 return retval;
1749 }
1750
1751 /*
1752 %!test <*45753>
1753 %! warning ("error");
1754 %! assert (! isempty (help ("warning")));
1755
1756 %!test <*51997>
1757 %! id = "Octave:logical-conversion";
1758 %! current = warning ("query", id);
1759 %! current_all = warning ();
1760 %! previous = warning (current_all);
1761 %! assert (previous, current_all);
1762 %! previous = warning (current);
1763 %! assert (previous, current);
1764 %! previous = warning (current.state, id);
1765 %! assert (previous, current);
1766
1767 %!test <*57290>
1768 %! warning ("oN", "Octave:test-57290-ID");
1769 %! warnst = warning ("QUery", "Octave:test-57290-ID");
1770 %! assert (warnst.state, "on");
1771 %! assert (warnst.identifier, "Octave:test-57290-ID");
1772 %! warning ("OFF", "Octave:test-57290-ID");
1773 %! warnst = warning ("QUery", "ALL");
1774 %! idx = strcmp ({warnst.identifier}, "Octave:test-57290-ID");
1775 %! assert (warnst(idx).state, "off");
1776
1777 */
1778
1779 octave_value_list
set_warning_state(const std::string & id,const std::string & state)1780 set_warning_state (const std::string& id, const std::string& state)
1781 {
1782 octave_value_list args;
1783
1784 args(1) = id;
1785 args(0) = state;
1786
1787 octave::interpreter& interp
1788 = octave::__get_interpreter__ ("set_warning_state");
1789
1790 return Fwarning (interp, args, 1);
1791 }
1792
1793 octave_value_list
set_warning_state(const octave_value_list & args)1794 set_warning_state (const octave_value_list& args)
1795 {
1796 octave::interpreter& interp
1797 = octave::__get_interpreter__ ("set_warning_state");
1798
1799 return Fwarning (interp, args, 1);
1800 }
1801
1802 void
disable_warning(const std::string & id)1803 disable_warning (const std::string& id)
1804 {
1805 octave::error_system& es = octave::__get_error_system__ ("disable_warning");
1806
1807 es.disable_warning (id);
1808 }
1809
1810 DEFMETHOD (lasterror, interp, args, ,
1811 doc: /* -*- texinfo -*-
1812 @deftypefn {} {@var{lasterr} =} lasterror ()
1813 @deftypefnx {} {} lasterror (@var{err})
1814 @deftypefnx {} {} lasterror ("reset")
1815 Query or set the last error message structure.
1816
1817 When called without arguments, return a structure containing the last error
1818 message and other information related to this error. The elements of the
1819 structure are:
1820
1821 @table @code
1822 @item message
1823 The text of the last error message
1824
1825 @item identifier
1826 The message identifier of this error message
1827
1828 @item stack
1829 A structure containing information on where the message occurred. This may
1830 be an empty structure if the information cannot be obtained. The fields of
1831 the structure are:
1832
1833 @table @code
1834 @item file
1835 The name of the file where the error occurred
1836
1837 @item name
1838 The name of function in which the error occurred
1839
1840 @item line
1841 The line number at which the error occurred
1842
1843 @item column
1844 An optional field with the column number at which the error occurred
1845 @end table
1846 @end table
1847
1848 The last error structure may be set by passing a scalar structure,
1849 @var{err}, as input. Any fields of @var{err} that match those above are
1850 set while any unspecified fields are initialized with default values.
1851
1852 If @code{lasterror} is called with the argument @qcode{"reset"}, all
1853 fields are set to their default values.
1854 @seealso{lasterr, error, lastwarn}
1855 @end deftypefn */)
1856 {
1857 int nargin = args.length ();
1858
1859 if (nargin > 1)
1860 print_usage ();
1861
1862 octave::error_system& es = interp.get_error_system ();
1863
1864 octave_scalar_map err;
1865
1866 err.assign ("message", es.last_error_message ());
1867 err.assign ("identifier", es.last_error_id ());
1868
1869 err.assign ("stack", octave_value (es.last_error_stack ()));
1870
1871 if (nargin == 1)
1872 {
1873 octave::tree_evaluator& tw = interp.get_evaluator ();
1874
1875 if (args(0).is_string ())
1876 {
1877 if (args(0).string_value () != "reset")
1878 error ("lasterror: unrecognized string argument");
1879
1880 es.last_error_message ("");
1881 es.last_error_id ("");
1882
1883 es.last_error_stack (tw.empty_backtrace ());
1884 }
1885 else if (args(0).isstruct ())
1886 {
1887 octave_scalar_map new_err = args(0).scalar_map_value ();
1888 octave_scalar_map new_err_stack;
1889 std::string new_error_message;
1890 std::string new_error_id;
1891 std::string new_error_file;
1892 std::string new_error_name;
1893 int new_error_line = -1;
1894 int new_error_column = -1;
1895 bool initialize_stack = false;
1896
1897 if (new_err.contains ("message"))
1898 {
1899 const std::string tmp
1900 = new_err.getfield ("message").string_value ();
1901 new_error_message = tmp;
1902 }
1903
1904 if (new_err.contains ("identifier"))
1905 {
1906 const std::string tmp
1907 = new_err.getfield ("identifier").string_value ();
1908 new_error_id = tmp;
1909 }
1910
1911 if (new_err.contains ("stack"))
1912 {
1913 if (new_err.getfield ("stack").isempty ())
1914 initialize_stack = true;
1915 else
1916 {
1917 new_err_stack
1918 = new_err.getfield ("stack").scalar_map_value ();
1919
1920 if (new_err_stack.contains ("file"))
1921 {
1922 const std::string tmp
1923 = new_err_stack.getfield ("file").string_value ();
1924 new_error_file = tmp;
1925 }
1926
1927 if (new_err_stack.contains ("name"))
1928 {
1929 const std::string tmp
1930 = new_err_stack.getfield ("name").string_value ();
1931 new_error_name = tmp;
1932 }
1933
1934 if (new_err_stack.contains ("line"))
1935 {
1936 const int tmp
1937 = new_err_stack.getfield ("line").nint_value ();
1938 new_error_line = tmp;
1939 }
1940
1941 if (new_err_stack.contains ("column"))
1942 {
1943 const int tmp
1944 = new_err_stack.getfield ("column").nint_value ();
1945 new_error_column = tmp;
1946 }
1947 }
1948 }
1949
1950 es.last_error_message (new_error_message);
1951 es.last_error_id (new_error_id);
1952
1953 if (initialize_stack)
1954 es.last_error_stack (tw.empty_backtrace ());
1955 else if (new_err.contains ("stack"))
1956 {
1957 new_err_stack.setfield ("file", new_error_file);
1958 new_err_stack.setfield ("name", new_error_name);
1959 new_err_stack.setfield ("line", new_error_line);
1960 new_err_stack.setfield ("column", new_error_column);
1961
1962 es.last_error_stack (new_err_stack);
1963 }
1964 else
1965 es.last_error_stack (tw.backtrace ());
1966 }
1967 else
1968 error ("lasterror: argument must be a structure or a string");
1969 }
1970
1971 return ovl (err);
1972 }
1973
1974 /*
1975 ## Test lasterror with empty error state
1976 %!test
1977 %! lasterror ("reset");
1978 %! x = lasterror ();
1979 %! assert (x.identifier, "")
1980 %! assert (x.message, "")
1981 %! assert (isempty (x.stack))
1982 %! lasterror (x);
1983 %! y = lasterror ();
1984 %! assert (y, x);
1985 */
1986
1987 DEFMETHOD (lasterr, interp, args, nargout,
1988 doc: /* -*- texinfo -*-
1989 @deftypefn {} {[@var{msg}, @var{msgid}] =} lasterr ()
1990 @deftypefnx {} {} lasterr (@var{msg})
1991 @deftypefnx {} {} lasterr (@var{msg}, @var{msgid})
1992 Query or set the last error message.
1993
1994 When called without input arguments, return the last error message and
1995 message identifier.
1996
1997 With one argument, set the last error message to @var{msg}.
1998
1999 With two arguments, also set the last message identifier.
2000 @seealso{lasterror, error, lastwarn}
2001 @end deftypefn */)
2002 {
2003 int nargin = args.length ();
2004
2005 if (nargin > 2)
2006 print_usage ();
2007
2008 octave::error_system& es = interp.get_error_system ();
2009
2010 string_vector argv = args.make_argv ("lasterr");
2011
2012 std::string prev_error_id = es.last_error_id ();
2013 std::string prev_error_message = es.last_error_message ();
2014
2015 if (nargin == 2)
2016 {
2017 es.last_error_id (argv[2]);
2018 es.last_error_message (argv[1]);
2019 }
2020 else if (nargin == 1)
2021 {
2022 es.last_error_id ("");
2023 es.last_error_message (argv[1]);
2024 }
2025
2026 if (nargin == 0 || nargout > 0)
2027 return ovl (prev_error_message, prev_error_id);
2028 else
2029 return ovl ();
2030 }
2031
2032 DEFMETHOD (lastwarn, interp, args, nargout,
2033 doc: /* -*- texinfo -*-
2034 @deftypefn {} {[@var{msg}, @var{msgid}] =} lastwarn ()
2035 @deftypefnx {} {} lastwarn (@var{msg})
2036 @deftypefnx {} {} lastwarn (@var{msg}, @var{msgid})
2037 Query or set the last warning message.
2038
2039 When called without input arguments, return the last warning message and
2040 message identifier.
2041
2042 With one argument, set the last warning message to @var{msg}.
2043
2044 With two arguments, also set the last message identifier.
2045 @seealso{warning, lasterror, lasterr}
2046 @end deftypefn */)
2047 {
2048 int nargin = args.length ();
2049
2050 if (nargin > 2)
2051 print_usage ();
2052
2053 octave::error_system& es = interp.get_error_system ();
2054
2055 string_vector argv = args.make_argv ("lastwarn");
2056
2057 std::string prev_warning_id = es.last_warning_id ();
2058 std::string prev_warning_message = es.last_warning_message ();
2059
2060 if (nargin == 2)
2061 {
2062 es.last_warning_id (argv[2]);
2063 es.last_warning_message (argv[1]);
2064 }
2065 else if (nargin == 1)
2066 {
2067 es.last_warning_id ("");
2068 es.last_warning_message (argv[1]);
2069 }
2070
2071 if (nargin == 0 || nargout > 0)
2072 return ovl (prev_warning_message, prev_warning_id);
2073 else
2074 return ovl ();
2075 }
2076
2077 DEFMETHOD (beep_on_error, interp, args, nargout,
2078 doc: /* -*- texinfo -*-
2079 @deftypefn {} {@var{val} =} beep_on_error ()
2080 @deftypefnx {} {@var{old_val} =} beep_on_error (@var{new_val})
2081 @deftypefnx {} {} beep_on_error (@var{new_val}, "local")
2082 Query or set the internal variable that controls whether Octave will try
2083 to ring the terminal bell before printing an error message.
2084
2085 When called from inside a function with the @qcode{"local"} option, the
2086 variable is changed locally for the function and any subroutines it calls.
2087 The original variable value is restored when exiting the function.
2088 @end deftypefn */)
2089 {
2090 octave::error_system& es = interp.get_error_system ();
2091
2092 return es.beep_on_error (args, nargout);
2093 }
2094
2095 DEFMETHOD (debug_on_error, interp, args, nargout,
2096 doc: /* -*- texinfo -*-
2097 @deftypefn {} {@var{val} =} debug_on_error ()
2098 @deftypefnx {} {@var{old_val} =} debug_on_error (@var{new_val})
2099 @deftypefnx {} {} debug_on_error (@var{new_val}, "local")
2100 Query or set the internal variable that controls whether Octave will try
2101 to enter the debugger when an error is encountered.
2102
2103 This will also inhibit printing of the normal traceback message (you will
2104 only see the top-level error message).
2105
2106 When called from inside a function with the @qcode{"local"} option, the
2107 variable is changed locally for the function and any subroutines it calls.
2108 The original variable value is restored when exiting the function.
2109 @seealso{debug_on_warning, debug_on_interrupt}
2110 @end deftypefn */)
2111 {
2112 octave::error_system& es = interp.get_error_system ();
2113
2114 return es.debug_on_error (args, nargout);
2115 }
2116
2117 DEFMETHOD (debug_on_warning, interp, args, nargout,
2118 doc: /* -*- texinfo -*-
2119 @deftypefn {} {@var{val} =} debug_on_warning ()
2120 @deftypefnx {} {@var{old_val} =} debug_on_warning (@var{new_val})
2121 @deftypefnx {} {} debug_on_warning (@var{new_val}, "local")
2122 Query or set the internal variable that controls whether Octave will try
2123 to enter the debugger when a warning is encountered.
2124
2125 When called from inside a function with the @qcode{"local"} option, the
2126 variable is changed locally for the function and any subroutines it calls.
2127 The original variable value is restored when exiting the function.
2128 @seealso{debug_on_error, debug_on_interrupt}
2129 @end deftypefn */)
2130 {
2131 octave::error_system& es = interp.get_error_system ();
2132
2133 return es.debug_on_warning (args, nargout);
2134 }
2135
2136 std::string
last_error_message(void)2137 last_error_message (void)
2138 {
2139 octave::error_system& es
2140 = octave::__get_error_system__ ("last_error_message");
2141
2142 return es.last_error_message ();
2143 }
2144
2145 std::string
last_error_id(void)2146 last_error_id (void)
2147 {
2148 octave::error_system& es
2149 = octave::__get_error_system__ ("last_error_id");
2150
2151 return es.last_error_id ();
2152 }
2153
2154 octave_map
last_error_stack(void)2155 last_error_stack (void)
2156 {
2157 octave::error_system& es
2158 = octave::__get_error_system__ ("last_error_stack");
2159
2160 return es.last_error_stack ();
2161 }
2162
2163 std::string
last_warning_message(void)2164 last_warning_message (void)
2165 {
2166 octave::error_system& es
2167 = octave::__get_error_system__ ("last_warning_message");
2168
2169 return es.last_warning_message ();
2170 }
2171
2172 std::string
last_warning_id(void)2173 last_warning_id (void)
2174 {
2175 octave::error_system& es
2176 = octave::__get_error_system__ ("last_warning_id");
2177
2178 return es.last_warning_id ();
2179 }
2180
2181 void
interpreter_try(octave::unwind_protect & frame)2182 interpreter_try (octave::unwind_protect& frame)
2183 {
2184 octave::error_system& es
2185 = octave::__get_error_system__ ("interpreter_try");
2186
2187 es.interpreter_try (frame);
2188 }
2189
2190 // Deprecated variables and functions.
2191
2192 // This variable is obsolete and always has the value 0.
2193 int error_state = 0;
2194