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