PageRenderTime 66ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/libinterp/corefcn/error.cc

https://bitbucket.org/ttl/octave-ttl
C++ | 2145 lines | 1679 code | 353 blank | 113 comment | 334 complexity | b8a79e0833412213a5f07ea4e6bb19cb MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file