changeset 14212:a0d98842a4d8

maint: periodic merge of stable to default.
author Rik <octave@nomad.inbox5.com>
date Wed, 18 Jan 2012 21:14:11 -0800
parents 3f4cae8cb9fc (diff) 846273dae16b (current diff)
children a022c04f68cc
files
diffstat 8 files changed, 200 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/contributors.in
+++ b/doc/interpreter/contributors.in
@@ -169,6 +169,7 @@
 Kai P. Mueller
 Hannes Müller
 Victor Munoz
+Iain Murray
 Carmen Navarrete
 Todd Neal
 Philip Nienhuis
--- a/scripts/plot/__gnuplot_drawnow__.m
+++ b/scripts/plot/__gnuplot_drawnow__.m
@@ -205,7 +205,7 @@
           endif
           switch (term)
           case terminals_with_size
-            size_str = sprintf ("size %g,%g", gnuplot_size);
+            size_str = sprintf ("size %.12g,%.12g", gnuplot_size);
           case "tikz"
             size_str = sprintf ("size %gin,%gin", gnuplot_size);
           case "dumb"
--- a/scripts/plot/legend.m
+++ b/scripts/plot/legend.m
@@ -147,7 +147,7 @@
     if (isscalar (kids))
       kids = get(kids, "children")(:);
     else
-      kids = [get(kids, "children"){:}](:);
+      kids = flipud ([get(kids, "children"){:}](:));
     endif
   endif
   nargs = numel (varargin);
@@ -1159,3 +1159,24 @@
 %! h = legend ("Hello_World", "foo^bar");
 %! set (h, "interpreter", "none")
 
+%!demo
+%! x = 0:10;
+%! y1 = rand (size (x));
+%! y2 = rand (size (x));
+%! [ax, h1, h2] = plotyy (x, y1, x, y2);
+%! legend ([h1, h2], {"Blue", "Green"}, "location", "south");
+
+%!demo
+%! x = 0:10;
+%! y1 = rand (size (x));
+%! y2 = rand (size (x));
+%! [ax, h1, h2] = plotyy (x, y1, x, y2);
+%! legend ({"Blue", "Green"}, "location", "south");
+
+%!demo
+%! x = 0:10;
+%! y1 = rand (size (x));
+%! y2 = rand (size (x));
+%! [ax, h1, h2] = plotyy (x, y1, x, y2);
+%! legend ("Blue", "Green", "location", "south");
+
--- a/scripts/plot/print.m
+++ b/scripts/plot/print.m
@@ -370,6 +370,10 @@
         else
           fontsize = opts.fontsize;
         endif
+        if (! isempty (opts.scalefontsize) && ! opt.scalefontsize != 1)
+          ## This is done to work around the bbox being whole numbers.
+          fontsize = fontsize * opts.scalefontsize;
+        endif
         set (h(ishandle(h)), "fontsize", fontsize);
       endif
     endif
--- a/scripts/plot/private/__print_parse_opts__.m
+++ b/scripts/plot/private/__print_parse_opts__.m
@@ -36,6 +36,7 @@
   arg_st.fig2dev_binary = __quote_path__ (__find_binary__ ("fig2dev"));
   arg_st.fontsize = "";
   arg_st.font = "";
+  arg_st.scalefontsize = 1;
   arg_st.force_solid = 0; # 0=default, -1=dashed, +1=solid
   arg_st.formatted_for_printing = false;
   arg_st.ghostscript.binary = __quote_path__ (__ghostscript_binary__ ());
@@ -326,8 +327,12 @@
       arg_st.ghostscript.pageoffset = paperposition(1:2);
     endif
   else
-    ## Convert canvas size to points from pixles.
-    arg_st.canvas_size = arg_st.canvas_size * 72 / arg_st.ghostscript.resolution;
+    ## Convert canvas size to points from pixels.
+    if (! isempty (arg_st.fontsize))
+      ## Work around the eps bbox having whole numbers (both gnuplot & gl2ps).
+      arg_st.scalefontsize = arg_st.ghostscript.resolution / 72;
+    endif
+    arg_st.ghostscript.resolution = 72;
     arg_st.ghostscript.papersize = arg_st.canvas_size;
     arg_st.ghostscript.epscrop = true;
     arg_st.ghostscript.pageoffset = [0, 0];
--- a/src/file-io.cc
+++ b/src/file-io.cc
@@ -43,7 +43,9 @@
 #include <cstdio>
 
 #include <iostream>
+#include <locale>
 #include <stack>
+#include <stdexcept>
 #include <vector>
 
 #include <fcntl.h>
@@ -1070,7 +1072,7 @@
 DEFUN (fscanf, args, ,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}] =} fscanf (@var{fid}, @var{template}, @var{size})\n\
-@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}] =} fscanf (@var{fid}, @var{template}, \"C\")\n\
++@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} fscanf (@var{fid}, @var{template}, @var{locale})\n\
 In the first form, read from @var{fid} according to @var{template},\n\
 returning the result in the matrix @var{val}.\n\
 \n\
@@ -1109,7 +1111,10 @@
 with each conversion specifier in @var{template} corresponding to a\n\
 single scalar return value.  This form is more `C-like', and also\n\
 compatible with previous versions of Octave.  The number of successful\n\
-conversions is returned in @var{count}\n\
+conversions is returned in @var{count}. It permits to explicitly\n\
+specify a locale to take into account langage specific features, \n\
+such as decimal separator. This operation restores the previous locales\n\
+setting at the end of the conversion.\n\
 @ifclear OCTAVE_MANUAL\n\
 \n\
 See the Formatted Input section of the GNU Octave manual for a\n\
@@ -1131,7 +1136,25 @@
       if (! error_state)
         {
           if (args(1).is_string ())
-            retval = os.oscanf (args(1), who);
+            {
+              std::locale oldloc;
+              try
+                {
+                  // Use args(2) val as the new locale setting. Keep
+                  // old val for restoring afterwards.
+                  oldloc = 
+                    os.imbue (std::locale (args(2).string_value ().c_str ()));
+                  
+                }
+              catch (std::runtime_error)
+                {
+                  // Display a warning if the specified locale is unknown
+                  warning ("fscanf: invalid locale. Try `locale -a' for a list of supported values.");
+                  oldloc = std::locale::classic ();
+                }
+              retval = os.oscanf (args(1), who);
+              os.imbue (oldloc);
+            }
           else
             ::error ("%s: format TEMPLATE must be a string", who.c_str ());
         }
@@ -1199,7 +1222,7 @@
 DEFUN (sscanf, args, ,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}, @var{pos}] =} sscanf (@var{string}, @var{template}, @var{size})\n\
-@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}] =} sscanf (@var{string}, @var{template}, \"C\")\n\
+@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} sscanf (@var{string}, @var{template}, @var{locale})\n\
 This is like @code{fscanf}, except that the characters are taken from the\n\
 string @var{string} instead of from a stream.  Reaching the end of the\n\
 string is treated as an end-of-file condition.  In addition to the values\n\
@@ -1224,8 +1247,22 @@
 
           if (os.is_valid ())
             {
-              if (args(1).is_string ())
-                retval = os.oscanf (args(1), who);
+              if (args(1).is_string ()) 
+                {
+                  // Use args(2) val as the new locale setting. As the os
+                  // object is short lived, we don't need to restore
+                  // locale afterwards.
+                  try
+                    {  
+                      os.imbue (std::locale (args(2).string_value ().c_str ()));
+                    }
+                  catch (std::runtime_error)
+                    {
+                      // Display a warning if the specified locale is unknown
+                      warning ("sscanf: invalid locale. Try `locale -a' for a list of supported values.");
+                    }
+                  retval = os.oscanf (args(1), who);
+                }              
               else
                 ::error ("%s: format TEMPLATE must be a string", who.c_str ());
             }
@@ -1293,10 +1330,16 @@
   return retval;
 }
 
+/*
+%!test
+%! assert(sscanf('1,2', '%f', 'C'), 1)
+%! assert(sscanf('1,2', '%f', 'fr_FR'), 1.2)
+*/
+
 DEFUN (scanf, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {[@var{val}, @var{count}, @var{errmsg}] =} scanf (@var{template}, @var{size})\n\
-@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}, @var{errmsg}]] =} scanf (@var{template}, \"C\")\n\
+@deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}]] =} scanf (@var{template}, @var{locale}))\n\
 This is equivalent to calling @code{fscanf} with @var{fid} = @code{stdin}.\n\
 \n\
 It is currently not useful to call @code{scanf} in interactive\n\
--- a/src/oct-stream.h
+++ b/src/oct-stream.h
@@ -371,6 +371,12 @@
 
   virtual std::ostream *output_stream (void) { return 0; }
 
+  // If the derived class is locale-aware, it must implement this function 
+  // in order to set a new locale. By default, this function avoids messing 
+  // with locales and ignores its input argument.
+  virtual std::locale imbue ( const std::locale & loc ) 
+    { return std::locale::classic (); }
+  
   // Return TRUE if this stream is open.
 
   bool is_open (void) const { return open_state; }
@@ -613,7 +619,23 @@
   {
     return rep ? rep->output_stream () : 0;
   }
-
+  
+  std::locale imbue (const std::locale & loc )
+    {
+      if (!rep) return std::locale::classic ();
+      
+      std::istream *is = rep->input_stream ();
+      std::ostream *os = rep->output_stream ();
+      
+      if (os) 
+        {
+          if (is)
+            (void) is->imbue (loc);
+          return os->imbue (loc);
+        }
+      return is ? is->imbue (loc) : std::locale::classic ();
+    }
+  
   void clearerr (void) { if (rep) rep->clearerr (); }
 
 private:
--- a/src/ov-usr-fcn.cc
+++ b/src/ov-usr-fcn.cc
@@ -51,6 +51,7 @@
 #include "parse.h"
 #include "profiler.h"
 #include "variables.h"
+#include "ov-fcn-handle.h"
 
 // Whether to optimize subsasgn method calls.
 static bool Voptimize_subsasgn_calls = true;
@@ -629,12 +630,15 @@
 DEFUN (nargin, args, ,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {} nargin ()\n\
-@deftypefnx {Built-in Function} {} nargin (@var{fcn_name})\n\
+@deftypefnx {Built-in Function} {} nargin (@var{fcn})\n\
 Within a function, return the number of arguments passed to the function.\n\
 At the top level, return the number of command line arguments passed to\n\
-Octave.  If called with the optional argument @var{fcn_name}, return the\n\
-maximum number of arguments the named function can accept, or -1 if the\n\
-function accepts a variable number of arguments.\n\
+Octave.\n\
+\n\
+If called with the optional argument @var{fcn}, a function name or handle,\n\
+return the declared number of arguments that the function can accept.\n\
+If the last argument is @var{varargin} the returned value is negative.\n\
+This feature does not work on builtin functions.\n\
 @seealso{nargout, varargin, isargout, varargout, nthargout}\n\
 @end deftypefn")
 {
@@ -644,40 +648,37 @@
 
   if (nargin == 1)
     {
-      std::string fname = args(0).string_value ();
+      octave_value func = args(0);
 
-      if (! error_state)
+      if (func.is_string ())
         {
-          octave_value fcn_val = symbol_table::find_function (fname);
-
-          if (fcn_val.is_user_function ())
-            {
-              octave_user_function *fcn = fcn_val.user_function_value (true);
+          std::string name = func.string_value ();
+          func = symbol_table::find_function (name);
+          if (func.is_undefined ())
+            error ("nargout: invalid function name: %s", name.c_str ());
+        }
 
-              if (fcn)
-                {
-                  if (fcn->takes_varargs ())
-                    retval = -1;
-                  else
-                    {
-                      tree_parameter_list *param_list = fcn->parameter_list ();
+      octave_function *fcn_val = func.function_value ();
+      if (fcn_val)
+        {
+          octave_user_function *fcn = fcn_val->user_function_value (true);
 
-                      retval = param_list ? param_list->length () : 0;
-                    }
-                }
-              else
-                error ("nargin: loading user-defined function failed");
+          if (fcn)
+            {
+              tree_parameter_list *param_list = fcn->parameter_list ();
+
+              retval = param_list ? param_list->length () : 0;
+              if (fcn->takes_varargs ())
+                retval = -1 - retval;
             }
           else
             {
-              // FIXME -- what about built-in functions or functions
-              // defined in .oct files or .mex files?
-
-              error ("nargin: FCN_NAME must be a user-defined function");
+              // Matlab gives up for histc, so maybe it's ok we give up somtimes too.
+              error ("nargin: nargin information not available for builtin functions");
             }
         }
       else
-        error ("nargin: FCN_NAME must be a string");
+        error ("nargin: FCN must be a string or function handle");
     }
   else if (nargin == 0)
     {
@@ -695,11 +696,12 @@
 DEFUN (nargout, args, ,
   "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {} nargout ()\n\
-@deftypefnx {Built-in Function} {} nargout (@var{fcn_name})\n\
+@deftypefnx {Built-in Function} {} nargout (@var{fcn})\n\
 Within a function, return the number of values the caller expects to\n\
-receive.  If called with the optional argument @var{fcn_name}, return the\n\
-maximum number of values the named function can produce, or -1 if the\n\
-function can produce a variable number of values.\n\
+receive.  If called with the optional argument @var{fcn}, a function\n\
+name or handle, return the number of declared output values that the\n\
+function can produce. If the final output argument is @var{varargout}\n\
+the returned value is negative.\n\
 \n\
 For example,\n\
 \n\
@@ -718,7 +720,23 @@
 will cause @code{nargout} to return 2 inside the function\n\
 @code{f}.\n\
 \n\
-At the top level, @code{nargout} is undefined.\n\
+In the second usage,\n\
+\n\
+@example\n\
+nargout (@@histc) \% or nargout ('histc')\n\
+@end example\n\
+\n\
+will return 2, because @code{histc} has two outputs, whereas\n\
+\n\
+@example\n\
+nargout (@@deal)\n\
+@end example\n\
+\n\
+will return -1, because @code{deal} has a variable number of outputs.\n\
+\n\
+At the top level, @code{nargout} with no argument is undefined.\n\
+@code{nargout} does not work on builtin functions.\n\
+@code{nargout} returns -1 for all anonymous functions.\n\
 @seealso{nargin, varargin, isargout, varargout, nthargout}\n\
 @end deftypefn")
 {
@@ -728,30 +746,58 @@
 
   if (nargin == 1)
     {
-      std::string fname = args(0).string_value ();
+      octave_value func = args(0);
 
-      if (! error_state)
+      if (func.is_string ())
+        {
+          std::string name = func.string_value ();
+          func = symbol_table::find_function (name);
+          if (func.is_undefined ())
+            error ("nargout: invalid function name: %s", name.c_str ());
+        }
+
+      if (func.is_inline_function ())
         {
-          octave_value fcn_val = symbol_table::find_user_function (fname);
+          retval = 1;
+          return retval;
+        }
+
+      if (func.is_function_handle ())
+        {
+          octave_fcn_handle *fh = func.fcn_handle_value ();
+          std::string fh_nm = fh->fcn_name ();
 
-          octave_user_function *fcn = fcn_val.user_function_value (true);
+          if (fh_nm == octave_fcn_handle::anonymous)
+            {
+              retval = -1;
+              return retval;
+            }
+        }
+
+      octave_function *fcn_val = func.function_value ();
+      if (fcn_val)
+        {
+          octave_user_function *fcn = fcn_val->user_function_value (true);
 
           if (fcn)
             {
+              tree_parameter_list *ret_list = fcn->return_list ();
+          
+              retval = ret_list ? ret_list->length () : 0;
+
               if (fcn->takes_var_return ())
-                retval = -1;
-              else
-                {
-                  tree_parameter_list *ret_list = fcn->return_list ();
-
-                  retval = ret_list ? ret_list->length () : 0;
-                }
+                retval = -1 - retval;
             }
           else
-            error ("nargout: invalid function");
+            {
+              // JWE said this information is not available (currently, 2011-03-10)
+              // without making intrusive changes to Octave.
+              // Matlab gives up for histc, so maybe it's ok we give up somtimes too.
+              error ("nargout: nargout information not available for builtin functions.");
+            }
         }
       else
-        error ("nargout: FCN_NAME must be a string");
+        error ("nargout: FCN must be a string or function handle");
     }
   else if (nargin == 0)
     {