changelog shortlog tags changeset files revisions annotate raw

src/error.cc

changeset 10289: 4b124317dc38
parent:2cd940306a06
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (52 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
4 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <cstdarg>
29#include <cstring>
30
31#include <iostream>
32#include <sstream>
33#include <string>
34
35#include "defun.h"
36#include "error.h"
37#include "input.h"
38#include "pager.h"
39#include "oct-obj.h"
40#include "oct-map.h"
41#include "utils.h"
42#include "ov.h"
43#include "ov-usr-fcn.h"
44#include "pt-pr-code.h"
45#include "pt-stmt.h"
46#include "toplev.h"
47#include "unwind-prot.h"
48#include "variables.h"
49
50// TRUE means that Octave will try to beep obnoxiously before printing
51// error messages.
52static bool Vbeep_on_error = false;
53
54// TRUE means that Octave will try to enter the debugger when an error
55// is encountered. This will also inhibit printing of the normal
56// traceback message (you will only see the top-level error message).
57bool Vdebug_on_error = false;
58
59// TRUE means that Octave will try to enter the debugger when a warning
60// is encountered.
61bool Vdebug_on_warning = false;
62
63// TRUE means that Octave will try to display a stack trace when a
64// warning is encountered.
65static bool Vbacktrace_on_warning = false;
66
67// TRUE means that Octave will print a verbose warning. Currently unused.
68static bool Vverbose_warning;
69
70// TRUE means that Octave will print no warnings, but lastwarn will be
71//updated
72static bool Vquiet_warning = false;
73
74// A structure containing (most of) the current state of warnings.
75static Octave_map warning_options;
76
77// The text of the last error message.
78static std::string Vlast_error_message;
79
80// The text of the last warning message.
81static std::string Vlast_warning_message;
82
83// The last warning message id.
84static std::string Vlast_warning_id;
85
86// The last error message id.
87static std::string Vlast_error_id;
88
89// The last file in which an error occured
90static Octave_map Vlast_error_stack;
91
92// Current error state.
93//
94// Valid values:
95//
96// -2: an error has occurred, but don't print any messages.
97// -1: an error has occurred, we are printing a traceback
98// 0: no error
99// 1: an error has occurred
100//
101int error_state = 0;
102
103// Current warning state.
104//
105// Valid values:
106//
107// 0: no warning
108// 1: a warning has occurred
109//
110int warning_state = 0;
111
112// Tell the error handler whether to print messages, or just store
113// them for later. Used for handling errors in eval() and
114// the `unwind_protect' statement.
115int buffer_error_messages = 0;
116
117// TRUE means error messages are turned off.
118bool discard_error_messages = false;
119
120// TRUE means warning messages are turned off.
121bool discard_warning_messages = false;
122
123// The message buffer.
124static std::ostringstream *error_message_buffer = 0;
125
126void
127reset_error_handler (void)
128{
129 error_state = 0;
130 warning_state = 0;
131 buffer_error_messages = 0;
132 discard_error_messages = false;
133}
134
135static void
136initialize_warning_options (const std::string& state)
137{
138 warning_options.clear ();
139
140 warning_options.assign ("identifier", "all");
141 warning_options.assign ("state", state);
142}
143
144static Octave_map
145initialize_last_error_stack (void)
146{
147 static bool initialized = false;
148
149 static string_vector sv (4);
150
151 if (! initialized)
152 {
153 sv[0] = "file";
154 sv[1] = "name";
155 sv[2] = "line";
156 sv[3] = "column";
157
158 initialized = true;
159 }
160
161 return Octave_map (dim_vector (0, 1), sv);
162}
163
164// Warning messages are never buffered.
165
166static void
167vwarning (const char *name, const char *id, const char *fmt, va_list args)
168{
169 if (discard_warning_messages)
170 return;
171
172 flush_octave_stdout ();
173
174 std::ostringstream output_buf;
175
176 if (name)
177 output_buf << name << ": ";
178
179 octave_vformat (output_buf, fmt, args);
180
181 output_buf << std::endl;
182
183 // FIXME -- we really want to capture the message before it
184 // has all the formatting goop attached to it. We probably also
185 // want just the message, not the traceback information.
186
187 std::string msg_string = output_buf.str ();
188
189 if (! warning_state)
190 {
191 // This is the first warning in a possible series.
192
193 Vlast_warning_id = id;
194 Vlast_warning_message = msg_string;
195 }
196
197 if (! Vquiet_warning)
198 {
199 octave_diary << msg_string;
200
201 std::cerr << msg_string;
202 }
203}
204
205static void
206verror (bool save_last_error, std::ostream& os,
207 const char *name, const char *id, const char *fmt, va_list args,
208 bool with_cfn = false)
209{
210 if (discard_error_messages)
211 return;
212
213 if (! buffer_error_messages)
214 flush_octave_stdout ();
215
216 // FIXME -- we really want to capture the message before it
217 // has all the formatting goop attached to it. We probably also
218 // want just the message, not the traceback information.
219
220 std::ostringstream output_buf;
221
222 octave_vformat (output_buf, fmt, args);
223
224 std::string base_msg = output_buf.str ();
225
226 bool to_beep_or_not_to_beep_p = Vbeep_on_error && ! error_state;
227
228 std::string msg_string;
229
230 if (to_beep_or_not_to_beep_p)
231 msg_string = "\a";
232
233 if (name)
234 msg_string += std::string (name) + ": ";
235
236 // If with_fcn is specified, we'll attempt to prefix the message with the name
237 // of the current executing function. But we'll do so only if:
238 // 1. the name is not empty (anonymous function)
239 // 2. it is not already there (including the following colon)
240 if (with_cfn)
241 {
242 octave_function *curfcn = octave_call_stack::current ();
243 if (curfcn)
244 {
245 std::string cfn = curfcn->name ();
246 if (! cfn.empty ())
247 {
248 cfn += ':';
249 if (cfn.length () > base_msg.length ()
250 || base_msg.compare (0, cfn.length (), cfn) != 0)
251 {
252 msg_string += cfn + ' ';
253 }
254 }
255 }
256 }
257
258 msg_string += base_msg + "\n";
259
260 if (! error_state && save_last_error)
261 {
262 // This is the first error in a possible series.
263
264 Vlast_error_id = id;
265 Vlast_error_message = base_msg;
266
267 octave_user_code *fcn = octave_call_stack::caller_user_code ();
268
269 if (fcn)
270 {
271 octave_idx_type curr_frame = -1;
272
273 Vlast_error_stack = octave_call_stack::backtrace (0, curr_frame);
274 }
275 else
276 Vlast_error_stack = initialize_last_error_stack ();
277 }
278
279 if (buffer_error_messages)
280 {
281 if (error_message_buffer)
282 msg_string = "error: " + msg_string;
283 else
284 error_message_buffer = new std::ostringstream ();
285
286 *error_message_buffer << msg_string;
287 }
288 else
289 {
290 octave_diary << msg_string;
291 os << msg_string;
292 }
293}
294
295// Note that we don't actually print any message if the error string
296// is just "" or "\n". This allows error ("") and error ("\n") to
297// just set the error state.
298
299static void
300error_1 (std::ostream& os, const char *name, const char *id,
301 const char *fmt, va_list args, bool with_cfn = false)
302{
303 if (error_state != -2)
304 {
305 if (fmt)
306 {
307 if (*fmt)
308 {
309 size_t len = strlen (fmt);
310
311 if (len > 0)
312 {
313 if (fmt[len - 1] == '\n')
314 {
315 if (len > 1)
316 {
317 char *tmp_fmt = strsave (fmt);
318 tmp_fmt[len - 1] = '\0';
319 verror (true, os, name, id, tmp_fmt, args, with_cfn);
320 delete [] tmp_fmt;
321 }
322
323 error_state = -2;
324 }
325 else
326 {
327 verror (true, os, name, id, fmt, args, with_cfn);
328
329 if (! error_state)
330 error_state = 1;
331 }
332 }
333 }
334 }
335 else
336 panic ("error_1: invalid format");
337 }
338}
339
340void
341vmessage (const char *name, const char *fmt, va_list args)
342{
343 verror (false, std::cerr, name, "", fmt, args);
344}
345
346void
347message (const char *name, const char *fmt, ...)
348{
349 va_list args;
350 va_start (args, fmt);
351 vmessage (name, fmt, args);
352 va_end (args);
353}
354
355void
356vmessage_with_id (const char *name, const char *id, const char *fmt,
357 va_list args)
358{
359 verror (false, std::cerr, name, id, fmt, args);
360}
361
362void
363message_with_id (const char *name, const char *id, const char *fmt, ...)
364{
365 va_list args;
366 va_start (args, fmt);
367 vmessage_with_id (name, id, fmt, args);
368 va_end (args);
369}
370
371void
372usage_1 (const char *id, const char *fmt, va_list args)
373{
374 verror (true, std::cerr, "usage", id, fmt, args);
375 error_state = -1;
376}
377
378void
379vusage (const char *fmt, va_list args)
380{
381 usage_1 ("", fmt, args);
382}
383
384void
385usage (const char *fmt, ...)
386{
387 va_list args;
388 va_start (args, fmt);
389 vusage (fmt, args);
390 va_end (args);
391}
392
393void
394vusage_with_id (const char *id, const char *fmt, va_list args)
395{
396 usage_1 (id, fmt, args);
397}
398
399void
400usage_with_id (const char *id, const char *fmt, ...)
401{
402 va_list args;
403 va_start (args, fmt);
404 vusage_with_id (id, fmt, args);
405 va_end (args);
406}
407
408static void
409pr_where_2 (const char *fmt, va_list args)
410{
411 if (fmt)
412 {
413 if (*fmt)
414 {
415 size_t len = strlen (fmt);
416
417 if (len > 0)
418 {
419 if (fmt[len - 1] == '\n')
420 {
421 if (len > 1)
422 {
423 char *tmp_fmt = strsave (fmt);
424 tmp_fmt[len - 1] = '\0';
425 verror (false, std::cerr, 0, "", tmp_fmt, args);
426 delete [] tmp_fmt;
427 }
428 }
429 else
430 verror (false, std::cerr, 0, "", fmt, args);
431 }
432 }
433 }
434 else
435 panic ("pr_where_2: invalid format");
436}
437
438static void
439pr_where_1 (const char *fmt, ...)
440{
441 va_list args;
442 va_start (args, fmt);
443 pr_where_2 (fmt, args);
444 va_end (args);
445}
446
447static void
448pr_where (const char *who)
449{
450 octave_idx_type curr_frame = -1;
451
452 Octave_map stk = octave_call_stack::backtrace (0, curr_frame);
453
454 octave_idx_type nframes_to_display = stk.numel ();
455
456 if (nframes_to_display > 0)
457 {
458 pr_where_1 ("%s: called from\n", who);
459
460 Cell names = stk.contents ("name");
461 Cell lines = stk.contents ("line");
462 Cell columns = stk.contents ("column");
463
464 for (octave_idx_type i = 0; i < nframes_to_display; i++)
465 {
466 octave_value name = names(i);
467 octave_value line = lines(i);
468 octave_value column = columns(i);
469
470 std::string nm = name.string_value ();
471
472 pr_where_1 (" %s at line %d column %d\n", nm.c_str (),
473 line.int_value (), column.int_value ());
474 }
475 }
476}
477
478static void
479error_2 (const char *id, const char *fmt, va_list args, bool with_cfn = false)
480{
481 int init_state = error_state;
482
483 error_1 (std::cerr, "error", id, fmt, args, with_cfn);
484
485 if ((interactive || forced_interactive)
486 && Vdebug_on_error && init_state == 0
487 && octave_call_stack::caller_user_code ())
488 {
489 unwind_protect frame;
490 frame.protect_var (Vdebug_on_error);
491 Vdebug_on_error = false;
492
493 error_state = 0;
494
495 pr_where ("error");
496
497 do_keyboard (octave_value_list ());
498 }
499}
500
501void
502verror (const char *fmt, va_list args)
503{
504 error_2 ("", fmt, args);
505}
506
507void
508error (const char *fmt, ...)
509{
510 va_list args;
511 va_start (args, fmt);
512 verror (fmt, args);
513 va_end (args);
514}
515
516void
517verror_with_cfn (const char *fmt, va_list args)
518{
519 error_2 ("", fmt, args, true);
520}
521
522void
523error_with_cfn (const char *fmt, ...)
524{
525 va_list args;
526 va_start (args, fmt);
527 verror_with_cfn (fmt, args);
528 va_end (args);
529}
530
531void
532verror_with_id (const char *id, const char *fmt, va_list args)
533{
534 error_2 (id, fmt, args);
535}
536
537void
538error_with_id (const char *id, const char *fmt, ...)
539{
540 va_list args;
541 va_start (args, fmt);
542 verror_with_id (id, fmt, args);
543 va_end (args);
544}
545
546void
547verror_with_id_cfn (const char *id, const char *fmt, va_list args)
548{
549 error_2 (id, fmt, args, true);
550}
551
552void
553error_with_id_cfn (const char *id, const char *fmt, ...)
554{
555 va_list args;
556 va_start (args, fmt);
557 verror_with_id_cfn (id, fmt, args);
558 va_end (args);
559}
560
561static int
562check_state (const std::string& state)
563{
564 // -1: not found
565 // 0: found, "off"
566 // 1: found, "on"
567 // 2: found, "error"
568
569 if (state == "off")
570 return 0;
571 else if (state == "on")
572 return 1;
573 else if (state == "error")
574 return 2;
575 else
576 return -1;
577}
578
579// For given warning ID, return 0 if warnings are disabled, 1 if
580// enabled, and 2 if this ID should be an error instead of a warning.
581
582int
583warning_enabled (const std::string& id)
584{
585 int retval = 0;
586
587 int all_state = -1;
588 int id_state = -1;
589
590 octave_idx_type nel = warning_options.numel ();
591
592 if (nel > 0)
593 {
594 Cell identifier = warning_options.contents ("identifier");
595 Cell state = warning_options.contents ("state");
596
597 bool all_found = false;
598 bool id_found = false;
599
600 for (octave_idx_type i = 0; i < nel; i++)
601 {
602 octave_value ov = identifier(i);
603 std::string ovs = ov.string_value ();
604
605 if (! all_found && ovs == "all")
606 {
607 all_state = check_state (state(i).string_value ());
608
609 if (all_state >= 0)
610 all_found = true;
611 }
612
613 if (! id_found && ovs == id)
614 {
615 id_state = check_state (state(i).string_value ());
616
617 if (id_state >= 0)
618 id_found = true;
619 }
620
621 if (all_found && id_found)
622 break;
623 }
624 }
625
626 if (all_state == -1)
627 panic_impossible ();
628
629 if (all_state == 0)
630 {
631 if (id_state >= 0)
632 retval = id_state;
633 }
634 else if (all_state == 1)
635 {
636 if (id_state == 0 || id_state == 2)
637 retval = id_state;
638 else
639 retval = all_state;
640 }
641 else if (all_state == 2)
642 {
643 if (id_state == 0)
644 retval= id_state;
645 else
646 retval = all_state;
647 }
648
649 return retval;
650}
651
652static void
653warning_1 (const char *id, const char *fmt, va_list args)
654{
655 int warn_opt = warning_enabled (id);
656
657 if (warn_opt == 2)
658 {
659 // Handle this warning as an error.
660
661 error_2 (id, fmt, args);
662 }
663 else if (warn_opt == 1)
664 {
665 vwarning ("warning", id, fmt, args);
666
667 if (! symbol_table::at_top_level ()
668 && Vbacktrace_on_warning
669 && ! warning_state
670 && ! discard_warning_messages)
671 pr_where ("warning");
672
673 warning_state = 1;
674
675 if ((interactive || forced_interactive)
676 && Vdebug_on_warning
677 && octave_call_stack::caller_user_code ())
678 {
679 unwind_protect frame;
680 frame.protect_var (Vdebug_on_warning);
681 Vdebug_on_warning = false;
682
683 do_keyboard (octave_value_list ());
684 }
685 }
686}
687
688void
689vwarning (const char *fmt, va_list args)
690{
691 warning_1 ("", fmt, args);
692}
693
694void
695warning (const char *fmt, ...)
696{
697 va_list args;
698 va_start (args, fmt);
699 vwarning (fmt, args);
700 va_end (args);
701}
702
703void
704vwarning_with_id (const char *id, const char *fmt, va_list args)
705{
706 warning_1 (id, fmt, args);
707}
708
709void
710warning_with_id (const char *id, const char *fmt, ...)
711{
712 va_list args;
713 va_start (args, fmt);
714 vwarning_with_id (id, fmt, args);
715 va_end (args);
716}
717
718void
719vparse_error (const char *fmt, va_list args)
720{
721 error_1 (std::cerr, 0, "", fmt, args);
722}
723
724void
725parse_error (const char *fmt, ...)
726{
727 va_list args;
728 va_start (args, fmt);
729 vparse_error (fmt, args);
730 va_end (args);
731}
732
733void
734vparse_error_with_id (const char *id, const char *fmt, va_list args)
735{
736 error_1 (std::cerr, 0, id, fmt, args);
737}
738
739void
740parse_error_with_id (const char *id, const char *fmt, ...)
741{
742 va_list args;
743 va_start (args, fmt);
744 vparse_error_with_id (id, fmt, args);
745 va_end (args);
746}
747
748void
749rethrow_error (const char *id, const char *fmt, ...)
750{
751 va_list args;
752 va_start (args, fmt);
753 error_1 (std::cerr, 0, id, fmt, args);
754 va_end (args);
755}
756
757void
758panic (const char *fmt, ...)
759{
760 va_list args;
761 va_start (args, fmt);
762 buffer_error_messages = 0;
763 discard_error_messages = false;
764 verror (false, std::cerr, "panic", "", fmt, args);
765 va_end (args);
766 abort ();
767}
768
769static void
770defun_usage_message_1 (const char *fmt, ...)
771{
772 va_list args;
773 va_start (args, fmt);
774 error_1 (octave_stdout, 0, "", fmt, args);
775 va_end (args);
776}
777
778void
779defun_usage_message (const std::string& msg)
780{
781 defun_usage_message_1 ("%s", msg.c_str ());
782}
783
784typedef void (*error_fun)(const char *, const char *, ...);
785
786extern octave_value_list Fsprintf (const octave_value_list&, int);
787
788static std::string
789handle_message (error_fun f, const char *id, const char *msg,
790 const octave_value_list& args)
791{
792 std::string retval;
793
794 std::string tstr;
795
796 int nargin = args.length ();
797
798 if (nargin > 0)
799 {
800 octave_value arg;
801
802 if (nargin > 1)
803 {
804 octave_value_list tmp = Fsprintf (args, 1);
805 arg = tmp(0);
806 }
807 else
808 arg = args(0);
809
810 if (arg.is_defined ())
811 {
812 if (arg.is_string ())
813 {
814 tstr = arg.string_value ();
815 msg = tstr.c_str ();
816
817 if (! msg)
818 return retval;
819 }
820 else if (arg.is_empty ())
821 return retval;
822 }
823 }
824
825// Ugh.
826
827 size_t len = strlen (msg);
828
829 if (len > 0)
830 {
831 if (msg[len - 1] == '\n')
832 {
833 if (len > 1)
834 {
835 char *tmp_msg = strsave (msg);
836 tmp_msg[len - 1] = '\0';
837 f (id, "%s\n", tmp_msg);
838 retval = tmp_msg;
839 delete [] tmp_msg;
840 }
841 }
842 else
843 {
844 f (id, "%s", msg);
845 retval = msg;
846 }
847 }
848
849 return retval;
850}
851
852DEFUN (rethrow, args, ,
853 "-*- texinfo -*-\n\
854@deftypefn {Built-in Function} {} rethrow (@var{err})\n\
855Reissues a previous error as defined by @var{err}. @var{err} is a structure\n\
856that must contain at least the 'message' and 'identifier' fields. @var{err}\n\
857can also contain a field 'stack' that gives information on the assumed\n\
858location of the error. Typically @var{err} is returned from\n\
859@code{lasterror}.\n\
860@seealso{lasterror, lasterr, error}\n\
861@end deftypefn")
862{
863 octave_value retval;
864 int nargin = args.length();
865
866 if (nargin != 1)
867 print_usage ();
868 else
869 {
870 Octave_map err = args(0).map_value ();
871
872 if (! error_state)
873 {
874 if (err.contains ("message") && err.contains ("identifier"))
875 {
876 std::string msg = err.contents("message")(0).string_value ();
877 std::string id = err.contents("identifier")(0).string_value ();
878 int len = msg.length();
879
880 std::string file;
881 std::string nm;
882 int l = -1;
883 int c = -1;
884
885 Octave_map err_stack = initialize_last_error_stack ();
886
887 if (err.contains ("stack"))
888 {
889 err_stack = err.contents("stack")(0).map_value ();
890
891 if (err_stack.numel () > 0)
892 {
893 if (err_stack.contains ("file"))
894 file = err_stack.contents("file")(0).string_value ();
895
896 if (err_stack.contains ("name"))
897 nm = err_stack.contents("name")(0).string_value ();
898
899 if (err_stack.contains ("line"))
900 l = err_stack.contents("line")(0).nint_value ();
901
902 if (err_stack.contains ("column"))
903 c = err_stack.contents("column")(0).nint_value ();
904 }
905 }
906
907 // Ugh.
908 char *tmp_msg = strsave (msg.c_str ());
909 if (tmp_msg[len-1] == '\n')
910 {
911 if (len > 1)
912 {
913 tmp_msg[len - 1] = '\0';
914 rethrow_error (id.c_str (), "%s\n", tmp_msg);
915 }
916 }
917 else
918 rethrow_error (id.c_str (), "%s", tmp_msg);
919 delete [] tmp_msg;
920
921 // FIXME -- is this the right thing to do for
922 // Vlast_error_stack? Should it be saved and restored
923 // with unwind_protect?
924
925 Vlast_error_stack = err_stack;
926
927 if (err.contains ("stack"))
928 {
929 if (file.empty ())
930 {
931 if (nm.empty ())
932 {
933 if (l > 0)
934 {
935 if (c > 0)
936 pr_where_1 ("error: near line %d, column %d",
937 l, c);
938 else
939 pr_where_1 ("error: near line %d", l);
940 }
941 }
942 else
943 {
944 if (l > 0)
945 {
946 if (c > 0)
947 pr_where_1 ("error: called from `%s' near line %d, column %d",
948 nm.c_str (), l, c);
949 else
950 pr_where_1 ("error: called from `%d' near line %d", nm.c_str (), l);
951 }
952 }
953 }
954 else
955 {
956 if (nm.empty ())
957 {
958 if (l > 0)
959 {
960 if (c > 0)
961 pr_where_1 ("error: in file %s near line %d, column %d",
962 file.c_str (), l, c);
963 else
964 pr_where_1 ("error: in file %s near line %d", file.c_str (), l);
965 }
966 }
967 else
968 {
969 if (l > 0)
970 {
971 if (c > 0)
972 pr_where_1 ("error: called from `%s' in file %s near line %d, column %d",
973 nm.c_str (), file.c_str (), l, c);
974 else
975 pr_where_1 ("error: called from `%d' in file %s near line %d", nm.c_str (), file.c_str (), l);
976 }
977 }
978 }
979 }
980 }
981 else
982 error ("rethrow: structure must contain the fields 'message and 'identifier'");
983 }
984 }
985 return retval;
986}
987
988DEFUN (error, args, ,
989 "-*- texinfo -*-\n\
990@deftypefn {Built-in Function} {} error (@var{template}, @dots{})\n\
991@deftypefnx {Built-in Function} {} error (@var{id}, @var{template}, @dots{})\n\
992Format the optional arguments under the control of the template string\n\
993@var{template} using the same rules as the @code{printf} family of\n\
994functions (@pxref{Formatted Output}) and print the resulting message\n\
995on the @code{stderr} stream. The message is prefixed by the character\n\
996string @samp{error: }.\n\
997\n\
998Calling @code{error} also sets Octave's internal error state such that\n\
999control will return to the top level without evaluating any more\n\
1000commands. This is useful for aborting from functions or scripts.\n\
1001\n\
1002If the error message does not end with a new line character, Octave will\n\
1003print a traceback of all the function calls leading to the error. For\n\
1004example, given the following function definitions:\n\
1005\n\
1006@example\n\
1007@group\n\
1008function f () g (); end\n\
1009function g () h (); end\n\
1010function h () nargin == 1 || error (\"nargin != 1\"); end\n\
1011@end group\n\
1012@end example\n\
1013\n\
1014@noindent\n\
1015calling the function @code{f} will result in a list of messages that\n\
1016can help you to quickly locate the exact location of the error:\n\
1017\n\
1018@example\n\
1019@group\n\
1020f ()\n\
1021error: nargin != 1\n\
1022error: called from:\n\
1023error: error at line -1, column -1\n\
1024error: h at line 1, column 27\n\
1025error: g at line 1, column 15\n\
1026error: f at line 1, column 15\n\
1027@end group\n\
1028@end example\n\
1029\n\
1030If the error message ends in a new line character, Octave will print the\n\
1031message but will not display any traceback messages as it returns\n\
1032control to the top level. For example, modifying the error message\n\
1033in the previous example to end in a new line causes Octave to only print\n\
1034a single message:\n\
1035\n\
1036@example\n\
1037@group\n\
1038function h () nargin == 1 || error (\"nargin != 1\\n\"); end\n\
1039f ()\n\
1040error: nargin != 1\n\
1041@end group\n\
1042@end example\n\
1043@end deftypefn")
1044{
1045 octave_value retval;
1046
1047 int nargin = args.length ();
1048
1049 octave_value_list nargs = args;
1050
1051 std::string id;
1052
1053 if (nargin == 0)
1054 print_usage ();
1055 else
1056 {
1057 if (nargin > 1)
1058 {
1059 std::string arg1 = args(0).string_value ();
1060
1061 if (! error_state)
1062 {
1063 if (arg1.find ('%') == std::string::npos)
1064 {
1065 id = arg1;
1066
1067 nargs.resize (nargin-1);
1068
1069 for (int i = 1; i < nargin; i++)
1070 nargs(i-1) = args(i);
1071 }
1072 }
1073 else
1074 return retval;
1075 }
1076 else if (nargin == 1 && args(0).is_map ())
1077 {
1078 octave_value_list tmp;
1079
1080 Octave_map m = args(0).map_value ();
1081
1082 if (m.numel () == 1)
1083 {
1084 if (m.contains ("message"))
1085 {
1086 Cell c = m.contents ("message");
1087
1088 if (! c.is_empty () && c(0).is_string ())
1089 nargs(0) = c(0).string_value ();
1090 }
1091
1092 if (m.contains ("identifier"))
1093 {
1094 Cell c = m.contents ("identifier");
1095
1096 if (! c.is_empty () && c(0).is_string ())
1097 id = c(0).string_value ();
1098 }
1099
1100 // FIXME -- also need to handle "stack" field in error
1101 // structure, but that will require some more significant
1102 // surgery on handle_message, error_with_id, etc.
1103 }
1104 }
1105
1106 handle_message (error_with_id, id.c_str (), "unspecified error", nargs);
1107 }
1108
1109 return retval;
1110}
1111
1112DEFUN (warning, args, nargout,
1113 "-*- texinfo -*-\n\
1114@deftypefn {Built-in Function} {} warning (@var{template}, @dots{})\n\
1115@deftypefnx {Built-in Function} {} warning (@var{id}, @var{template}, @dots{})\n\
1116Format the optional arguments under the control of the template string\n\
1117@var{template} using the same rules as the @code{printf} family of\n\
1118functions (@pxref{Formatted Output}) and print the resulting message\n\
1119on the @code{stderr} stream. The message is prefixed by the character\n\
1120string @samp{warning: }.\n\
1121You should use this function when you want to notify the user\n\
1122of an unusual condition, but only when it makes sense for your program\n\
1123to go on.\n\
1124\n\
1125The optional message identifier allows users to enable or disable\n\
1126warnings tagged by @var{id}. The special identifier @samp{\"all\"} may\n\
1127be used to set the state of all warnings.\n\
1128\n\
1129@deftypefnx {Built-in Function} {} warning (\"on\", @var{id})\n\
1130@deftypefnx {Built-in Function} {} warning (\"off\", @var{id})\n\
1131@deftypefnx {Built-in Function} {} warning (\"error\", @var{id})\n\
1132@deftypefnx {Built-in Function} {} warning (\"query\", @var{id})\n\
1133Set or query the state of a particular warning using the identifier\n\
1134@var{id}. If the identifier is omitted, a value of @samp{\"all\"} is\n\
1135assumed. If you set the state of a warning to @samp{\"error\"}, the\n\
1136warning named by @var{id} is handled as if it were an error instead.\n\
1137@seealso{warning_ids}\n\
1138@end deftypefn")
1139{
1140 octave_value retval;
1141
1142 int nargin = args.length ();
1143 int argc = nargin + 1;
1144
1145 bool done = false;
1146
1147 if (argc > 1 && args.all_strings_p ())
1148 {
1149 string_vector argv = args.make_argv ("warning");
1150
1151 if (! error_state)
1152 {
1153 std::string arg1 = argv(1);
1154 std::string arg2 = "all";
1155
1156 if (argc == 3)
1157 arg2 = argv(2);
1158
1159 if (arg1 == "on" || arg1 == "off" || arg1 == "error")
1160 {
1161 Octave_map old_warning_options = warning_options;
1162
1163 if (arg2 == "all")
1164 {
1165 Octave_map tmp;
1166
1167 Cell id (1, 1);
1168 Cell st (1, 1);
1169
1170 id(0) = arg2;
1171 st(0) = arg1;
1172
1173 // Since internal Octave functions are not
1174 // compatible, turning all warnings into errors
1175 // should leave the state of
1176 // Octave:matlab-incompatible alone.
1177
1178 if (arg1 == "error"
1179 && warning_options.contains ("identifier"))
1180 {
1181 octave_idx_type n = 1;
1182
1183 Cell tid = warning_options.contents ("identifier");
1184 Cell tst = warning_options.contents ("state");
1185
1186 for (octave_idx_type i = 0; i < tid.numel (); i++)
1187 {
1188 octave_value vid = tid(i);
1189
1190 if (vid.is_string ())
1191 {
1192 std::string key = vid.string_value ();
1193
1194 if (key == "Octave:matlab-incompatible"
1195 || key == "Octave:single-quote-string")
1196 {
1197 id.resize (dim_vector (1, n+1));
1198 st.resize (dim_vector (1, n+1));
1199
1200 id(n) = tid(i);
1201 st(n) = tst(i);
1202
1203 n++;
1204 }
1205 }
1206 }
1207 }
1208
1209 tmp.assign ("identifier", id);
1210 tmp.assign ("state", st);
1211
1212 warning_options = tmp;
1213
1214 done = true;
1215 }
1216 else if (arg2 == "backtrace")
1217 {
1218 if (arg1 != "error")
1219 {
1220 Vbacktrace_on_warning = (arg1 == "on");
1221 done = true;
1222 }
1223 }
1224 else if (arg2 == "debug")
1225 {
1226 if (arg1 != "error")
1227 {
1228 Vdebug_on_warning = (arg1 == "on");
1229 done = true;
1230 }
1231 }
1232 else if (arg2 == "verbose")
1233 {
1234 if (arg1 != "error")
1235 {
1236 Vverbose_warning = (arg1 == "on");
1237 done = true;
1238 }
1239 }
1240 else if (arg2 == "quiet")
1241 {
1242 if (arg1 != "error")
1243 {
1244 Vquiet_warning = (arg1 == "on");
1245 done = true;
1246 }
1247 }
1248 else
1249 {
1250 if (arg2 == "last")
1251 arg2 = Vlast_warning_id;
1252
1253 if (arg2 == "all")
1254 initialize_warning_options (arg1);
1255 else
1256 {
1257 Cell ident = warning_options.contents ("identifier");
1258 Cell state = warning_options.contents ("state");
1259
1260 octave_idx_type nel = ident.numel ();
1261
1262 bool found = false;
1263
1264 for (octave_idx_type i = 0; i < nel; i++)
1265 {
1266 if (ident(i).string_value () == arg2)
1267 {
1268 // FIXME -- if state for "all" is
1269 // same as arg1, we can simply remove the
1270 // item from the list.
1271
1272 state(i) = arg1;
1273 warning_options.assign ("state", state);
1274 found = true;
1275 break;
1276 }
1277 }
1278
1279 if (! found)
1280 {
1281 // FIXME -- if state for "all" is
1282 // same as arg1, we don't need to do anything.
1283
1284 ident.resize (dim_vector (1, nel+1));
1285 state.resize (dim_vector (1, nel+1));
1286
1287 ident(nel) = arg2;
1288 state(nel) = arg1;
1289
1290 warning_options.clear ();
1291
1292 warning_options.assign ("identifier", ident);
1293 warning_options.assign ("state", state);
1294 }
1295 }
1296
1297 done = true;
1298 }
1299
1300 if (done && nargout > 0)
1301 retval = old_warning_options;
1302 }
1303 else if (arg1 == "query")
1304 {
1305 if (arg2 == "all")
1306 retval = warning_options;
1307 else if (arg2 == "backtrace" || arg2 == "debug"
1308 || arg2 == "verbose" || arg2 == "quiet")
1309 {
1310 Octave_map tmp;
1311 tmp.assign ("identifier", arg2);
1312 if (arg2 == "backtrace")
1313 tmp.assign ("state", Vbacktrace_on_warning ? "on" : "off");
1314 else if (arg2 == "debug")
1315 tmp.assign ("state", Vdebug_on_warning ? "on" : "off");
1316 else if (arg2 == "verbose")
1317 tmp.assign ("state", Vverbose_warning ? "on" : "off");
1318 else
1319 tmp.assign ("state", Vquiet_warning ? "on" : "off");
1320
1321 retval = tmp;
1322 }
1323 else
1324 {
1325 if (arg2 == "last")
1326 arg2 = Vlast_warning_id;
1327
1328 Cell ident = warning_options.contents ("identifier");
1329 Cell state = warning_options.contents ("state");
1330
1331 octave_idx_type nel = ident.numel ();
1332
1333 bool found = false;
1334
1335 std::string val;
1336
1337 for (octave_idx_type i = 0; i < nel; i++)
1338 {
1339 if (ident(i).string_value () == arg2)
1340 {
1341 val = state(i).string_value ();
1342 found = true;
1343 break;
1344 }
1345 }
1346
1347 if (! found)
1348 {
1349 for (octave_idx_type i = 0; i < nel; i++)
1350 {
1351 if (ident(i).string_value () == "all")
1352 {
1353 val = state(i).string_value ();
1354 found = true;
1355 break;
1356 }
1357 }
1358 }
1359
1360 if (found)
1361 {
1362 Octave_map tmp;
1363
1364 tmp.assign ("identifier", arg2);
1365 tmp.assign ("state", val);
1366
1367 retval = tmp;
1368 }
1369 else
1370 error ("warning: unable to find default warning state!");
1371 }
1372
1373 done = true;
1374 }
1375 }
1376 }
1377 else if (argc == 1)
1378 {
1379 retval = warning_options;
1380
1381 done = true;
1382 }
1383 else if (argc == 2)
1384 {
1385 octave_value arg = args(0);
1386
1387 Octave_map old_warning_options = warning_options;
1388
1389 if (arg.is_map ())
1390 {
1391 Octave_map m = arg.map_value ();
1392
1393 if (m.contains ("identifier") && m.contains ("state"))
1394 warning_options = m;
1395 else
1396 error ("warning: expecting structure with fields `identifier' and `state'");
1397
1398 done = true;
1399
1400 if (nargout > 0)
1401 retval = old_warning_options;
1402 }
1403 }
1404
1405 if (! (error_state || done))
1406 {
1407 octave_value_list nargs = args;
1408
1409 std::string id;
1410
1411 if (nargin > 1)
1412 {
1413 std::string arg1 = args(0).string_value ();
1414
1415 if (! error_state)
1416 {
1417 if (arg1.find ('%') == std::string::npos)
1418 {
1419 id = arg1;
1420
1421 nargs.resize (nargin-1);
1422
1423 for (int i = 1; i < nargin; i++)
1424 nargs(i-1) = args(i);
1425 }
1426 }
1427 else
1428 return retval;
1429 }
1430
1431 std::string prev_msg = Vlast_warning_message;
1432
1433 std::string curr_msg = handle_message (warning_with_id, id.c_str (),
1434 "unspecified warning", nargs);
1435
1436 if (nargout > 0)
1437 retval = prev_msg;
1438 }
1439
1440 return retval;
1441}
1442
1443void
1444disable_warning (const std::string& id)
1445{
1446 octave_value_list args;
1447
1448 args(1) = id;
1449 args(0) = "off";
1450
1451 Fwarning (args, 0);
1452}
1453
1454void
1455initialize_default_warning_state (void)
1456{
1457 initialize_warning_options ("on");
1458
1459 // Most people will want to have the following disabled.
1460
1461 disable_warning ("Octave:array-to-scalar");
1462 disable_warning ("Octave:array-to-vector");
1463 disable_warning ("Octave:empty-list-elements");
1464 disable_warning ("Octave:fortran-indexing");
1465 disable_warning ("Octave:imag-to-real");
1466 disable_warning ("Octave:matlab-incompatible");
1467 disable_warning ("Octave:missing-semicolon");
1468 disable_warning ("Octave:neg-dim-as-zero");
1469 disable_warning ("Octave:resize-on-range-error");
1470 disable_warning ("Octave:separator-insert");
1471 disable_warning ("Octave:single-quote-string");
1472 disable_warning ("Octave:str-to-num");
1473 disable_warning ("Octave:string-concat");
1474 disable_warning ("Octave:variable-switch-label");
1475 disable_warning ("Octave:int-convert-nan");
1476 disable_warning ("Octave:int-convert-non-int-val");
1477 disable_warning ("Octave:int-convert-overflow");
1478 disable_warning ("Octave:int-math-overflow");
1479 disable_warning ("Octave:complex-cmp-ops");
1480}
1481
1482DEFUN (lasterror, args, ,
1483 "-*- texinfo -*-\n\
1484@deftypefn {Built-in Function} {@var{err} =} lasterror (@var{err})\n\
1485@deftypefnx {Built-in Function} {} lasterror ('reset')\n\
1486Returns or sets the last error message. Called without any arguments\n\
1487returns a structure containing the last error message, as well as other\n\
1488information related to this error. The elements of this structure are:\n\
1489\n\
1490@table @asis\n\
1491@item 'message'\n\
1492The text of the last error message\n\
1493@item 'identifier'\n\
1494The message identifier of this error message\n\
1495@item 'stack'\n\
1496A structure containing information on where the message occurred. This might\n\
1497be an empty structure if this in the case where this information cannot\n\
1498be obtained. The fields of this structure are:\n\
1499\n\
1500@table @asis\n\
1501@item 'file'\n\
1502The name of the file where the error occurred\n\
1503@item 'name'\n\
1504The name of function in which the error occurred\n\
1505@item 'line'\n\
1506The line number at which the error occurred\n\
1507@item 'column'\n\
1508An optional field with the column number at which the error occurred\n\
1509@end table\n\
1510@end table\n\
1511\n\
1512The @var{err} structure may also be passed to @code{lasterror} to set the\n\
1513information about the last error. The only constraint on @var{err} in that\n\
1514case is that it is a scalar structure. Any fields of @var{err} that match\n\
1515the above are set to the value passed in @var{err}, while other fields are\n\
1516set to their default values.\n\
1517\n\
1518If @code{lasterror} is called with the argument 'reset', all values take\n\
1519their default values.\n\
1520@end deftypefn")
1521{
1522 octave_value retval;
1523 int nargin = args.length();
1524
1525 unwind_protect frame;
1526
1527 frame.protect_var (error_state);
1528 error_state = 0;
1529
1530 if (nargin < 2)
1531 {
1532 Octave_map err;
1533
1534 err.assign ("message", Vlast_error_message);
1535 err.assign ("identifier", Vlast_error_id);
1536
1537 err.assign ("stack", octave_value (Vlast_error_stack));
1538
1539 if (nargin == 1)
1540 {
1541 if (args(0).is_string())
1542 {
1543 if (args(0).string_value () == "reset")
1544 {
1545 Vlast_error_message = std::string();
1546 Vlast_error_id = std::string();
1547
1548 Vlast_error_stack = initialize_last_error_stack ();
1549 }
1550 else
1551 error("lasterror: unrecognized string argument");
1552 }
1553 else if (args(0).is_map ())
1554 {
1555 Octave_map new_err = args(0).map_value ();
1556 std::string new_error_message;
1557 std::string new_error_id;
1558 std::string new_error_file;
1559 std::string new_error_name;
1560 int new_error_line = -1;
1561 int new_error_column = -1;
1562
1563 if (! error_state && new_err.contains ("message"))
1564 {
1565 const std::string tmp =
1566 new_err.contents("message")(0).string_value ();
1567 new_error_message = tmp;
1568 }
1569
1570 if (! error_state && new_err.contains ("identifier"))
1571 {
1572 const std::string tmp =
1573 new_err.contents("identifier")(0).string_value ();
1574 new_error_id = tmp;
1575 }
1576
1577 if (! error_state && new_err.contains ("stack"))
1578 {
1579 Octave_map new_err_stack =
1580 new_err.contents("identifier")(0).map_value ();
1581
1582 if (! error_state && new_err_stack.contains ("file"))
1583 {
1584 const std::string tmp =
1585 new_err_stack.contents("file")(0).string_value ();
1586 new_error_file = tmp;
1587 }
1588
1589 if (! error_state && new_err_stack.contains ("name"))
1590 {
1591 const std::string tmp =
1592 new_err_stack.contents("name")(0).string_value ();
1593 new_error_name = tmp;
1594 }
1595
1596 if (! error_state && new_err_stack.contains ("line"))
1597 {
1598 const int tmp =
1599 new_err_stack.contents("line")(0).nint_value ();
1600 new_error_line = tmp;
1601 }
1602
1603 if (! error_state && new_err_stack.contains ("column"))
1604 {
1605 const int tmp =
1606 new_err_stack.contents("column")(0).nint_value ();
1607 new_error_column = tmp;
1608 }
1609 }
1610
1611 if (! error_state)
1612 {
1613 Vlast_error_message = new_error_message;
1614 Vlast_error_id = new_error_id;
1615
1616 octave_idx_type curr_frame = -1;
1617
1618 Vlast_error_stack
1619 = octave_call_stack::backtrace (0, curr_frame);
1620 }
1621 }
1622 else
1623 error ("lasterror: argument must be a structure or a string");
1624 }
1625
1626 if (! error_state)
1627 retval = err;
1628 }
1629 else
1630 print_usage ();
1631
1632 return retval;
1633}
1634
1635DEFUN (lasterr, args, nargout,
1636 "-*- texinfo -*-\n\
1637@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lasterr (@var{msg}, @var{msgid})\n\
1638Without any arguments, return the last error message. With one\n\
1639argument, set the last error message to @var{msg}. With two arguments,\n\
1640also set the last message identifier.\n\
1641@end deftypefn")
1642{
1643 octave_value_list retval;
1644
1645 unwind_protect frame;
1646
1647 frame.protect_var (error_state);
1648 error_state = 0;
1649
1650 int argc = args.length () + 1;
1651
1652 if (argc < 4)
1653 {
1654 string_vector argv = args.make_argv ("lasterr");
1655
1656 if (! error_state)
1657 {
1658 std::string prev_error_id = Vlast_error_id;
1659 std::string prev_error_message = Vlast_error_message;
1660
1661 if (argc > 2)
1662 Vlast_error_id = argv(2);
1663
1664 if (argc > 1)
1665 Vlast_error_message = argv(1);
1666
1667 if (argc == 1 || nargout > 0)
1668 {
1669 retval(1) = prev_error_id;
1670 retval(0) = prev_error_message;
1671 }
1672 }
1673 else
1674 error ("lasterr: expecting arguments to be character strings");
1675 }
1676 else
1677 print_usage ();
1678
1679 return retval;
1680}
1681
1682// For backward compatibility.
1683DEFALIAS (error_text, lasterr);
1684DEFALIAS (__error_text__, lasterr);
1685
1686DEFUN (lastwarn, args, nargout,
1687 "-*- texinfo -*-\n\
1688@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lastwarn (@var{msg}, @var{msgid})\n\
1689Without any arguments, return the last warning message. With one\n\
1690argument, set the last warning message to @var{msg}. With two arguments,\n\
1691also set the last message identifier.\n\
1692@end deftypefn")
1693{
1694 octave_value_list retval;
1695
1696 int argc = args.length () + 1;
1697
1698 if (argc < 4)
1699 {
1700 string_vector argv = args.make_argv ("lastwarn");
1701
1702 if (! error_state)
1703 {
1704 std::string prev_warning_id = Vlast_warning_id;
1705 std::string prev_warning_message = Vlast_warning_message;
1706
1707 if (argc > 2)
1708 Vlast_warning_id = argv(2);
1709
1710 if (argc > 1)
1711 Vlast_warning_message = argv(1);
1712
1713 if (argc == 1 || nargout > 0)
1714 {
1715 warning_state = 0;
1716 retval(1) = prev_warning_id;
1717 retval(0) = prev_warning_message;
1718 }
1719 }
1720 else
1721 error ("lastwarn: expecting arguments to be character strings");
1722 }
1723 else
1724 print_usage ();
1725
1726 return retval;
1727}
1728
1729DEFUN (usage, args, ,
1730 "-*- texinfo -*-\n\
1731@deftypefn {Built-in Function} {} usage (@var{msg})\n\
1732Print the message @var{msg}, prefixed by the string @samp{usage: }, and\n\
1733set Octave's internal error state such that control will return to the\n\
1734top level without evaluating any more commands. This is useful for\n\
1735aborting from functions.\n\
1736\n\
1737After @code{usage} is evaluated, Octave will print a traceback of all\n\
1738the function calls leading to the usage message.\n\
1739\n\
1740You should use this function for reporting problems errors that result\n\
1741from an improper call to a function, such as calling a function with an\n\
1742incorrect number of arguments, or with arguments of the wrong type. For\n\
1743example, most functions distributed with Octave begin with code like\n\
1744this\n\
1745\n\
1746@example\n\
1747@group\n\
1748if (nargin != 2)\n\
1749 usage (\"foo (a, b)\");\n\
1750endif\n\
1751@end group\n\
1752@end example\n\
1753\n\
1754@noindent\n\
1755to check for the proper number of arguments.\n\
1756@end deftypefn")
1757{
1758 octave_value_list retval;
1759 handle_message (usage_with_id, "", "unknown", args);
1760 return retval;
1761}
1762
1763DEFUN (beep_on_error, args, nargout,
1764 "-*- texinfo -*-\n\
1765@deftypefn {Built-in Function} {@var{val} =} beep_on_error ()\n\
1766@deftypefnx {Built-in Function} {@var{old_val} =} beep_on_error (@var{new_val})\n\
1767Query or set the internal variable that controls whether Octave will try\n\
1768to ring the terminal bell before printing an error message.\n\
1769@end deftypefn")
1770{
1771 return SET_INTERNAL_VARIABLE (beep_on_error);
1772}
1773
1774DEFUN (debug_on_error, args, nargout,
1775 "-*- texinfo -*-\n\
1776@deftypefn {Built-in Function} {@var{val} =} debug_on_error ()\n\
1777@deftypefnx {Built-in Function} {@var{old_val} =} debug_on_error (@var{new_val})\n\
1778Query or set the internal variable that controls whether Octave will try\n\
1779to enter the debugger when an error is encountered. This will also\n\
1780inhibit printing of the normal traceback message (you will only see\n\
1781the top-level error message).\n\
1782@end deftypefn")
1783{
1784 return SET_INTERNAL_VARIABLE (debug_on_error);
1785}
1786
1787DEFUN (debug_on_warning, args, nargout,
1788 "-*- texinfo -*-\n\
1789@deftypefn {Built-in Function} {@var{val} =} debug_on_warning ()\n\
1790@deftypefnx {Built-in Function} {@var{old_val} =} debug_on_warning (@var{new_val})\n\
1791Query or set the internal variable that controls whether Octave will try\n\
1792to enter the debugger when a warning is encountered.\n\
1793@end deftypefn")
1794{
1795 return SET_INTERNAL_VARIABLE (debug_on_warning);
1796}
1797
1798std::string
1799last_error_message (void)
1800{
1801 return Vlast_error_message;
1802}
1803
1804std::string
1805last_error_id (void)
1806{
1807 return Vlast_error_id;
1808}
1809
1810std::string
1811last_warning_message (void)
1812{
1813 return Vlast_warning_message;
1814}
1815
1816std::string
1817last_warning_id (void)
1818{
1819 return Vlast_warning_id;
1820}