comparison libinterp/corefcn/error.cc @ 31608:23664317f0d3

maint: merge stable to default
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 20:05:44 -0800
parents dfa5d9c3ae72 aac27ad79be6
children 5c6395400843
comparison
equal deleted inserted replaced
31606:dfa5d9c3ae72 31608:23664317f0d3
233 return have_fmt; 233 return have_fmt;
234 } 234 }
235 235
236 OCTAVE_BEGIN_NAMESPACE(octave) 236 OCTAVE_BEGIN_NAMESPACE(octave)
237 237
238 static octave_scalar_map 238 static octave_scalar_map
239 init_warning_options (const std::string& state) 239 init_warning_options (const std::string& state)
240 { 240 {
241 octave_scalar_map initw; 241 octave_scalar_map initw;
242 242
243 initw.setfield ("identifier", "all"); 243 initw.setfield ("identifier", "all");
244 initw.setfield ("state", state); 244 initw.setfield ("state", state);
245 245
246 return initw; 246 return initw;
247 } 247 }
248 248
249 static octave_map 249 static octave_map
250 init_error_stack (interpreter& interp) 250 init_error_stack (interpreter& interp)
251 { 251 {
252 tree_evaluator& tw = interp.get_evaluator (); 252 tree_evaluator& tw = interp.get_evaluator ();
253 253
254 return tw.empty_backtrace (); 254 return tw.empty_backtrace ();
255 } 255 }
256 256
257 error_system::error_system (interpreter& interp) 257 error_system::error_system (interpreter& interp)
258 : m_interpreter (interp), 258 : m_interpreter (interp),
259 m_debug_on_error (false), 259 m_debug_on_error (false),
260 m_debug_on_caught (false), 260 m_debug_on_caught (false),
261 m_debug_on_warning (false), 261 m_debug_on_warning (false),
262 m_discard_warning_messages (false), 262 m_discard_warning_messages (false),
263 m_beep_on_error (false), 263 m_beep_on_error (false),
264 m_backtrace_on_warning (true), 264 m_backtrace_on_warning (true),
265 m_verbose_warning (false), 265 m_verbose_warning (false),
266 m_quiet_warning (false), 266 m_quiet_warning (false),
267 m_warning_options (init_warning_options ("on")), 267 m_warning_options (init_warning_options ("on")),
268 m_last_error_message (), 268 m_last_error_message (),
269 m_last_warning_message (), 269 m_last_warning_message (),
270 m_last_warning_id (), 270 m_last_warning_id (),
271 m_last_error_id (), 271 m_last_error_id (),
272 m_last_error_stack (init_error_stack (interp)) 272 m_last_error_stack (init_error_stack (interp))
273 { 273 {
274 initialize_default_warning_state (); 274 initialize_default_warning_state ();
275 } 275 }
276 276
277 octave_value 277 octave_value
278 error_system::debug_on_error (const octave_value_list& args, int nargout) 278 error_system::debug_on_error (const octave_value_list& args, int nargout)
279 { 279 {
280 return set_internal_variable (m_debug_on_error, args, nargout, 280 return set_internal_variable (m_debug_on_error, args, nargout,
281 "debug_on_error"); 281 "debug_on_error");
282 } 282 }
283 283
284 octave_value 284 octave_value
285 error_system::debug_on_caught (const octave_value_list& args, int nargout) 285 error_system::debug_on_caught (const octave_value_list& args, int nargout)
286 { 286 {
287 return set_internal_variable (m_debug_on_caught, args, nargout, 287 return set_internal_variable (m_debug_on_caught, args, nargout,
288 "debug_on_caught"); 288 "debug_on_caught");
289 } 289 }
290 290
291 octave_value 291 octave_value
292 error_system::debug_on_warning (const octave_value_list& args, int nargout) 292 error_system::debug_on_warning (const octave_value_list& args, int nargout)
293 { 293 {
294 return set_internal_variable (m_debug_on_warning, args, nargout, 294 return set_internal_variable (m_debug_on_warning, args, nargout,
295 "debug_on_warning"); 295 "debug_on_warning");
296 } 296 }
297 297
298 octave_value 298 octave_value
299 error_system::discard_warning_messages (const octave_value_list& args, 299 error_system::discard_warning_messages (const octave_value_list& args,
300 int nargout) 300 int nargout)
301 { 301 {
302 return set_internal_variable (m_discard_warning_messages, args, nargout, 302 return set_internal_variable (m_discard_warning_messages, args, nargout,
303 "discard_warning_messages"); 303 "discard_warning_messages");
304 } 304 }
305 305
306 octave_value 306 octave_value
307 error_system::beep_on_error (const octave_value_list& args, int nargout) 307 error_system::beep_on_error (const octave_value_list& args, int nargout)
308 { 308 {
309 return set_internal_variable (m_beep_on_error, args, nargout, 309 return set_internal_variable (m_beep_on_error, args, nargout,
310 "beep_on_error"); 310 "beep_on_error");
311 } 311 }
312 312
313 octave_value 313 octave_value
314 error_system::backtrace_on_warning (const octave_value_list& args, 314 error_system::backtrace_on_warning (const octave_value_list& args,
315 int nargout) 315 int nargout)
316 { 316 {
317 return set_internal_variable (m_backtrace_on_warning, args, nargout, 317 return set_internal_variable (m_backtrace_on_warning, args, nargout,
318 "backtrace_on_warning"); 318 "backtrace_on_warning");
319 } 319 }
320 320
321 octave_value 321 octave_value
322 error_system::verbose_warning (const octave_value_list& args, int nargout) 322 error_system::verbose_warning (const octave_value_list& args, int nargout)
323 { 323 {
324 return set_internal_variable (m_verbose_warning, args, nargout, 324 return set_internal_variable (m_verbose_warning, args, nargout,
325 "verbose_warning"); 325 "verbose_warning");
326 } 326 }
327 327
328 octave_value 328 octave_value
329 error_system::quiet_warning (const octave_value_list& args, int nargout) 329 error_system::quiet_warning (const octave_value_list& args, int nargout)
330 { 330 {
331 return set_internal_variable (m_quiet_warning, args, nargout, 331 return set_internal_variable (m_quiet_warning, args, nargout,
332 "quiet_warning"); 332 "quiet_warning");
333 } 333 }
334 334
335 octave_value 335 octave_value
336 error_system::last_error_message (const octave_value_list& args, int nargout) 336 error_system::last_error_message (const octave_value_list& args, int nargout)
337 { 337 {
338 return set_internal_variable (m_last_error_message, args, nargout, 338 return set_internal_variable (m_last_error_message, args, nargout,
339 "last_error_message"); 339 "last_error_message");
340 } 340 }
341 341
342 octave_value 342 octave_value
343 error_system::last_warning_message (const octave_value_list& args, 343 error_system::last_warning_message (const octave_value_list& args,
344 int nargout) 344 int nargout)
345 { 345 {
346 return set_internal_variable (m_last_warning_message, args, nargout, 346 return set_internal_variable (m_last_warning_message, args, nargout,
347 "last_warning_message"); 347 "last_warning_message");
348 } 348 }
349 349
350 octave_value 350 octave_value
351 error_system::last_warning_id (const octave_value_list& args, int nargout) 351 error_system::last_warning_id (const octave_value_list& args, int nargout)
352 { 352 {
353 return set_internal_variable (m_last_warning_id, args, nargout, 353 return set_internal_variable (m_last_warning_id, args, nargout,
354 "last_warning_id"); 354 "last_warning_id");
355 } 355 }
356 356
357 octave_value 357 octave_value
358 error_system::last_error_id (const octave_value_list& args, int nargout) 358 error_system::last_error_id (const octave_value_list& args, int nargout)
359 { 359 {
360 return set_internal_variable (m_last_error_id, args, nargout, 360 return set_internal_variable (m_last_error_id, args, nargout,
361 "last_error_id"); 361 "last_error_id");
362 } 362 }
363 363
364 // Use static fields for the best efficiency. 364 // Use static fields for the best efficiency.
365 // NOTE: C++0x will allow these two to be merged into one. 365 // NOTE: C++0x will allow these two to be merged into one.
366 static const char *bt_fieldnames[] = 366 static const char *bt_fieldnames[] =
367 { "file", "name", "line", "column", nullptr }; 367 { "file", "name", "line", "column", nullptr };
368 368
369 static const octave_fields bt_fields (bt_fieldnames); 369 static const octave_fields bt_fields (bt_fieldnames);
370 370
371 octave_map 371 octave_map
372 error_system::make_stack_map (const std::list<frame_info>& frames) 372 error_system::make_stack_map (const std::list<frame_info>& frames)
373 { 373 {
374 std::size_t nframes = frames.size (); 374 std::size_t nframes = frames.size ();
375 375
376 octave_map retval (dim_vector (nframes, 1), bt_fields); 376 octave_map retval (dim_vector (nframes, 1), bt_fields);
377 377
378 Cell& file = retval.contents (0); 378 Cell& file = retval.contents (0);
379 Cell& name = retval.contents (1); 379 Cell& name = retval.contents (1);
380 Cell& line = retval.contents (2); 380 Cell& line = retval.contents (2);
381 Cell& column = retval.contents (3); 381 Cell& column = retval.contents (3);
382 382
383 octave_idx_type k = 0; 383 octave_idx_type k = 0;
384 384
385 for (const auto& frm : frames) 385 for (const auto& frm : frames)
386 { 386 {
387 file(k) = frm.file_name (); 387 file(k) = frm.file_name ();
388 name(k) = frm.fcn_name (); 388 name(k) = frm.fcn_name ();
389 line(k) = frm.line (); 389 line(k) = frm.line ();
390 column(k) = frm.column (); 390 column(k) = frm.column ();
391 391
392 k++; 392 k++;
393 } 393 }
394 394
395 return retval; 395 return retval;
396 } 396 }
397 397
398 std::list<frame_info> 398 std::list<frame_info>
399 error_system::make_stack_frame_list (const octave_map& stack) 399 error_system::make_stack_frame_list (const octave_map& stack)
400 { 400 {
401 std::list<frame_info> frames; 401 std::list<frame_info> frames;
402 402
403 Cell file = stack.contents ("file"); 403 Cell file = stack.contents ("file");
404 Cell name = stack.contents ("name"); 404 Cell name = stack.contents ("name");
405 Cell line = stack.contents ("line"); 405 Cell line = stack.contents ("line");
406 Cell column = stack.contents ("column"); 406 Cell column = stack.contents ("column");
407 407
408 octave_idx_type nel = name.numel (); 408 octave_idx_type nel = name.numel ();
409 409
410 for (octave_idx_type i = 0; i < nel; i++) 410 for (octave_idx_type i = 0; i < nel; i++)
411 frames.push_back (frame_info (file(i).string_value (), 411 frames.push_back (frame_info (file(i).string_value (),
412 name(i).string_value (), 412 name(i).string_value (),
413 line(i).int_value (), 413 line(i).int_value (),
414 column(i).int_value ())); 414 column(i).int_value ()));
415 415
416 return frames; 416 return frames;
417 } 417 }
418 418
419 // For given warning ID, return 0 if warnings are disabled, 1 if 419 // For given warning ID, return 0 if warnings are disabled, 1 if
420 // enabled, and 2 if the given ID should be an error instead of a 420 // enabled, and 2 if the given ID should be an error instead of a
421 // warning. 421 // warning.
422 422
423 int error_system::warning_enabled (const std::string& id) 423 int error_system::warning_enabled (const std::string& id)
424 { 424 {
425 int retval = 0; 425 int retval = 0;
426 426
427 int all_state = -1; 427 int all_state = -1;
428 int id_state = -1; 428 int id_state = -1;
429 429
430 octave_map opts = warning_options (); 430 octave_map opts = warning_options ();
431 431
432 octave_idx_type nel = opts.numel (); 432 octave_idx_type nel = opts.numel ();
433 433
434 if (nel > 0) 434 if (nel > 0)
435 { 435 {
436 Cell identifier = opts.contents ("identifier"); 436 Cell identifier = opts.contents ("identifier");
437 Cell state = opts.contents ("state"); 437 Cell state = opts.contents ("state");
438 438
439 bool all_found = false; 439 bool all_found = false;
440 bool id_found = false; 440 bool id_found = false;
441 441
442 for (octave_idx_type i = 0; i < nel; i++) 442 for (octave_idx_type i = 0; i < nel; i++)
443 { 443 {
444 octave_value ov = identifier(i); 444 octave_value ov = identifier(i);
445 std::string ovs = ov.string_value (); 445 std::string ovs = ov.string_value ();
446 446
447 if (! all_found && ovs == "all") 447 if (! all_found && ovs == "all")
448 { 448 {
449 all_state = check_state (state(i).string_value ()); 449 all_state = check_state (state(i).string_value ());
450 450
451 if (all_state >= 0) 451 if (all_state >= 0)
452 all_found = true; 452 all_found = true;
453 } 453 }
454 454
455 if (! id_found && ovs == id) 455 if (! id_found && ovs == id)
456 { 456 {
457 id_state = check_state (state(i).string_value ()); 457 id_state = check_state (state(i).string_value ());
458 458
459 if (id_state >= 0) 459 if (id_state >= 0)
460 id_found = true; 460 id_found = true;
461 } 461 }
462 462
463 if (all_found && id_found) 463 if (all_found && id_found)
464 break;
465 }
466 }
467
468 // If "all" is not present, assume warnings are enabled.
469 if (all_state == -1)
470 all_state = 1;
471
472 if (all_state == 0)
473 {
474 if (id_state >= 0)
475 retval = id_state;
476 }
477 else if (all_state == 1)
478 {
479 if (id_state == 0 || id_state == 2)
480 retval = id_state;
481 else
482 retval = all_state;
483 }
484 else if (all_state == 2)
485 {
486 if (id_state == 0)
487 retval= id_state;
488 else
489 retval = all_state;
490 }
491
492 return retval;
493 }
494
495 void error_system::vusage (const char *id, const char *fmt, va_list args)
496 {
497 std::string str_id = id ? id : "";
498 std::string message = format_message (fmt, args);
499
500 throw_error ("usage", str_id, message);
501 }
502
503 void error_system::vwarning (const char *name, const char *id,
504 const char *fmt, va_list args)
505 {
506 flush_stdout ();
507
508 std::string base_msg = format_message (fmt, args);
509 std::string msg_string;
510
511 if (name)
512 msg_string = std::string (name) + ": ";
513
514 msg_string += base_msg;
515
516 bool fmt_suppresses_backtrace = false;
517 std::size_t fmt_len = (fmt ? strlen (fmt) : 0);
518 fmt_suppresses_backtrace = (fmt_len > 0 && fmt[fmt_len-1] == '\n');
519
520 if (! fmt_suppresses_backtrace)
521 msg_string += '\n';
522
523 last_warning_id (id);
524 last_warning_message (base_msg);
525
526 if (discard_warning_messages ())
527 return;
528
529 tree_evaluator& tw = m_interpreter.get_evaluator ();
530
531 bool in_user_code = tw.in_user_code ();
532
533 if (! quiet_warning ())
534 {
535 octave_diary << msg_string;
536 std::cerr << msg_string;
537
538 if (! fmt_suppresses_backtrace && in_user_code
539 && backtrace_on_warning ()
540 && ! discard_warning_messages ())
541 {
542 std::string bt_msg = tw.backtrace_message ();
543
544 if (! bt_msg.empty ())
545 bt_msg = "warning: called from\n" + bt_msg;
546
547 octave_diary << bt_msg << std::endl;
548 std::cerr << bt_msg << std::endl;
549 }
550 }
551
552 bp_table& bptab = tw.get_bp_table ();
553
554 if ((m_interpreter.interactive ()
555 || application::forced_interactive ())
556 && debug_on_warning () && in_user_code && bptab.debug_on_warn (id))
557 {
558 unwind_protect_var<bool> restore_var (m_debug_on_warning, false);
559
560 tw.enter_debugger ();
561 }
562 }
563
564 void error_system::error_1 (execution_exception& ee, const char *id,
565 const char *fmt, va_list args)
566 {
567 ee.set_identifier (id);
568 ee.set_message (format_message (fmt, args));
569
570 throw_error (ee);
571 }
572
573 void error_system::error_1 (const char *id, const char *fmt,
574 va_list args)
575 {
576 std::string message = format_message (fmt, args);
577
578 std::list<frame_info> stack_info;
579
580 throw_error ("error", id, message);
581 }
582
583 void error_system::vwarning (const char *id, const char *fmt, va_list args)
584 {
585 int warn_opt = warning_enabled (id);
586
587 if (warn_opt == 2)
588 {
589 // Handle this warning as an error.
590
591 error_1 (id, fmt, args);
592 }
593 else if (warn_opt == 1)
594 vwarning ("warning", id, fmt, args);
595 }
596
597 void error_system::rethrow_error (const std::string& id,
598 const std::string& msg,
599 const octave_map& stack)
600 {
601 std::list<frame_info> stack_info;
602
603 execution_exception ee ("error", id, msg, stack_info);
604
605 if (! stack.isempty ())
606 {
607 if (! (stack.contains ("file") && stack.contains ("name")
608 && stack.contains ("line")))
609 error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'");
610
611 if (! stack.contains ("column"))
612 {
613 octave_map new_stack = stack;
614
615 new_stack.setfield ("column", Cell (octave_value (-1)));
616
617 ee.set_stack_info (make_stack_frame_list (new_stack));
618 }
619 else
620 ee.set_stack_info (make_stack_frame_list (stack));
621 }
622
623 throw_error (ee);
624 }
625
626 void error_system::vpanic (const char *fmt, va_list args)
627 {
628 // Is there any point in trying to write the panic message to the
629 // diary?
630
631 std::cerr << "panic: " << format_message (fmt, args) << std::endl;
632
633 abort ();
634 }
635
636 void error_system::panic (const char *fmt, ...)
637 {
638 va_list args;
639 va_start (args, fmt);
640 vpanic (fmt, args);
641 va_end (args);
642 }
643
644 octave_scalar_map error_system::warning_query (const std::string& id_arg)
645 {
646 octave_scalar_map retval;
647
648 std::string id = id_arg;
649
650 if (id == "last")
651 id = last_warning_id ();
652
653 octave_map opts = warning_options ();
654
655 Cell ident = opts.contents ("identifier");
656 Cell state = opts.contents ("state");
657
658 octave_idx_type nel = ident.numel ();
659
660 panic_if (nel == 0);
661
662 bool found = false;
663
664 std::string val;
665
666 for (octave_idx_type i = 0; i < nel; i++)
667 {
668 if (ident(i).string_value () == id)
669 {
670 val = state(i).string_value ();
671 found = true;
672 break;
673 }
674 }
675
676 if (! found)
677 {
678 for (octave_idx_type i = 0; i < nel; i++)
679 {
680 if (ident(i).string_value () == "all")
681 {
682 val = state(i).string_value ();
683 found = true;
464 break; 684 break;
465 } 685 }
466 } 686 }
467 687 }
468 // If "all" is not present, assume warnings are enabled. 688
469 if (all_state == -1) 689 // The warning state "all" is always supposed to remain in the list,
470 all_state = 1; 690 // so we should always find a state, either explicitly or by using the
471 691 // state for "all".
472 if (all_state == 0) 692 panic_unless (found);
473 { 693
474 if (id_state >= 0) 694 retval.assign ("identifier", id);
475 retval = id_state; 695 retval.assign ("state", val);
476 } 696
477 else if (all_state == 1) 697 return retval;
478 { 698 }
479 if (id_state == 0 || id_state == 2) 699
480 retval = id_state; 700 std::string error_system::default_warning_state (void)
481 else 701 {
482 retval = all_state; 702 std::string retval = "on";
483 } 703
484 else if (all_state == 2) 704 octave_map opts = warning_options ();
485 { 705
486 if (id_state == 0) 706 Cell ident = opts.contents ("identifier");
487 retval= id_state; 707 Cell state = opts.contents ("state");
488 else 708
489 retval = all_state; 709 octave_idx_type nel = ident.numel ();
490 } 710
491 711 for (octave_idx_type i = 0; i < nel; i++)
492 return retval; 712 {
493 } 713 if (ident(i).string_value () == "all")
494 714 {
495 void error_system::vusage (const char *id, const char *fmt, va_list args) 715 retval = state(i).string_value ();
496 { 716 break;
497 std::string str_id = id ? id : ""; 717 }
498 std::string message = format_message (fmt, args); 718 }
499 719
500 throw_error ("usage", str_id, message); 720 return retval;
501 } 721 }
502 722
503 void error_system::vwarning (const char *name, const char *id, 723 void error_system::display_warning_options (std::ostream& os)
504 const char *fmt, va_list args) 724 {
505 { 725 octave_map opts = warning_options ();
506 flush_stdout (); 726
507 727 Cell ident = opts.contents ("identifier");
508 std::string base_msg = format_message (fmt, args); 728 Cell state = opts.contents ("state");
509 std::string msg_string; 729
510 730 octave_idx_type nel = ident.numel ();
511 if (name) 731
512 msg_string = std::string (name) + ": "; 732 std::string all_state = default_warning_state ();
513 733
514 msg_string += base_msg; 734 if (all_state == "on")
515 735 os << "By default, warnings are enabled.";
516 bool fmt_suppresses_backtrace = false; 736 else if (all_state == "off")
517 std::size_t fmt_len = (fmt ? strlen (fmt) : 0); 737 os << "By default, warnings are disabled.";
518 fmt_suppresses_backtrace = (fmt_len > 0 && fmt[fmt_len-1] == '\n'); 738 else if (all_state == "error")
519 739 os << "By default, warnings are treated as errors.";
520 if (! fmt_suppresses_backtrace) 740 else
521 msg_string += '\n'; 741 panic_impossible ();
522 742
523 last_warning_id (id); 743 if (nel > 1)
524 last_warning_message (base_msg); 744 {
525 745 os << "\n";
526 if (discard_warning_messages ()) 746 os << "Non-default warning states are:\n\n";
527 return; 747 os << " State Warning ID\n";
528 748 }
529 tree_evaluator& tw = m_interpreter.get_evaluator (); 749
530 750 // The state for "all" is always supposed to be first in the list.
531 bool in_user_code = tw.in_user_code (); 751
532 752 for (octave_idx_type i = 1; i < nel; i++)
533 if (! quiet_warning ()) 753 {
534 { 754 std::string tid = ident(i).string_value ();
535 octave_diary << msg_string; 755 std::string tst = state(i).string_value ();
536 std::cerr << msg_string; 756
537 757 os << std::setw (7) << tst << " " << tid << "\n";
538 if (! fmt_suppresses_backtrace && in_user_code 758 }
539 && backtrace_on_warning () 759
540 && ! discard_warning_messages ()) 760 os << std::endl;
541 { 761 }
542 std::string bt_msg = tw.backtrace_message (); 762
543 763 void error_system::set_warning_option (const std::string& state,
544 if (! bt_msg.empty ()) 764 const std::string& ident)
545 bt_msg = "warning: called from\n" + bt_msg; 765 {
546 766 std::string all_state = default_warning_state ();
547 octave_diary << bt_msg << std::endl; 767
548 std::cerr << bt_msg << std::endl; 768 if (state != "on" && state != "off" && state != "error")
549 } 769 error ("invalid warning state: %s", state.c_str ());
550 } 770
551 771 octave_map opts = warning_options ();
552 bp_table& bptab = tw.get_bp_table (); 772
553 773 Cell tid = opts.contents ("identifier");
554 if ((m_interpreter.interactive () 774 Cell tst = opts.contents ("state");
555 || application::forced_interactive ()) 775
556 && debug_on_warning () && in_user_code && bptab.debug_on_warn (id)) 776 octave_idx_type nel = tid.numel ();
557 { 777
558 unwind_protect_var<bool> restore_var (m_debug_on_warning, false); 778 for (octave_idx_type i = 0; i < nel; i++)
559 779 {
560 tw.enter_debugger (); 780 if (tid(i).string_value () == ident)
561 } 781 {
562 } 782 // We found it in the current list of options. If the state
563 783 // for "all" is same as arg1, we can simply remove the item
564 void error_system::error_1 (execution_exception& ee, const char *id, 784 // from the list.
565 const char *fmt, va_list args) 785
566 { 786 if (state == all_state && ident != "all")
567 ee.set_identifier (id); 787 {
568 ee.set_message (format_message (fmt, args)); 788 for (i = i + 1; i < nel; i++)
569 789 {
570 throw_error (ee); 790 tid(i-1) = tid(i);
571 } 791 tst(i-1) = tst(i);
572 792 }
573 void error_system::error_1 (const char *id, const char *fmt, 793
574 va_list args) 794 tid.resize (dim_vector (1, nel-1));
575 { 795 tst.resize (dim_vector (1, nel-1));
576 std::string message = format_message (fmt, args); 796 }
577 797 else
578 std::list<frame_info> stack_info; 798 tst(i) = state;
579 799
580 throw_error ("error", id, message); 800 opts.clear ();
581 } 801
582 802 opts.assign ("identifier", tid);
583 void error_system::vwarning (const char *id, const char *fmt, va_list args) 803 opts.assign ("state", tst);
584 { 804
585 int warn_opt = warning_enabled (id); 805 warning_options (opts);
586 806
587 if (warn_opt == 2) 807 return;
588 { 808 }
589 // Handle this warning as an error. 809 }
590 810
591 error_1 (id, fmt, args); 811 // The option wasn't already in the list. Append it.
592 } 812
593 else if (warn_opt == 1) 813 tid.resize (dim_vector (1, nel+1));
594 vwarning ("warning", id, fmt, args); 814 tst.resize (dim_vector (1, nel+1));
595 } 815
596 816 tid(nel) = ident;
597 void error_system::rethrow_error (const std::string& id, 817 tst(nel) = state;
598 const std::string& msg, 818
599 const octave_map& stack) 819 opts.clear ();
600 { 820
601 std::list<frame_info> stack_info; 821 opts.assign ("identifier", tid);
602 822 opts.assign ("state", tst);
603 execution_exception ee ("error", id, msg, stack_info); 823
604 824 warning_options (opts);
605 if (! stack.isempty ()) 825 }
606 { 826
607 if (! (stack.contains ("file") && stack.contains ("name") 827 void error_system::disable_warning (const std::string& id)
608 && stack.contains ("line"))) 828 {
609 error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'"); 829 set_warning_option ("off", id);
610 830 }
611 if (! stack.contains ("column")) 831
612 { 832 void error_system::initialize_default_warning_state (void)
613 octave_map new_stack = stack; 833 {
614 834 warning_options (init_warning_options ("on"));
615 new_stack.setfield ("column", Cell (octave_value (-1))); 835
616 836 // Most people will want to have the following disabled.
617 ee.set_stack_info (make_stack_frame_list (new_stack)); 837
618 } 838 disable_warning ("Octave:array-as-logical");
619 else 839 disable_warning ("Octave:array-to-scalar");
620 ee.set_stack_info (make_stack_frame_list (stack)); 840 disable_warning ("Octave:array-to-vector");
621 } 841 disable_warning ("Octave:imag-to-real");
622 842 disable_warning ("Octave:language-extension");
623 throw_error (ee); 843 disable_warning ("Octave:missing-semicolon");
624 } 844 disable_warning ("Octave:neg-dim-as-zero");
625 845 disable_warning ("Octave:separator-insert");
626 void error_system::vpanic (const char *fmt, va_list args) 846 disable_warning ("Octave:single-quote-string");
627 { 847 disable_warning ("Octave:str-to-num");
628 // Is there any point in trying to write the panic message to the 848 disable_warning ("Octave:mixed-string-concat");
629 // diary? 849 disable_warning ("Octave:variable-switch-label");
630 850 }
631 std::cerr << "panic: " << format_message (fmt, args) << std::endl; 851
632 852 void error_system::interpreter_try (unwind_protect& frame)
633 abort (); 853 {
634 } 854 frame.protect_var (m_debug_on_error);
635 855 m_debug_on_error = false;
636 void error_system::panic (const char *fmt, ...) 856
637 { 857 frame.protect_var (m_debug_on_warning);
638 va_list args; 858 m_debug_on_warning = false;
639 va_start (args, fmt); 859
640 vpanic (fmt, args); 860 // Leave debug_on_caught as it was, so errors in try/catch are still
641 va_end (args); 861 // caught.
642 } 862 }
643 863
644 octave_scalar_map error_system::warning_query (const std::string& id_arg) 864 void error_system::throw_error (const std::string& err_type,
645 { 865 const std::string& id,
646 octave_scalar_map retval; 866 const std::string& message,
647 867 const std::list<frame_info>& stack_info_arg)
648 std::string id = id_arg; 868 {
649 869 std::list<frame_info> stack_info = stack_info_arg;
650 if (id == "last") 870
651 id = last_warning_id (); 871 if (stack_info.empty ())
652 872 {
653 octave_map opts = warning_options (); 873 tree_evaluator& tw = m_interpreter.get_evaluator ();
654 874
655 Cell ident = opts.contents ("identifier"); 875 stack_info = tw.backtrace_info ();
656 Cell state = opts.contents ("state"); 876
657 877 // Print the error message only if it is different from the
658 octave_idx_type nel = ident.numel (); 878 // previous one; makes the output more concise and readable.
659 879
660 panic_if (nel == 0); 880 stack_info.unique ();
661 881 }
662 bool found = false; 882
663 883 execution_exception ex (err_type, id, message, stack_info);
664 std::string val; 884
665 885 throw_error (ex);
666 for (octave_idx_type i = 0; i < nel; i++) 886 }
667 { 887
668 if (ident(i).string_value () == id) 888 void error_system::throw_error (execution_exception& ex)
669 { 889 {
670 val = state(i).string_value (); 890 throw ex;
671 found = true; 891 }
672 break; 892
673 } 893 void error_system::save_exception (const execution_exception& ee)
674 } 894 {
675 895 last_error_id (ee.identifier ());
676 if (! found) 896 std::string message = ee.message ();
677 { 897 std::string xmsg
678 for (octave_idx_type i = 0; i < nel; i++) 898 = (message.size () > 0 && message.back () == '\n'
679 { 899 ? message.substr (0, message.size () - 1) : message);
680 if (ident(i).string_value () == "all") 900 last_error_message (xmsg);
681 { 901 last_error_stack (make_stack_map (ee.stack_info ()));
682 val = state(i).string_value (); 902 }
683 found = true; 903
684 break; 904 void error_system::display_exception (const execution_exception& ee) const
685 } 905 {
686 } 906 // FIXME: How should we handle beep_on_error?
687 } 907
688 908 ee.display (octave_diary);
689 // The warning state "all" is always supposed to remain in the list, 909
690 // so we should always find a state, either explicitly or by using the 910 // FIXME: Handle display using an event manager message so that the
691 // state for "all". 911 // GUI or other client can receive error messages without needing to
692 panic_unless (found); 912 // capture them from std::cerr or some other stream.
693 913
694 retval.assign ("identifier", id); 914 event_manager& evmgr = m_interpreter.get_event_manager ();
695 retval.assign ("state", val); 915
696 916 evmgr.display_exception (ee, m_beep_on_error);
697 return retval; 917 }
698 }
699
700 std::string error_system::default_warning_state (void)
701 {
702 std::string retval = "on";
703
704 octave_map opts = warning_options ();
705
706 Cell ident = opts.contents ("identifier");
707 Cell state = opts.contents ("state");
708
709 octave_idx_type nel = ident.numel ();
710
711 for (octave_idx_type i = 0; i < nel; i++)
712 {
713 if (ident(i).string_value () == "all")
714 {
715 retval = state(i).string_value ();
716 break;
717 }
718 }
719
720 return retval;
721 }
722
723 void error_system::display_warning_options (std::ostream& os)
724 {
725 octave_map opts = warning_options ();
726
727 Cell ident = opts.contents ("identifier");
728 Cell state = opts.contents ("state");
729
730 octave_idx_type nel = ident.numel ();
731
732 std::string all_state = default_warning_state ();
733
734 if (all_state == "on")
735 os << "By default, warnings are enabled.";
736 else if (all_state == "off")
737 os << "By default, warnings are disabled.";
738 else if (all_state == "error")
739 os << "By default, warnings are treated as errors.";
740 else
741 panic_impossible ();
742
743 if (nel > 1)
744 {
745 os << "\n";
746 os << "Non-default warning states are:\n\n";
747 os << " State Warning ID\n";
748 }
749
750 // The state for "all" is always supposed to be first in the list.
751
752 for (octave_idx_type i = 1; i < nel; i++)
753 {
754 std::string tid = ident(i).string_value ();
755 std::string tst = state(i).string_value ();
756
757 os << std::setw (7) << tst << " " << tid << "\n";
758 }
759
760 os << std::endl;
761 }
762
763 void error_system::set_warning_option (const std::string& state,
764 const std::string& ident)
765 {
766 std::string all_state = default_warning_state ();
767
768 if (state != "on" && state != "off" && state != "error")
769 error ("invalid warning state: %s", state.c_str ());
770
771 octave_map opts = warning_options ();
772
773 Cell tid = opts.contents ("identifier");
774 Cell tst = opts.contents ("state");
775
776 octave_idx_type nel = tid.numel ();
777
778 for (octave_idx_type i = 0; i < nel; i++)
779 {
780 if (tid(i).string_value () == ident)
781 {
782 // We found it in the current list of options. If the state
783 // for "all" is same as arg1, we can simply remove the item
784 // from the list.
785
786 if (state == all_state && ident != "all")
787 {
788 for (i = i + 1; i < nel; i++)
789 {
790 tid(i-1) = tid(i);
791 tst(i-1) = tst(i);
792 }
793
794 tid.resize (dim_vector (1, nel-1));
795 tst.resize (dim_vector (1, nel-1));
796 }
797 else
798 tst(i) = state;
799
800 opts.clear ();
801
802 opts.assign ("identifier", tid);
803 opts.assign ("state", tst);
804
805 warning_options (opts);
806
807 return;
808 }
809 }
810
811 // The option wasn't already in the list. Append it.
812
813 tid.resize (dim_vector (1, nel+1));
814 tst.resize (dim_vector (1, nel+1));
815
816 tid(nel) = ident;
817 tst(nel) = state;
818
819 opts.clear ();
820
821 opts.assign ("identifier", tid);
822 opts.assign ("state", tst);
823
824 warning_options (opts);
825 }
826
827 void error_system::disable_warning (const std::string& id)
828 {
829 set_warning_option ("off", id);
830 }
831
832 void error_system::initialize_default_warning_state (void)
833 {
834 warning_options (init_warning_options ("on"));
835
836 // Most people will want to have the following disabled.
837
838 disable_warning ("Octave:array-as-logical");
839 disable_warning ("Octave:array-to-scalar");
840 disable_warning ("Octave:array-to-vector");
841 disable_warning ("Octave:imag-to-real");
842 disable_warning ("Octave:language-extension");
843 disable_warning ("Octave:missing-semicolon");
844 disable_warning ("Octave:neg-dim-as-zero");
845 disable_warning ("Octave:separator-insert");
846 disable_warning ("Octave:single-quote-string");
847 disable_warning ("Octave:str-to-num");
848 disable_warning ("Octave:mixed-string-concat");
849 disable_warning ("Octave:variable-switch-label");
850 }
851
852 void error_system::interpreter_try (unwind_protect& frame)
853 {
854 frame.protect_var (m_debug_on_error);
855 m_debug_on_error = false;
856
857 frame.protect_var (m_debug_on_warning);
858 m_debug_on_warning = false;
859
860 // Leave debug_on_caught as it was, so errors in try/catch are still
861 // caught.
862 }
863
864 void error_system::throw_error (const std::string& err_type,
865 const std::string& id,
866 const std::string& message,
867 const std::list<frame_info>& stack_info_arg)
868 {
869 std::list<frame_info> stack_info = stack_info_arg;
870
871 if (stack_info.empty ())
872 {
873 tree_evaluator& tw = m_interpreter.get_evaluator ();
874
875 stack_info = tw.backtrace_info ();
876
877 // Print the error message only if it is different from the
878 // previous one; makes the output more concise and readable.
879
880 stack_info.unique ();
881 }
882
883 execution_exception ex (err_type, id, message, stack_info);
884
885 throw_error (ex);
886 }
887
888 void error_system::throw_error (execution_exception& ex)
889 {
890 throw ex;
891 }
892
893 void error_system::save_exception (const execution_exception& ee)
894 {
895 last_error_id (ee.identifier ());
896 std::string message = ee.message ();
897 std::string xmsg
898 = (message.size () > 0 && message.back () == '\n'
899 ? message.substr (0, message.size () - 1) : message);
900 last_error_message (xmsg);
901 last_error_stack (make_stack_map (ee.stack_info ()));
902 }
903
904 void error_system::display_exception (const execution_exception& ee) const
905 {
906 // FIXME: How should we handle beep_on_error?
907
908 ee.display (octave_diary);
909
910 // FIXME: Handle display using an event manager message so that the
911 // GUI or other client can receive error messages without needing to
912 // capture them from std::cerr or some other stream.
913
914 event_manager& evmgr = m_interpreter.get_event_manager ();
915
916 evmgr.display_exception (ee, m_beep_on_error);
917 }
918 918
919 OCTAVE_END_NAMESPACE(octave) 919 OCTAVE_END_NAMESPACE(octave)
920 920
921 void 921 void
922 vmessage (const char *name, const char *fmt, va_list args) 922 vmessage (const char *name, const char *fmt, va_list args)
1681 else 1681 else
1682 { 1682 {
1683 octave_scalar_map tmp = es.warning_query (arg2); 1683 octave_scalar_map tmp = es.warning_query (arg2);
1684 1684
1685 octave_stdout << '"' << arg2 << R"(" warning state is ")" << 1685 octave_stdout << '"' << arg2 << R"(" warning state is ")" <<
1686 tmp.getfield ("state").string_value () << 1686 tmp.getfield ("state").string_value () <<
1687 "\"\n"; 1687 "\"\n";
1688 } 1688 }
1689 } 1689 }
1690 1690
1691 done = true; 1691 done = true;
1692 } 1692 }