changeset 14558:0c9c85e702ca

better compatibility for error/warning message IDs and format specifiers * error.cc (maybe_extract_message_id): New function. (Ferror, Fwarning): Use it to check for and extract message ID and format string. (handle_message): New arg, HAVE_FMT. Use it to determine whether to call sprintf. Change all callers.
author John W. Eaton <jwe@octave.org>
date Thu, 12 Apr 2012 16:48:54 -0400
parents e8e86ae3abbc
children 90c51d8797cc
files src/error.cc
diffstat 1 files changed, 69 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/error.cc	Thu Apr 12 16:27:39 2012 -0400
+++ b/src/error.cc	Thu Apr 12 16:48:54 2012 -0400
@@ -764,7 +764,7 @@
 
 static std::string
 handle_message (error_fun f, const char *id, const char *msg,
-                const octave_value_list& args)
+                const octave_value_list& args, bool have_fmt)
 {
   std::string retval;
 
@@ -776,7 +776,7 @@
     {
       octave_value arg;
 
-      if (nargin > 1)
+      if (have_fmt)
         {
           octave_value_list tmp = Fsprintf (args, 1);
           arg = tmp(0);
@@ -962,6 +962,56 @@
   return retval;
 }
 
+// Determine whether the first argument to error or warning function
+// should be handled as the message identifier or as the format string.
+
+static bool
+maybe_extract_message_id (const std::string& caller,
+                          const octave_value_list& args,
+                          octave_value_list& nargs,
+                          std::string& id)
+{
+  nargs = args;
+  id = std::string ();
+
+  int nargin = args.length ();
+
+  bool have_fmt = nargin > 1;
+
+  if (nargin > 0)
+    {
+      std::string arg1 = args(0).string_value ();
+
+      if (! error_state)
+        {
+          // For compatibility with Matlab, an identifier must contain
+          // ':', but not at the beginning or the end, and it must not
+          // contain '%' (even if it is not a valid conversion operator).
+
+          if (arg1.find ('%') == std::string::npos
+              && arg1.find (':') != std::string::npos
+              && arg1[0] != ':'
+              && arg1[arg1.length()-1] != ':')
+            {
+              if (nargin > 1)
+                {
+                  id = arg1;
+
+                  nargs.resize (nargin-1);
+
+                  for (int i = 1; i < nargin; i++)
+                    nargs(i-1) = args(i);
+                }
+              else
+                nargs(0) = "call to " + caller
+                  + " with message identifier requires message";
+            }
+        }
+    }
+
+  return have_fmt;
+}
+
 DEFUN (error, args, ,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {} error (@var{template}, @dots{})\n\
@@ -1031,26 +1081,9 @@
     print_usage ();
   else
     {
-      if (nargin > 1)
-        {
-          std::string arg1 = args(0).string_value ();
-
-          if (! error_state)
-            {
-              if (arg1.find ('%') == std::string::npos)
-                {
-                  id = arg1;
+      bool have_fmt = false;
 
-                  nargs.resize (nargin-1);
-
-                  for (int i = 1; i < nargin; i++)
-                    nargs(i-1) = args(i);
-                }
-            }
-          else
-            return retval;
-        }
-      else if (nargin == 1 && args(0).is_map ())
+      if (nargin == 1 && args(0).is_map ())
         {
           // empty struct is not an error.  return and resume calling function.
           if (args(0).is_empty ())
@@ -1084,8 +1117,16 @@
           // structure, but that will require some more significant
           // surgery on handle_message, error_with_id, etc.
         }
+      else
+        {
+          have_fmt = maybe_extract_message_id ("error", args, nargs, id);
 
-      handle_message (error_with_id, id.c_str (), "unspecified error", nargs);
+          if (error_state)
+            return retval;
+        }
+
+      handle_message (error_with_id, id.c_str (), "unspecified error",
+                      nargs, have_fmt);
     }
 
   return retval;
@@ -1399,30 +1440,16 @@
 
       std::string id;
 
-      if (nargin > 1)
-        {
-          std::string arg1 = args(0).string_value ();
-
-          if (! error_state)
-            {
-              if (arg1.find ('%') == std::string::npos)
-                {
-                  id = arg1;
+      bool have_fmt = maybe_extract_message_id ("warning", args, nargs, id);
 
-                  nargs.resize (nargin-1);
-
-                  for (int i = 1; i < nargin; i++)
-                    nargs(i-1) = args(i);
-                }
-            }
-          else
-            return retval;
-        }
+      if (error_state)
+        return retval;
 
       std::string prev_msg = Vlast_warning_message;
 
       std::string curr_msg = handle_message (warning_with_id, id.c_str (),
-                                             "unspecified warning", nargs);
+                                             "unspecified warning", nargs,
+                                             have_fmt);
 
       if (nargout > 0)
         retval = prev_msg;
@@ -1765,7 +1792,7 @@
 @end deftypefn")
 {
   octave_value_list retval;
-  handle_message (usage_with_id, "", "unknown", args);
+  handle_message (usage_with_id, "", "unknown", args, true);
   return retval;
 }