changeset 19473:93fbdbcb3349

fix handling of options struct passed to warning function (bug #36393) * error.cc (default_warning_state, display_warning_options, set_warning_option): New static functions. (Fwarning): Use them. If given a structure arguemnt, step through elements sequentially. * error.tst: New tests.
author John W. Eaton <jwe@octave.org>
date Mon, 29 Dec 2014 23:05:25 -0500
parents 9552138fe6f5
children 8ee14c64ab5f
files libinterp/corefcn/error.cc test/error.tst
diffstat 2 files changed, 177 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/error.cc	Mon Dec 29 18:07:54 2014 -0800
+++ b/libinterp/corefcn/error.cc	Mon Dec 29 23:05:25 2014 -0500
@@ -27,6 +27,7 @@
 #include <cstdarg>
 #include <cstring>
 
+#include <iomanip>
 #include <iostream>
 #include <sstream>
 #include <string>
@@ -1221,6 +1222,127 @@
   return retval;
 }
 
+static std::string
+default_warning_state (void)
+{
+  std::string retval = "on";
+
+  Cell ident = warning_options.contents ("identifier");
+  Cell state = warning_options.contents ("state");
+
+  octave_idx_type nel = ident.numel ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      if (ident(i).string_value () == "all")
+        {
+          retval = state(i).string_value ();
+          break;
+        }
+    }
+
+  return retval;
+}
+
+static void
+display_warning_options (std::ostream& os)
+{
+  Cell ident = warning_options.contents ("identifier");
+  Cell state = warning_options.contents ("state");
+
+  octave_idx_type nel = ident.numel ();
+
+  std::string all_state = default_warning_state ();
+
+  if (all_state == "on")
+    os << "By default, warnings are enabled.";
+  else if (all_state == "off")
+    os << "By default, warnings are disabled.";
+  else if (all_state == "error")
+    os << "By default, warnings are treated as errors.";
+  else
+    panic_impossible ();
+  
+  if (nel > 1)
+    os << "\n\n";
+
+  // The state for all is always supposed to be first in the list.
+
+  for (octave_idx_type i = 1; i < nel; i++)
+    {
+      std::string tid = ident(i).string_value ();
+      std::string tst = state(i).string_value ();
+
+      os << std::setw (7) << tst << "  " << tid << "\n";
+    }
+
+  os << std::endl;
+}
+
+static void
+set_warning_option (const std::string& state, const std::string& ident)
+{
+  if (ident == "all")
+    {
+      initialize_warning_options (state);
+      return;
+    }
+
+  std::string all_state = default_warning_state ();
+
+  if (state != "on" && state != "off" && state != "error")
+    error ("invalid warning state: %s", state.c_str ());
+
+  Cell tid = warning_options.contents ("identifier");
+  Cell tst = warning_options.contents ("state");
+
+  octave_idx_type nel = tid.numel ();
+
+  for (octave_idx_type i = 0; i < nel; i++)
+    {
+      if (tid(i).string_value () == ident)
+        {
+          // We found it in the current list of options.  If the state
+          // for "all" is same as arg1, we can simply remove the item
+          // from the list.
+
+          if (state == all_state)
+            {
+              for (i = i + 1; i < nel; i++)
+                {
+                  tid(i-1) = tid(i);
+                  tst(i-1) = tst(i);
+                }
+
+              tid.resize (dim_vector (1, nel-1));
+              tst.resize (dim_vector (1, nel-1));
+            }
+          else
+            tst(i) = state;
+
+          warning_options.clear ();
+
+          warning_options.assign ("identifier", tid);
+          warning_options.assign ("state", tst);
+
+          return;
+        }
+    }
+
+  // The option wasn't already in the list.  Append it.
+
+  tid.resize (dim_vector (1, nel+1));
+  tst.resize (dim_vector (1, nel+1));
+
+  tid(nel) = ident;
+  tst(nel) = state;
+
+  warning_options.clear ();
+
+  warning_options.assign ("identifier", tid);
+  warning_options.assign ("state", tst);
+}
+
 DEFUN (warning, args, nargout,
        "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {} warning (@var{template}, @dots{})\n\
@@ -1475,49 +1597,7 @@
                   if (arg2 == "last")
                     arg2 = Vlast_warning_id;
 
-                  if (arg2 == "all")
-                    initialize_warning_options (arg1);
-                  else
-                    {
-                      Cell ident = warning_options.contents ("identifier");
-                      Cell state = warning_options.contents ("state");
-
-                      octave_idx_type nel = ident.numel ();
-
-                      bool found = false;
-
-                      for (octave_idx_type i = 0; i < nel; i++)
-                        {
-                          if (ident(i).string_value () == arg2)
-                            {
-                              // FIXME: if state for "all" is  same as arg1,
-                              //        we can simply remove the item
-                              //        from the list.
-
-                              state(i) = arg1;
-                              warning_options.assign ("state", state);
-                              found = true;
-                              break;
-                            }
-                        }
-
-                      if (! found)
-                        {
-                          // FIXME: if state for "all" is same as arg1,
-                          //        we don't need to do anything.
-
-                          ident.resize (dim_vector (1, nel+1));
-                          state.resize (dim_vector (1, nel+1));
-
-                          ident(nel) = arg2;
-                          state(nel) = arg1;
-
-                          warning_options.clear ();
-
-                          warning_options.assign ("identifier", ident);
-                          warning_options.assign ("state", state);
-                        }
-                    }
+                  set_warning_option (arg1, arg2);
 
                   done = true;
                 }
@@ -1554,7 +1634,10 @@
     }
   else if (argc == 1)
     {
-      retval = warning_options;
+      if (nargout > 0)
+        retval = warning_options;
+      else
+        display_warning_options (octave_stdout);
 
       done = true;
     }
@@ -1569,7 +1652,25 @@
           octave_map m = arg.map_value ();
 
           if (m.contains ("identifier") && m.contains ("state"))
-            warning_options = m;
+            {
+              // Simply step through the struct elements one at a time.
+
+              Cell ident = m.contents ("identifier");
+              Cell state = m.contents ("state");
+
+              octave_idx_type nel = ident.numel ();
+
+              for (octave_idx_type i = 0; i < nel; i++)
+                {
+                  std::string tst = state(i).string_value ();
+                  std::string tid = ident(i).string_value ();
+
+                  if (error_state)
+                    return retval;
+
+                  set_warning_option (tst, tid);
+                }
+            }
           else
             error ("warning: expecting structure with fields 'identifier' and 'state'");
 
@@ -1624,7 +1725,7 @@
 void
 disable_warning (const std::string& id)
 {
-  set_warning_state (id, "off");
+  set_warning_option ("off", id);
 }
 
 void
--- a/test/error.tst	Mon Dec 29 18:07:54 2014 -0800
+++ b/test/error.tst	Mon Dec 29 23:05:25 2014 -0500
@@ -59,6 +59,36 @@
 %! assert (warning ("query", "backtrace"), st);
 %! warning (ws.state, "backtrace");
 
+%!shared t1_opts, t2_opts, t1_id, t1_state, saved_opts, saved_id, saved_state
+%! saved_opts = warning ();
+%! saved_id = {saved_opts.identifier};
+%! saved_state = {saved_opts.state};
+%! warning ("off", "all");
+%! assert (warning (), struct ("identifier", {"all"}, "state", {"off"}));
+%! warning ("off", "all");
+%! warning (saved_opts);
+%! t1_opts = struct ("identifier", {"foo:bar"}, "state", {"off"});
+%! t1_id = {t1_opts.identifier};
+%! t1_state = {t1_opts.state};
+%! warning (t1_opts);
+%! t2_opts = struct ("identifier", [saved_id, t1_id], "state", [saved_state, t1_state]);
+%! assert (warning (), t2_opts);
+%! warning ("off", "all");
+%! warning (saved_opts);
+
+## Bug 36393
+
+%!test
+%! w0 = warning;
+%! warnoffId = "MATLAB:singularMatrix";
+%! warnstat = warning ("query", warnoffId);
+%! warnoff = warnstat;
+%! warnoff.state = "off";
+%! warning (warnoff); %update warning status
+%! warning (warnstat); %reset warning status
+%! w = warning;
+%! assert (w, w0);
+
 ## Test usage() function
 
 %!function g ()