changeset 26088:2b92498c111e

move symbol_info and symbol_info_list classes to separate file * syminfo.h, syminfo.h: New files. Move symbol_info and symbol_info_list classes here from variables.cc and move them inside octave namespace. Change all uses. * libinterp/corefcn/module.mk: Update.
author John W. Eaton <jwe@octave.org>
date Thu, 15 Nov 2018 22:45:04 -0500
parents 7656fcd0ff9f
children e71893aa322c
files libinterp/corefcn/module.mk libinterp/corefcn/syminfo.cc libinterp/corefcn/syminfo.h libinterp/corefcn/variables.cc
diffstat 4 files changed, 697 insertions(+), 602 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/module.mk	Thu Nov 15 15:05:36 2018 -0500
+++ b/libinterp/corefcn/module.mk	Thu Nov 15 22:45:04 2018 -0500
@@ -82,6 +82,7 @@
   %reldir%/sighandlers.h \
   %reldir%/sparse-xdiv.h \
   %reldir%/sparse-xpow.h \
+  %reldir%/syminfo.h \
   %reldir%/symrec.h \
   %reldir%/symscope.h \
   %reldir%/symtab.h \
@@ -237,6 +238,7 @@
   %reldir%/sub2ind.cc \
   %reldir%/svd.cc \
   %reldir%/sylvester.cc \
+  %reldir%/syminfo.cc \
   %reldir%/symrec.cc \
   %reldir%/symscope.cc \
   %reldir%/symtab.cc \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/syminfo.cc	Thu Nov 15 22:45:04 2018 -0500
@@ -0,0 +1,560 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <iomanip>
+#include <list>
+#include <ostream>
+#include <sstream>
+
+#include "Cell.h"
+#include "octave-preserve-stream-state.h"
+#include "ov.h"
+#include "oct-map.h"
+#include "pager.h"
+#include "syminfo.h"
+
+namespace octave
+{
+  void
+  symbol_info::display_line (std::ostream& os,
+                             const std::list<whos_parameter>& params) const
+  {
+    std::string dims_str = m_value.get_dims_str ();
+
+    auto i = params.begin ();
+
+    octave::preserve_stream_state stream_state (os);
+
+    while (i != params.end ())
+      {
+        whos_parameter param = *i;
+
+        if (param.command != '\0')
+          {
+            // Do the actual printing.
+
+            switch (param.modifier)
+              {
+              case 'l':
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                break;
+
+              case 'r':
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+                break;
+
+              case 'c':
+                if (param.command == 's')
+                  {
+                    int front = param.first_parameter_length
+                      - dims_str.find ('x');
+                    int back = param.parameter_length
+                      - dims_str.length ()
+                      - front;
+                    front = (front > 0) ? front : 0;
+                    back = (back > 0) ? back : 0;
+
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (front)
+                       << ""
+                       << std::resetiosflags (std::ios::left)
+                       << dims_str
+                       << std::setiosflags (std::ios::left)
+                       << std::setw (back)
+                       << ""
+                       << std::resetiosflags (std::ios::left);
+                  }
+                else
+                  {
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (param.parameter_length);
+                  }
+                break;
+
+              default:
+                error ("whos_line_format: modifier '%c' unknown",
+                       param.modifier);
+
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+              }
+
+            switch (param.command)
+              {
+              case 'a':
+                {
+                  char tmp[6];
+
+                  tmp[0] = (m_is_automatic ? 'a' : ' ');
+                  tmp[1] = (m_is_complex ? 'c' : ' ');
+                  tmp[2] = (m_is_formal ? 'f' : ' ');
+                  tmp[3] = (m_is_global ? 'g' : ' ');
+                  tmp[4] = (m_is_persistent ? 'p' : ' ');
+                  tmp[5] = 0;
+
+                  os << tmp;
+                }
+                break;
+
+              case 'b':
+                os << m_value.byte_size ();
+                break;
+
+              case 'c':
+                os << m_value.class_name ();
+                break;
+
+              case 'e':
+                os << m_value.numel ();
+                break;
+
+              case 'n':
+                os << m_name;
+                break;
+
+              case 's':
+                if (param.modifier != 'c')
+                  os << dims_str;
+                break;
+
+              case 't':
+                os << m_value.type_name ();
+                break;
+
+              default:
+                error ("whos_line_format: command '%c' unknown",
+                       param.command);
+              }
+
+            os << std::resetiosflags (std::ios::left)
+               << std::resetiosflags (std::ios::right);
+            i++;
+          }
+        else
+          {
+            os << param.text;
+            i++;
+          }
+      }
+  }
+
+  octave_map
+  symbol_info_list::map_value (const std::string& caller_function_name,
+                               int nesting_level) const
+  {
+    size_t len = m_lst.size ();
+
+    Cell name_info (len, 1);
+    Cell size_info (len, 1);
+    Cell bytes_info (len, 1);
+    Cell class_info (len, 1);
+    Cell global_info (len, 1);
+    Cell sparse_info (len, 1);
+    Cell complex_info (len, 1);
+    Cell nesting_info (len, 1);
+    Cell persistent_info (len, 1);
+
+    size_t j = 0;
+
+    for (const auto& syminfo : m_lst)
+      {
+        octave_scalar_map ni;
+
+        ni.assign ("function", caller_function_name);
+        ni.assign ("level", nesting_level);
+
+        name_info(j) = syminfo.name ();
+        global_info(j) = syminfo.is_global ();
+        persistent_info(j) = syminfo.is_persistent ();
+
+        octave_value val = syminfo.value ();
+
+        size_info(j) = val.size ();
+        bytes_info(j) = val.byte_size ();
+        class_info(j) = val.class_name ();
+        sparse_info(j) = val.issparse ();
+        complex_info(j) = val.iscomplex ();
+        nesting_info(j) = ni;
+
+        j++;
+      }
+
+    octave_map info;
+
+    info.assign ("name", name_info);
+    info.assign ("size", size_info);
+    info.assign ("bytes", bytes_info);
+    info.assign ("class", class_info);
+    info.assign ("global", global_info);
+    info.assign ("sparse", sparse_info);
+    info.assign ("complex", complex_info);
+    info.assign ("nesting", nesting_info);
+    info.assign ("persistent", persistent_info);
+
+    return info;
+  }
+
+  void
+  symbol_info_list::print_descriptor (std::ostream& os,
+                                      const std::list<whos_parameter> params) const
+  {
+    std::ostringstream param_buf;
+
+    octave::preserve_stream_state stream_state (os);
+
+    for (const auto& param : params)
+      {
+        if (param.command != '\0')
+          {
+            // Do the actual printing
+            switch (param.modifier)
+              {
+              case 'l':
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::left)
+                          << std::setw (param.parameter_length);
+                break;
+
+              case 'r':
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::right)
+                          << std::setw (param.parameter_length);
+                break;
+
+              case 'c':
+                if (param.command != 's')
+                  {
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (param.parameter_length);
+                    param_buf << std::setiosflags (std::ios::left)
+                              << std::setw (param.parameter_length);
+                  }
+                break;
+
+              default:
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::left)
+                          << std::setw (param.parameter_length);
+              }
+
+            if (param.command == 's' && param.modifier == 'c')
+              {
+                if (param.modifier == 'c')
+                  {
+                    int a = param.first_parameter_length - param.balance;
+                    a = (a < 0 ? 0 : a);
+                    int b = param.parameter_length - a - param.text.length ();
+                    b = (b < 0 ? 0 : b);
+                    os << std::setiosflags (std::ios::left) << std::setw (a)
+                       << "" << std::resetiosflags (std::ios::left) << param.text
+                       << std::setiosflags (std::ios::left)
+                       << std::setw (b) << ""
+                       << std::resetiosflags (std::ios::left);
+                    param_buf << std::setiosflags (std::ios::left)
+                              << std::setw (a)
+                              << "" << std::resetiosflags (std::ios::left)
+                              << param.line
+                              << std::setiosflags (std::ios::left)
+                              << std::setw (b) << ""
+                              << std::resetiosflags (std::ios::left);
+                  }
+              }
+            else
+              {
+                os << param.text;
+                param_buf << param.line;
+              }
+            os << std::resetiosflags (std::ios::left)
+               << std::resetiosflags (std::ios::right);
+            param_buf << std::resetiosflags (std::ios::left)
+                      << std::resetiosflags (std::ios::right);
+          }
+        else
+          {
+            os << param.text;
+            param_buf << param.line;
+          }
+      }
+
+    os << param_buf.str ();
+  }
+
+  void symbol_info_list::display (std::ostream& os, const std::string& format)
+  {
+    if (! m_lst.empty ())
+      {
+        size_t bytes = 0;
+        size_t elements = 0;
+
+        std::list<whos_parameter> params = parse_whos_line_format (format);
+
+        print_descriptor (os, params);
+
+        octave_stdout << "\n";
+
+        for (const auto& syminfo : m_lst)
+          {
+            syminfo.display_line (os, params);
+
+            octave_value val = syminfo.value ();
+
+            elements += val.numel ();
+            bytes += val.byte_size ();
+          }
+
+        os << "\nTotal is " << elements
+           << (elements == 1 ? " element" : " elements")
+           << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
+           << "\n";
+      }
+  }
+
+  std::list<whos_parameter>
+  symbol_info_list::parse_whos_line_format (const std::string& format)
+  {
+    int idx;
+    size_t format_len = format.length ();
+    char garbage;
+    std::list<whos_parameter> params;
+
+    size_t bytes1;
+    int elements1;
+
+    std::string param_string = "abcenst";
+    Array<int> param_length (dim_vector (param_string.length (), 1));
+    Array<std::string> param_names (dim_vector (param_string.length (), 1));
+    size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
+
+    pos_a = param_string.find ('a'); // Attributes
+    pos_b = param_string.find ('b'); // Bytes
+    pos_c = param_string.find ('c'); // Class
+    pos_e = param_string.find ('e'); // Elements
+    pos_n = param_string.find ('n'); // Name
+    pos_s = param_string.find ('s'); // Size
+    pos_t = param_string.find ('t'); // Type
+
+    param_names(pos_a) = "Attr";
+    param_names(pos_b) = "Bytes";
+    param_names(pos_c) = "Class";
+    param_names(pos_e) = "Elements";
+    param_names(pos_n) = "Name";
+    param_names(pos_s) = "Size";
+    param_names(pos_t) = "Type";
+
+    for (size_t i = 0; i < param_string.length (); i++)
+      param_length(i) = param_names(i).length ();
+
+    // The attribute column needs size 5.
+    param_length(pos_a) = 5;
+
+    // Calculating necessary spacing for name column,
+    // bytes column, elements column and class column
+
+    for (const auto& syminfo : m_lst)
+      {
+        std::stringstream ss1, ss2;
+        std::string str;
+
+        str = syminfo.name ();
+        param_length(pos_n) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_n)))
+                               ? str.length () : param_length(pos_n));
+
+        octave_value val = syminfo.value ();
+
+        str = val.type_name ();
+        param_length(pos_t) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_t)))
+                               ? str.length () : param_length(pos_t));
+
+        elements1 = val.numel ();
+        ss1 << elements1;
+        str = ss1.str ();
+        param_length(pos_e) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_e)))
+                               ? str.length () : param_length(pos_e));
+
+        bytes1 = val.byte_size ();
+        ss2 << bytes1;
+        str = ss2.str ();
+        param_length(pos_b) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_b)))
+                               ? str.length () : param_length (pos_b));
+      }
+
+    idx = 0;
+    while (static_cast<size_t> (idx) < format_len)
+      {
+        whos_parameter param;
+        param.command = '\0';
+
+        if (format[idx] == '%')
+          {
+            bool error_encountered = false;
+            param.modifier = 'r';
+            param.parameter_length = 0;
+
+            int a = 0;
+            int b = -1;
+            int balance = 1;
+            unsigned int items;
+            size_t pos;
+            std::string cmd;
+
+            // Parse one command from format
+            cmd = format.substr (idx, format.length ());
+            pos = cmd.find (';');
+            if (pos == std::string::npos)
+              error ("parameter without ; in format");
+
+            cmd = cmd.substr (0, pos+1);
+
+            idx += cmd.length ();
+
+            // FIXME: use iostream functions instead of sscanf!
+
+            if (cmd.find_first_of ("crl") != 1)
+              items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
+                              &garbage, &param.command, &a, &b, &balance);
+            else
+              items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
+                              &garbage, &param.modifier, &param.command,
+                              &a, &b, &balance) - 1;
+
+            if (items < 2)
+              error ("whos_line_format: found parameter structure without command");
+
+            // Exception case of bare class command 'c' without modifier 'l/r'
+            if (param.modifier == 'c'
+                && param_string.find (param.command) == std::string::npos)
+              {
+                param.modifier = 'r';
+                param.command = 'c';
+              }
+
+            // Insert data into parameter
+            param.first_parameter_length = 0;
+            pos = param_string.find (param.command);
+            if (pos == std::string::npos)
+              error ("whos_line_format: '%c' is not a command", param.command);
+
+            param.parameter_length = param_length(pos);
+            param.text = param_names(pos);
+            param.line.assign (param_names(pos).length (), '=');
+
+            param.parameter_length = (a > param.parameter_length
+                                      ? a : param.parameter_length);
+            if (param.command == 's' && param.modifier == 'c' && b > 0)
+              param.first_parameter_length = b;
+
+            if (param.command == 's')
+              {
+                // Have to calculate space needed for printing
+                // matrix dimensions Space needed for Size column is
+                // hard to determine in prior, because it depends on
+                // dimensions to be shown.  That is why it is
+                // recalculated for each Size-command int first,
+                // rest = 0, total;
+                int rest = 0;
+                int first = param.first_parameter_length;
+                int total = param.parameter_length;
+
+                for (const auto& syminfo : m_lst)
+                  {
+                    octave_value val = syminfo.value ();
+                    std::string dims_str = val.get_dims_str ();
+                    int first1 = dims_str.find ('x');
+                    int total1 = dims_str.length ();
+                    int rest1 = total1 - first1;
+                    rest = (rest1 > rest ? rest1 : rest);
+                    first = (first1 > first ? first1 : first);
+                    total = (total1 > total ? total1 : total);
+                  }
+
+                if (param.modifier == 'c')
+                  {
+                    if (first < balance)
+                      first += balance - first;
+                    if (rest + balance < param.parameter_length)
+                      rest += param.parameter_length - rest - balance;
+
+                    param.parameter_length = first + rest;
+                    param.first_parameter_length = first;
+                    param.balance = balance;
+                  }
+                else
+                  {
+                    param.parameter_length = total;
+                    param.first_parameter_length = 0;
+                  }
+              }
+            else if (param.modifier == 'c')
+              error ("whos_line_format: modifier 'c' not available for command '%c'",
+                     param.command);
+
+            // What happens if format contains negative numbers
+            // at param_length positions?
+            param.balance = (b < 0 ? 0 : param.balance);
+            param.first_parameter_length = (b < 0
+                                            ? 0
+                                            : param.first_parameter_length);
+            param.parameter_length = (a < 0
+                                      ? 0
+                                      : (param.parameter_length
+                                         < param_length(pos_s)
+                                         ? param_length(pos_s)
+                                         : param.parameter_length));
+
+            // Parameter will not be pushed into parameter list if ...
+            if (! error_encountered)
+              params.push_back (param);
+          }
+        else
+          {
+            // Text string, to be printed as it is ...
+            std::string text;
+            size_t pos;
+            text = format.substr (idx, format.length ());
+            pos = text.find ('%');
+            if (pos != std::string::npos)
+              text = text.substr (0, pos);
+
+            // Push parameter into list ...
+            idx += text.length ();
+            param.text=text;
+            param.line.assign (text.length (), ' ');
+            params.push_back (param);
+          }
+      }
+
+    return params;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/syminfo.h	Thu Nov 15 22:45:04 2018 -0500
@@ -0,0 +1,129 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (octave_syminfo_h)
+#define octave_syminfo_h 1
+
+#include "octave-config.h"
+
+#include <string>
+#include <iosfwd>
+
+#include "ov.h"
+
+class octave_map;
+
+namespace octave
+{
+  struct whos_parameter
+  {
+    char command;
+    char modifier;
+    int parameter_length;
+    int first_parameter_length;
+    int balance;
+    std::string text;
+    std::string line;
+  };
+
+  class symbol_info
+  {
+  public:
+
+    symbol_info (const std::string& name, const octave_value& value,
+                 bool is_automatic, bool is_complex, bool is_formal,
+                 bool is_global, bool is_persistent)
+      : m_name (name), m_value (value), m_is_automatic (is_automatic),
+        m_is_complex (is_complex), m_is_formal (is_formal),
+        m_is_global (is_global), m_is_persistent (is_persistent)
+    { }
+
+    std::string name (void) const { return m_name; }
+
+    octave_value value (void) const { return m_value; }
+
+    bool is_automatic (void) const { return m_is_automatic; }
+
+    bool is_complex (void) const { return m_is_complex; }
+
+    bool is_formal (void) const { return m_is_formal; }
+
+    bool is_global (void) const { return m_is_global; }
+
+    bool is_persistent (void) const { return m_is_persistent; }
+
+    void display_line (std::ostream& os,
+                       const std::list<whos_parameter>& params) const;
+  private:
+
+    std::string m_name;
+    octave_value m_value;
+    bool m_is_automatic;
+    bool m_is_complex;
+    bool m_is_formal;
+    bool m_is_global;
+    bool m_is_persistent;
+  };
+
+  class symbol_info_list
+  {
+  public:
+
+    symbol_info_list (void) = default;
+
+    symbol_info_list (const symbol_info_list&) = default;
+
+    symbol_info_list& operator = (const symbol_info_list&) = default;
+
+    ~symbol_info_list (void) = default;
+
+    void append (const symbol_info& syminf)
+    {
+      m_lst.push_back (syminf);
+    }
+
+    size_t size (void) const { return m_lst.size (); }
+
+    bool empty (void) const { return m_lst.empty (); }
+
+    octave_map map_value (const std::string& caller_function_name,
+                          int nesting_level) const;
+
+    // Print a line of information for a given symbol.
+    void print_descriptor (std::ostream& os,
+                           const std::list<whos_parameter> params) const;
+
+    void display (std::ostream& os, const std::string& format);
+
+    // Parse FORMAT, and return a parameter list,
+    // containing all information needed to print the given
+    // attributes of the symbols.
+    std::list<whos_parameter>
+    parse_whos_line_format (const std::string& format);
+
+  private:
+
+    std::list<symbol_info> m_lst;
+  };
+}
+
+#endif
--- a/libinterp/corefcn/variables.cc	Thu Nov 15 15:05:36 2018 -0500
+++ b/libinterp/corefcn/variables.cc	Thu Nov 15 22:45:04 2018 -0500
@@ -60,6 +60,7 @@
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
+#include "syminfo.h"
 #include "symtab.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -828,610 +829,12 @@
   return retval;
 }
 
-struct
-whos_parameter
-{
-  char command;
-  char modifier;
-  int parameter_length;
-  int first_parameter_length;
-  int balance;
-  std::string text;
-  std::string line;
-};
-
-// Print a line of information for a given symbol.
-
-static void
-print_descriptor (std::ostream& os, std::list<whos_parameter> params)
-{
-  std::ostringstream param_buf;
-
-  octave::preserve_stream_state stream_state (os);
-
-  for (const auto& param : params)
-    {
-      if (param.command != '\0')
-        {
-          // Do the actual printing
-          switch (param.modifier)
-            {
-            case 'l':
-              os << std::setiosflags (std::ios::left)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::left)
-                        << std::setw (param.parameter_length);
-              break;
-
-            case 'r':
-              os << std::setiosflags (std::ios::right)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::right)
-                        << std::setw (param.parameter_length);
-              break;
-
-            case 'c':
-              if (param.command != 's')
-                {
-                  os << std::setiosflags (std::ios::left)
-                     << std::setw (param.parameter_length);
-                  param_buf << std::setiosflags (std::ios::left)
-                            << std::setw (param.parameter_length);
-                }
-              break;
-
-            default:
-              os << std::setiosflags (std::ios::left)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::left)
-                        << std::setw (param.parameter_length);
-            }
-
-          if (param.command == 's' && param.modifier == 'c')
-            {
-              if (param.modifier == 'c')
-                {
-                  int a = param.first_parameter_length - param.balance;
-                  a = (a < 0 ? 0 : a);
-                  int b = param.parameter_length - a - param.text.length ();
-                  b = (b < 0 ? 0 : b);
-                  os << std::setiosflags (std::ios::left) << std::setw (a)
-                     << "" << std::resetiosflags (std::ios::left) << param.text
-                     << std::setiosflags (std::ios::left)
-                     << std::setw (b) << ""
-                     << std::resetiosflags (std::ios::left);
-                  param_buf << std::setiosflags (std::ios::left)
-                            << std::setw (a)
-                            << "" << std::resetiosflags (std::ios::left)
-                            << param.line
-                            << std::setiosflags (std::ios::left)
-                            << std::setw (b) << ""
-                            << std::resetiosflags (std::ios::left);
-                }
-            }
-          else
-            {
-              os << param.text;
-              param_buf << param.line;
-            }
-          os << std::resetiosflags (std::ios::left)
-             << std::resetiosflags (std::ios::right);
-          param_buf << std::resetiosflags (std::ios::left)
-                    << std::resetiosflags (std::ios::right);
-        }
-      else
-        {
-          os << param.text;
-          param_buf << param.line;
-        }
-    }
-
-  os << param_buf.str ();
-}
-
-class symbol_info
-{
-public:
-
-  symbol_info (const std::string& name, const octave_value& value,
-               bool is_automatic, bool is_complex, bool is_formal,
-               bool is_global, bool is_persistent)
-    : m_name (name), m_value (value), m_is_automatic (is_automatic),
-      m_is_complex (is_complex), m_is_formal (is_formal),
-      m_is_global (is_global), m_is_persistent (is_persistent)
-  { }
-
-  std::string name (void) const { return m_name; }
-
-  octave_value value (void) const { return m_value; }
-
-  bool is_automatic (void) const { return m_is_automatic; }
-
-  bool is_complex (void) const { return m_is_complex; }
-
-  bool is_formal (void) const { return m_is_formal; }
-
-  bool is_global (void) const { return m_is_global; }
-
-  bool is_persistent (void) const { return m_is_persistent; }
-
-  void display_line (std::ostream& os,
-                     const std::list<whos_parameter>& params) const
-  {
-    std::string dims_str = m_value.get_dims_str ();
-
-    auto i = params.begin ();
-
-    octave::preserve_stream_state stream_state (os);
-
-    while (i != params.end ())
-      {
-        whos_parameter param = *i;
-
-        if (param.command != '\0')
-          {
-            // Do the actual printing.
-
-            switch (param.modifier)
-              {
-              case 'l':
-                os << std::setiosflags (std::ios::left)
-                   << std::setw (param.parameter_length);
-                break;
-
-              case 'r':
-                os << std::setiosflags (std::ios::right)
-                   << std::setw (param.parameter_length);
-                break;
-
-              case 'c':
-                if (param.command == 's')
-                  {
-                    int front = param.first_parameter_length
-                      - dims_str.find ('x');
-                    int back = param.parameter_length
-                      - dims_str.length ()
-                      - front;
-                    front = (front > 0) ? front : 0;
-                    back = (back > 0) ? back : 0;
-
-                    os << std::setiosflags (std::ios::left)
-                       << std::setw (front)
-                       << ""
-                       << std::resetiosflags (std::ios::left)
-                       << dims_str
-                       << std::setiosflags (std::ios::left)
-                       << std::setw (back)
-                       << ""
-                       << std::resetiosflags (std::ios::left);
-                  }
-                else
-                  {
-                    os << std::setiosflags (std::ios::left)
-                       << std::setw (param.parameter_length);
-                  }
-                break;
-
-              default:
-                error ("whos_line_format: modifier '%c' unknown",
-                       param.modifier);
-
-                os << std::setiosflags (std::ios::right)
-                   << std::setw (param.parameter_length);
-              }
-
-            switch (param.command)
-              {
-              case 'a':
-                {
-                  char tmp[6];
-
-                  tmp[0] = (m_is_automatic ? 'a' : ' ');
-                  tmp[1] = (m_is_complex ? 'c' : ' ');
-                  tmp[2] = (m_is_formal ? 'f' : ' ');
-                  tmp[3] = (m_is_global ? 'g' : ' ');
-                  tmp[4] = (m_is_persistent ? 'p' : ' ');
-                  tmp[5] = 0;
-
-                  os << tmp;
-                }
-                break;
-
-              case 'b':
-                os << m_value.byte_size ();
-                break;
-
-              case 'c':
-                os << m_value.class_name ();
-                break;
-
-              case 'e':
-                os << m_value.numel ();
-                break;
-
-              case 'n':
-                os << m_name;
-                break;
-
-              case 's':
-                if (param.modifier != 'c')
-                  os << dims_str;
-                break;
-
-              case 't':
-                os << m_value.type_name ();
-                break;
-
-              default:
-                error ("whos_line_format: command '%c' unknown",
-                       param.command);
-              }
-
-            os << std::resetiosflags (std::ios::left)
-               << std::resetiosflags (std::ios::right);
-            i++;
-          }
-        else
-          {
-            os << param.text;
-            i++;
-          }
-      }
-  }
-
-private:
-
-  std::string m_name;
-  octave_value m_value;
-  bool m_is_automatic;
-  bool m_is_complex;
-  bool m_is_formal;
-  bool m_is_global;
-  bool m_is_persistent;
-};
-
-class
-symbol_info_list
-{
-public:
-
-  symbol_info_list (void) = default;
-
-  symbol_info_list (const symbol_info_list&) = default;
-
-  symbol_info_list& operator = (const symbol_info_list&) = default;
-
-  ~symbol_info_list (void) = default;
-
-  void append (const symbol_info& syminf)
-  {
-    m_lst.push_back (syminf);
-  }
-
-  size_t size (void) const { return m_lst.size (); }
-
-  bool empty (void) const { return m_lst.empty (); }
-
-  octave_map
-  map_value (const std::string& caller_function_name, int nesting_level) const
-  {
-    size_t len = m_lst.size ();
-
-    Cell name_info (len, 1);
-    Cell size_info (len, 1);
-    Cell bytes_info (len, 1);
-    Cell class_info (len, 1);
-    Cell global_info (len, 1);
-    Cell sparse_info (len, 1);
-    Cell complex_info (len, 1);
-    Cell nesting_info (len, 1);
-    Cell persistent_info (len, 1);
-
-    size_t j = 0;
-
-    for (const auto& syminfo : m_lst)
-      {
-        octave_scalar_map ni;
-
-        ni.assign ("function", caller_function_name);
-        ni.assign ("level", nesting_level);
-
-        name_info(j) = syminfo.name ();
-        global_info(j) = syminfo.is_global ();
-        persistent_info(j) = syminfo.is_persistent ();
-
-        octave_value val = syminfo.value ();
-
-        size_info(j) = val.size ();
-        bytes_info(j) = val.byte_size ();
-        class_info(j) = val.class_name ();
-        sparse_info(j) = val.issparse ();
-        complex_info(j) = val.iscomplex ();
-        nesting_info(j) = ni;
-
-        j++;
-      }
-
-    octave_map info;
-
-    info.assign ("name", name_info);
-    info.assign ("size", size_info);
-    info.assign ("bytes", bytes_info);
-    info.assign ("class", class_info);
-    info.assign ("global", global_info);
-    info.assign ("sparse", sparse_info);
-    info.assign ("complex", complex_info);
-    info.assign ("nesting", nesting_info);
-    info.assign ("persistent", persistent_info);
-
-    return info;
-  }
-
-  void display (std::ostream& os, const std::string& format)
-  {
-    if (! m_lst.empty ())
-      {
-        size_t bytes = 0;
-        size_t elements = 0;
-
-        std::list<whos_parameter> params = parse_whos_line_format (format);
-
-        print_descriptor (os, params);
-
-        octave_stdout << "\n";
-
-        for (const auto& syminfo : m_lst)
-          {
-            syminfo.display_line (os, params);
-
-            octave_value val = syminfo.value ();
-
-            elements += val.numel ();
-            bytes += val.byte_size ();
-          }
-
-        os << "\nTotal is " << elements
-           << (elements == 1 ? " element" : " elements")
-           << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
-           << "\n";
-      }
-  }
-
-  // Parse FORMAT, and return a parameter list,
-  // containing all information needed to print the given
-  // attributes of the symbols.
-  std::list<whos_parameter> parse_whos_line_format (const std::string& format)
-  {
-    int idx;
-    size_t format_len = format.length ();
-    char garbage;
-    std::list<whos_parameter> params;
-
-    size_t bytes1;
-    int elements1;
-
-    std::string param_string = "abcenst";
-    Array<int> param_length (dim_vector (param_string.length (), 1));
-    Array<std::string> param_names (dim_vector (param_string.length (), 1));
-    size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
-
-    pos_a = param_string.find ('a'); // Attributes
-    pos_b = param_string.find ('b'); // Bytes
-    pos_c = param_string.find ('c'); // Class
-    pos_e = param_string.find ('e'); // Elements
-    pos_n = param_string.find ('n'); // Name
-    pos_s = param_string.find ('s'); // Size
-    pos_t = param_string.find ('t'); // Type
-
-    param_names(pos_a) = "Attr";
-    param_names(pos_b) = "Bytes";
-    param_names(pos_c) = "Class";
-    param_names(pos_e) = "Elements";
-    param_names(pos_n) = "Name";
-    param_names(pos_s) = "Size";
-    param_names(pos_t) = "Type";
-
-    for (size_t i = 0; i < param_string.length (); i++)
-      param_length(i) = param_names(i).length ();
-
-    // The attribute column needs size 5.
-    param_length(pos_a) = 5;
-
-    // Calculating necessary spacing for name column,
-    // bytes column, elements column and class column
-
-    for (const auto& syminfo : m_lst)
-      {
-        std::stringstream ss1, ss2;
-        std::string str;
-
-        str = syminfo.name ();
-        param_length(pos_n) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_n)))
-                               ? str.length () : param_length(pos_n));
-
-        octave_value val = syminfo.value ();
-
-        str = val.type_name ();
-        param_length(pos_t) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_t)))
-                               ? str.length () : param_length(pos_t));
-
-        elements1 = val.numel ();
-        ss1 << elements1;
-        str = ss1.str ();
-        param_length(pos_e) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_e)))
-                               ? str.length () : param_length(pos_e));
-
-        bytes1 = val.byte_size ();
-        ss2 << bytes1;
-        str = ss2.str ();
-        param_length(pos_b) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_b)))
-                               ? str.length () : param_length (pos_b));
-      }
-
-    idx = 0;
-    while (static_cast<size_t> (idx) < format_len)
-      {
-        whos_parameter param;
-        param.command = '\0';
-
-        if (format[idx] == '%')
-          {
-            bool error_encountered = false;
-            param.modifier = 'r';
-            param.parameter_length = 0;
-
-            int a = 0;
-            int b = -1;
-            int balance = 1;
-            unsigned int items;
-            size_t pos;
-            std::string cmd;
-
-            // Parse one command from format
-            cmd = format.substr (idx, format.length ());
-            pos = cmd.find (';');
-            if (pos == std::string::npos)
-              error ("parameter without ; in format");
-
-            cmd = cmd.substr (0, pos+1);
-
-            idx += cmd.length ();
-
-            // FIXME: use iostream functions instead of sscanf!
-
-            if (cmd.find_first_of ("crl") != 1)
-              items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
-                              &garbage, &param.command, &a, &b, &balance);
-            else
-              items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
-                              &garbage, &param.modifier, &param.command,
-                              &a, &b, &balance) - 1;
-
-            if (items < 2)
-              error ("whos_line_format: found parameter structure without command");
-
-            // Exception case of bare class command 'c' without modifier 'l/r'
-            if (param.modifier == 'c'
-                && param_string.find (param.command) == std::string::npos)
-              {
-                param.modifier = 'r';
-                param.command = 'c';
-              }
-
-            // Insert data into parameter
-            param.first_parameter_length = 0;
-            pos = param_string.find (param.command);
-            if (pos == std::string::npos)
-              error ("whos_line_format: '%c' is not a command", param.command);
-
-            param.parameter_length = param_length(pos);
-            param.text = param_names(pos);
-            param.line.assign (param_names(pos).length (), '=');
-
-            param.parameter_length = (a > param.parameter_length
-                                      ? a : param.parameter_length);
-            if (param.command == 's' && param.modifier == 'c' && b > 0)
-              param.first_parameter_length = b;
-
-            if (param.command == 's')
-              {
-                // Have to calculate space needed for printing
-                // matrix dimensions Space needed for Size column is
-                // hard to determine in prior, because it depends on
-                // dimensions to be shown.  That is why it is
-                // recalculated for each Size-command int first,
-                // rest = 0, total;
-                int rest = 0;
-                int first = param.first_parameter_length;
-                int total = param.parameter_length;
-
-                for (const auto& syminfo : m_lst)
-                  {
-                    octave_value val = syminfo.value ();
-                    std::string dims_str = val.get_dims_str ();
-                    int first1 = dims_str.find ('x');
-                    int total1 = dims_str.length ();
-                    int rest1 = total1 - first1;
-                    rest = (rest1 > rest ? rest1 : rest);
-                    first = (first1 > first ? first1 : first);
-                    total = (total1 > total ? total1 : total);
-                  }
-
-                if (param.modifier == 'c')
-                  {
-                    if (first < balance)
-                      first += balance - first;
-                    if (rest + balance < param.parameter_length)
-                      rest += param.parameter_length - rest - balance;
-
-                    param.parameter_length = first + rest;
-                    param.first_parameter_length = first;
-                    param.balance = balance;
-                  }
-                else
-                  {
-                    param.parameter_length = total;
-                    param.first_parameter_length = 0;
-                  }
-              }
-            else if (param.modifier == 'c')
-              error ("whos_line_format: modifier 'c' not available for command '%c'",
-                     param.command);
-
-            // What happens if format contains negative numbers
-            // at param_length positions?
-            param.balance = (b < 0 ? 0 : param.balance);
-            param.first_parameter_length = (b < 0
-                                            ? 0
-                                            : param.first_parameter_length);
-            param.parameter_length = (a < 0
-                                      ? 0
-                                      : (param.parameter_length
-                                         < param_length(pos_s)
-                                         ? param_length(pos_s)
-                                         : param.parameter_length));
-
-            // Parameter will not be pushed into parameter list if ...
-            if (! error_encountered)
-              params.push_back (param);
-          }
-        else
-          {
-            // Text string, to be printed as it is ...
-            std::string text;
-            size_t pos;
-            text = format.substr (idx, format.length ());
-            pos = text.find ('%');
-            if (pos != std::string::npos)
-              text = text.substr (0, pos);
-
-            // Push parameter into list ...
-            idx += text.length ();
-            param.text=text;
-            param.line.assign (text.length (), ' ');
-            params.push_back (param);
-          }
-      }
-
-    return params;
-  }
-
-private:
-
-  std::list<symbol_info> m_lst;
-
-};
-
 static octave_value
 do_who_two (octave::interpreter& interp, const string_vector& pats,
             bool global_only, bool have_regexp, bool return_list,
             bool verbose = false, std::string msg = "")
 {
-  symbol_info_list symbol_stats;
+  octave::symbol_info_list symbol_stats;
   std::list<std::string> symbol_names;
 
   octave::tree_evaluator& tw = interp.get_evaluator ();
@@ -1464,9 +867,10 @@
             {
               if (verbose)
                 {
-                  symbol_info syminf (sr.name (), value, sr.is_automatic (),
-                                      value.iscomplex (), sr.is_formal (),
-                                      sr.is_global (), sr.is_persistent ());
+                  octave::symbol_info
+                    syminf (sr.name (), value, sr.is_automatic (),
+                            value.iscomplex (), sr.is_formal (),
+                            sr.is_global (), sr.is_persistent ());
 
                   symbol_stats.append (syminf);
                 }