changeset 4913:c8368716bab3

[project @ 2004-07-23 16:00:48 by jwe]
author jwe
date Fri, 23 Jul 2004 16:00:49 +0000
parents 048db020498c
children 1c0442da75fd
files doc/interpreter/var.txi src/ChangeLog src/symtab.cc src/symtab.h
diffstat 4 files changed, 767 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/var.txi	Thu Jul 22 20:45:59 2004 +0000
+++ b/doc/interpreter/var.txi	Fri Jul 23 16:00:49 2004 +0000
@@ -203,6 +203,10 @@
 
 @DOCSTRING(who)
 
+@DOCSTRING(whos)
+
+@DOCSTRING(whos_line_format)
+
 @DOCSTRING(exist)
 
 @DOCSTRING(document)
--- a/src/ChangeLog	Thu Jul 22 20:45:59 2004 +0000
+++ b/src/ChangeLog	Fri Jul 23 16:00:49 2004 +0000
@@ -1,3 +1,27 @@
+2004-07-23  Oyvind Kristiansen  <oyvinkri@stud.ntnu.no>
+
+	* symtab.cc (symbol_record::subsymbols_list): New method.
+	(symbol_record::maybe_list): Call to subsymbols_list and merge
+	result with the original list of symbols.
+
+	* symtab.cc (symbol_record::make_dimensions_string): New method.
+	(symbol_record::print_symbol_info_line): Print N-d info.  Output
+	for long format now under control of format string.
+	(symbol_table::maybe_list): Headers to whos listing updated.
+	Also print footer info.
+	(symbol_table::print_descriptor): Method printing the 
+	header of whos listings.
+	(symbol_table::parse_whos_line_format): New method.
+	(whos_line_format, Vwhos_line_format): New built-in variables.
+	(symbols_of_symtab): DEFVAR them.
+	(symbol_record::nelem, symbol_record::symbol_def::nelem,
+	symbol_record::byte_size, symbol_record::symbol_def::byte_size):
+	New methods.
+	(symbol_record::dimensions_string_req_first_space): New	method.
+	(symbol_record::dimensions_string_req_total_space): New	method.
+	* symtab.h (whos_parameter): New struct.  Container for one
+	parameter in whos_line_format.
+
 2004-07-22  Paul Kienzle  <pkienzle@users.sf.net>
 
 	* DLD-FUNCTIONS/dassl.cc (Fdassl): Fix doc string.
--- a/src/symtab.cc	Thu Jul 22 20:45:59 2004 +0000
+++ b/src/symtab.cc	Fri Jul 23 16:00:49 2004 +0000
@@ -47,6 +47,12 @@
 #include "utils.h"
 #include "variables.h"
 
+#include "gripes.h"
+#include "lo-mappers.h"
+
+#include "parse.h"
+#include <stdio.h>
+
 unsigned long int symbol_table::symtab_count = 0;
 
 // Should variables be allowed to hide functions of the same name?  A
@@ -57,6 +63,9 @@
 // Nonzero means we print debugging info about symbol table lookups.
 static int Vdebug_symtab_lookups;
 
+// Defines layout for the whos/who -long command
+std::string Vwhos_line_format;
+
 octave_allocator
 symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def));
 
@@ -410,33 +419,238 @@
     }
 }
 
-void
-symbol_record::print_symbol_info_line (std::ostream& os) const
+int
+symbol_record::dimensions_string_req_first_space (int print_dims) const 
 {
-  os << (is_read_only () ? " r-" : " rw")
-     << (is_static () || is_eternal () ? "-" : "d")
-     << "  "
-     << std::setiosflags (std::ios::left) << std::setw (24)
-     << type_name () . c_str ();
+  // This method calculates how much space needs to be reserved for the
+  // first part of the dimensions string.
+  // Example: mat is a 12x3 matrix
+  //                   ^^  => 2 columns
+  long dim = 0;
+  int first_param_space = 0;
+
+  // Calculating dimensions
+  std::string dim_str = "";
+  std::stringstream ss;
+  dim_vector dimensions;
+
+  if (is_variable ())
+    {
+      if (is_matrix_type ()) 
+        {
+	  dimensions = dims ();
+	  dim = dimensions.length ();
+	}
+    }
+
+  first_param_space = (first_param_space >= 1 ? first_param_space : 1);
+
+  // Preparing dimension string
+  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
+    {
+      // Dimensions string must be printed like this: 2x3x4x2
+      if (dim == 0 || dim == 1)
+	first_param_space = 1; // First parameter is 1
+      else
+        {
+	  ss << dimensions (0);
+	  
+	  dim_str = ss.str ();
+	  first_param_space = dim_str.length ();
+	}
+    }
+  else 
+    {
+      // Printing dimension string as: a-D
+      ss << dim;
 
-  os << std::resetiosflags (std::ios::left);
+      dim_str = ss.str ();
+      first_param_space = dim_str.length ();
+    }
+
+  return first_param_space;
+}
+
+int
+symbol_record::dimensions_string_req_total_space (int print_dims) const
+{
+  // This method calculates how much space needs to be reserved for the
+  // the dimensions string.
+  // Example: mat is a 12x3 matrix
+  //                   ^^^^ => 4 columns
+
+  std::string dim_str = "";
+  std::stringstream ss;
+
+  ss << make_dimensions_string (print_dims);
+  dim_str = ss.str ();
+
+  return dim_str.length ();
+}
 
-  int nr = rows ();
-  int nc = columns ();
+std::string
+symbol_record::make_dimensions_string (int print_dims) const 
+{
+  // This method makes the dimensions-string, which is a string that tells
+  // how large a object is, dimensionally.
+  // Example: mat is a 2x3 matrix
+  //                   ^^^ 
+
+  long dim = 0;
+
+  // Calculating dimensions
+  std::string dim_str = "";
+  std::stringstream ss;
+  dim_vector dimensions;
+
+  if (is_variable ())
+    {
+      if (is_matrix_type ()) 
+        {
+	  dimensions = dims ();
+	  dim = dimensions.length ();
+	}
+    }
 
-  if (nr < 0)
-    os << "      -";
-  else
-    os << std::setiosflags (std::ios::right) << std::setw (7) << nr;
+  // Preparing dimension string
+  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
+    {
+      // Only printing the dimension string as: axbxc...
+      if (dim == 0)
+	ss << "1x1";
+      else
+        {
+	  for (int i = 0; i < dim; i++) 
+	    {
+	      if (i == 0)
+		{
+		  if (dim == 1)
+		    // Looks like this is not going to happen in Octave, but ...
+		    ss << "1x" << dimensions (i);
+		  else
+		    ss << dimensions (i);
+		}
+	      else if (i < dim && dim != 1) 
+		ss << "x" << dimensions (i);
+	    }
+	}
+    }
+  else 
+    {
+      // Printing dimension string as: a-D
+      ss << dim << "-D";
+    }
+
+  dim_str = ss.str ();
+
+  return dim_str;
+}
+
+void
+symbol_record::print_symbol_info_line (std::ostream& os,
+				       std::list<whos_parameter>& params) const
+{
+  // This method prints a line of information on a given symbol
+  std::list<whos_parameter>::iterator i = params.begin ();
+  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 -
+		      dimensions_string_req_first_space (param.dimensions);
+		  int back = param.parameter_length -
+		      dimensions_string_req_total_space (param.dimensions) -
+		      front;
+		  front = (front > 0) ? front : 0;
+		  back = (back > 0) ? back : 0;
 
-  if (nc < 0)
-    os << "      -";
-  else
-    os << std::setiosflags (std::ios::right) << std::setw (7) << nc;
+		  os << std::setiosflags (std::ios::left) 
+		     << std::setw (front)
+		     << "" << std::resetiosflags (std::ios::left)
+		     << make_dimensions_string (param.dimensions)
+		     << 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 'b':
+	      os << byte_size ();
+	      break;
+
+	    case 'e':
+	      os << numel ();
+	      break;
+
+	    case 'n':
+	      os << name ();
+	      break;
 
-  os << std::resetiosflags (std::ios::right);
+	    case 'p':
+	      {
+		std::stringstream ss;
+		std::string str;
+
+		ss << (is_read_only () ? "r-" : "rw")
+		   << (is_static () || is_eternal () ? "-" : "d");
+		str = ss.str ();
+
+		os << str;
+	      }
+	      break;
+
+	    case 's':
+	      if (param.modifier != 'c')
+		os << make_dimensions_string (param.dimensions);
+	      break;
 
-  os << "  " << name () << "\n";
+	    case 't':
+	      os << 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++;
+	}
+    }
 }
 
 void
@@ -833,6 +1047,69 @@
 }
 
 Array<symbol_record *>
+symbol_table::subsymbol_list (const string_vector& pats,
+			      unsigned int type, unsigned int scope) const
+{
+  int count = 0;
+
+  int n = size ();
+
+  Array<symbol_record *> subsymbols (n);
+  int pats_length = pats.length ();
+
+  if (n == 0)
+    return subsymbols;
+
+  // Look for separators like .({
+  for (int j = 0; j < pats_length; j++)
+    {
+      std::string var_name = pats (j);
+
+      size_t pos = var_name.find_first_of (".({");
+
+      if ((pos != NPOS) && (pos > 0))
+        {
+	  std::string first_name = var_name.substr(0,pos);
+
+	  for (unsigned int i = 0; i < table_size; i++)
+	    {
+	      symbol_record *ptr = table[i].next ();
+
+	      while (ptr)
+	        {
+		  assert (count < n);
+
+		  unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky...
+
+		  unsigned int my_type = ptr->type ();
+
+		  std::string my_name = ptr->name ();
+
+		  if ((type & my_type) && (scope & my_scope) && (first_name == my_name))
+		    {
+		      symbol_record *sym_ptr = new symbol_record ();
+		      octave_value value;
+		      int parse_status;
+	  
+		      value = eval_string (var_name, true, parse_status);
+	  
+		      sym_ptr->define (value);
+		      sym_ptr->rename (var_name);
+		      subsymbols(count++) = sym_ptr;
+		    }
+
+		  ptr = ptr->next ();
+		}
+	    }
+	}
+    }
+
+  subsymbols.resize (count);
+
+  return subsymbols;
+}
+
+Array<symbol_record *>
 symbol_table::symbol_list (const string_vector& pats,
 			   unsigned int type, unsigned int scope) const
 {
@@ -859,8 +1136,7 @@
 
 	  std::string my_name = ptr->name ();
 
-	  if ((type & my_type) && (scope & my_scope)
-	      && matches_patterns (my_name, pats))
+	  if ((type & my_type) && (scope & my_scope) && (matches_patterns (my_name, pats)))
 	    symbols(count++) = ptr;
 
 	  ptr = ptr->next ();
@@ -908,29 +1184,352 @@
   return a_nm.compare (b_nm);
 }
 
+void
+symbol_table::print_descriptor (std::ostream& os,
+				std::list<whos_parameter> params) const
+{
+  // This method prints a line of information on a given symbol
+  std::list<whos_parameter>::iterator i = params.begin ();
+  OSSTREAM param_buf;
+
+  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);
+	      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')
+	    {
+	      int a, b;
+	      
+	      if (param.modifier == 'c')
+	        {
+		  a = param.first_parameter_length - param.balance;
+		  a = (a < 0 ? 0 : a);
+		  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);
+	  i++;
+	}
+      else
+	{
+	  os << param.text;
+	  param_buf << param.line;
+	  i++;
+	}
+    }
+
+  param_buf << OSSTREAM_ENDS;
+  os << OSSTREAM_C_STR (param_buf);
+  OSSTREAM_FREEZE (param_buf);
+}
+
+std::list<whos_parameter>
+symbol_table::parse_whos_line_format (Array<symbol_record *>& symbols) const
+{
+  // This method parses the string whos_line_format, and returns
+  // a parameter list, containing all information needed to print
+  // the given attributtes of the symbols
+  int idx;
+  size_t format_len = Vwhos_line_format.length ();
+  char garbage;
+  std::list<whos_parameter> params;
+
+  size_t bytes1;
+  int elements1;
+
+  int len = symbols.length (), i;
+
+  std::string param_string = "benpst";
+  Array<int> param_length(param_string.length ());
+  Array<std::string> param_names(param_string.length ());
+  size_t pos_b, pos_t, pos_e, pos_n, pos_p, pos_s;
+
+  pos_b = param_string.find ('b'); // Bytes
+  pos_t = param_string.find ('t'); // (Type aka) Class
+  pos_e = param_string.find ('e'); // Elements
+  pos_n = param_string.find ('n'); // Name
+  pos_p = param_string.find ('p'); // Protected
+  pos_s = param_string.find ('s'); // Size
+
+  param_names(pos_b) = "Bytes";
+  param_names(pos_t) = "Class";
+  param_names(pos_e) = "Elements";
+  param_names(pos_n) = "Name";
+  param_names(pos_p) = "Prot";
+  param_names(pos_s) = "Size";
+
+  for (i = 0; i < 6; i++)
+    param_length(i) = param_names(i) . length ();
+
+  // Calculating necessary spacing for name column,
+  // bytes column, elements column and class column
+  for (i = 0; i < static_cast<int> (len); i++)
+    {
+      std::stringstream ss1, ss2;
+      std::string str;
+
+      str = symbols(i)->name ();
+      param_length(pos_n) = ((str.length () > static_cast<size_t> (param_length(pos_n))) ?
+			     str.length () : param_length(pos_n));
+
+      str = symbols(i)->type_name ();
+      param_length(pos_t) = ((str.length () > static_cast<size_t> (param_length(pos_t))) ?
+			     str.length () : param_length(pos_t));
+
+      elements1 = symbols(i)->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 = symbols(i)->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 (Vwhos_line_format[idx] == '%')
+        {  
+	  bool _error = false;
+	  param.modifier = 'r';
+	  param.parameter_length = 0;
+	  param.dimensions = 8;
+
+	  int a = 0, b = -1, c = 8, balance = 1;
+	  unsigned int items;
+	  size_t pos;
+	  std::string cmd;
+
+	  // Parse one command from whos_line_format
+	  cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
+	  pos = cmd.find (';');
+	  if (pos != NPOS)
+	    cmd = cmd.substr (0, pos+1);
+	  else
+	    error ("parameter without ; in whos_line_format");
+
+	  idx += cmd.length ();
+	  
+	  if (cmd.find_first_of ("crl") != 1)
+	    items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d:%d;",
+			    &garbage, &param.command, &a, &b, &c, &balance);
+	  else
+	    items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d:%d;",
+			    &garbage, &param.modifier, &param.command, &a, &b, &c, &balance) - 1;
+	  
+	  if (items < 2)
+	    {
+	      error ("whos_line_format: parameter structure without command in whos_line_format");
+	      _error = true;
+	    }
+
+	  // Insert data into parameter
+	  param.first_parameter_length = 0;
+	  pos = param_string.find (param.command);
+	  if (pos != NPOS)
+	    {
+	      param.parameter_length = param_length(pos);
+	      param.text = param_names(pos);
+	      param.line.assign (param_names (pos).length (), '=');
+	    }
+	  else
+	    {
+	      error ("whos_line_format: '%c' is not a command",
+		     param.command);
+	      _error = true;
+	    }
+
+	  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 j, first = 0, rest = 0, total = 0;
+	      param.dimensions = c;
+	      
+	      for (j = 0; j < len; j++)
+	      {
+		int first1 = symbols(j)->dimensions_string_req_first_space (param.dimensions);
+		int total1 = symbols(j)->dimensions_string_req_total_space (param.dimensions);
+		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);
+	      _error = true;
+	    }
+
+	  // What happens if whos_line_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)
+	    params.push_back (param);
+	}
+      else
+        {
+	  // Text string, to be printed as it is ...
+	  std::string text;
+	  size_t pos;
+	  text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
+	  pos = text.find ('%');
+	  if (pos != 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;
+}
+
 int
 symbol_table::maybe_list (const char *header, const string_vector& argv,
 			  std::ostream& os, bool show_verbose,
 			  unsigned type, unsigned scope)
 {
+  // This method prints information for sets of symbols, but only one set
+  // at a time (like, for instance: all variables, og all
+  // built-in-functions)
+
+  // This method invokes print_symbol_info_line to print info on every symbol
+
   int status = 0;
 
   if (show_verbose)
     {
-      Array<symbol_record *> symbols = symbol_list (argv, type, scope);
+      // XXX FIXME XXX Should separate argv to lists with and without dots
+      Array<symbol_record *> _symbols = symbol_list (argv, type, scope);
+      Array<symbol_record *> _subsymbols = subsymbol_list (argv, type, scope);
 
-      int len = symbols.length ();
+      int sym_len = _symbols.length (), subsym_len = _subsymbols.length (), 
+	len = sym_len + subsym_len;
+  
+      Array<symbol_record *> symbols (len);
 
       if (len > 0)
 	{
-	  os << "\n" << header << "\n\n"
-		     << "prot  type                       rows   cols  name\n"
-		     << "====  ====                       ====   ====  ====\n";
+	  int bytes = 0, elements = 0, i;
+	  std::list<whos_parameter> params;
+
+	  // Joining symbolic tables
+	  for (i = 0; i < sym_len; i++)
+	    symbols(i) = _symbols(i);
+
+	  for (i = 0; i < subsym_len; i++)
+	    symbols(i+sym_len) = _subsymbols(i);
+
+	  os << "\n" << header << "\n\n";
 
 	  symbols.qsort (maybe_list_cmp_fcn);
 
-	  for (int i = 0; i < len; i++)
-	    symbols(i)->print_symbol_info_line (os);
+	  params = parse_whos_line_format (symbols);
+
+	  print_descriptor (os, params);
+
+	  os << "\n";
+
+	  for (int j = 0; j < len; j++)
+	    {
+	      symbols(j)->print_symbol_info_line (os, params);
+	      elements += symbols(j)->numel ();
+	      bytes += symbols(j)->byte_size ();
+	    }
+
+	  os << "\nTotal is " << elements 
+	     << " element" << ((elements > 1) ? "s" : "") << " using "
+	     << bytes << " byte" << ((bytes > 1) ? "s" : "") << "\n";
 
 	  status = 1;
 	}
@@ -940,7 +1539,7 @@
       string_vector symbols = name_list (argv, 1, type, scope);
 
       if (! symbols.empty ())
-	{
+	{     
 	  os << "\n" << header << "\n\n";
 
 	  symbols.list_in_columns (os);
@@ -1107,6 +1706,14 @@
   return 0;
 }
 
+static int
+whos_line_format (void)
+{
+  Vwhos_line_format = builtin_string_variable ("whos_line_format");
+
+  return 0;
+}
+
 void
 symbols_of_symtab (void)
 {
@@ -1121,12 +1728,57 @@
   DEFVAR (debug_symtab_lookups, false, debug_symtab_lookups,
     "-*- texinfo -*-\n\
 @defvr debug_symtab_lookups\n\
-If the value of htis variable is nonzero, print debugging info when\n\
+If the value of this variable is nonzero, print debugging info when\n\
 searching for symbols in the symbol tables.\n\
 @end defvr");
+
+  DEFVAR (whos_line_format, "  %p:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lt:-1;\n", whos_line_format,
+    "-*- texinfo -*-\n\
+@defvr {Built-in Variable} whos_line_format\n\
+This string decides in what order attributtes of variables are to be printed.\n\
+The following commands are used:\n\
+@table @code\n\
+@item %b\n\
+Prints number of bytes occupied by variables.\n\
+@item %e\n\
+Prints elements held by variables.\n\
+@item %n\n\
+Prints variable names.\n\
+@item %p\n\
+Prints protection attributtes of variables.\n\
+@item %s\n\
+Prints dimensions of variables.\n\
+@item %t\n\
+Prints type names of variables.\n\
+@end table\n\
+\n\
+Every command may also have a modifier:\n\
+@table @code\n\
+@item l\n\
+Left alignment.\n\
+@item r\n\
+Right alignment (this is the default).\n\
+@item c\n\
+Centered (may only be applied to command %s).\n\
+@end table\n\
+\n\
+A command is composed like this:\n\
+%[modifier]<command>[:size_of_parameter[:center-specific[:print_dims[:balance]]]];\n\
+\n\
+Command and modifier is already explained. Size_of_parameter\n\
+tells how many columns the parameter will need for printing.\n\
+print_dims tells how many dimensions to print. If number of\n\
+dimensions exceeds print_dims, dimensions will be printed like\n\
+x-D.\n\
+center-specific and print_dims may only be applied to command\n\
+%s. A negative value for print_dims will cause Octave to print all\n\
+dimensions whatsoever.\n\
+balance specifies the offset for printing of the dimensions string.\n\
+\n\
+Default format is \"  %p:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lt:-1;\\n\".\n\
+@end defvr\n");
 }
 
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/symtab.h	Thu Jul 22 20:45:59 2004 +0000
+++ b/src/symtab.h	Fri Jul 23 16:00:49 2004 +0000
@@ -45,6 +45,15 @@
 class symbol_record;
 class symbol_table;
 
+struct
+whos_parameter
+{
+  char command, modifier;
+  int parameter_length, first_parameter_length, dimensions, balance;
+  std::string text;
+  std::string line;
+};
+
 // Individual records in a symbol table.
 
 class
@@ -146,6 +155,18 @@
     bool is_eternal (void) const
       { return eternal; }
 
+    bool is_matrix_type (void) const 
+      { return definition.is_matrix_type (); }
+
+    size_t byte_size (void) const
+      { return definition.byte_size (); };
+
+    int numel (void) const
+      { return definition.numel (); };
+
+    dim_vector dims (void) const 
+      { return definition.dims (); }
+
     int rows (void) const { return definition.rows (); }
     int columns (void) const { return definition.columns (); }
 
@@ -325,6 +346,23 @@
   bool is_static (void) const { return tagged_static; }
   void unmark_static (void) { tagged_static = false; }
 
+  bool is_matrix_type (void) const 
+    { return definition->is_matrix_type (); }
+
+  size_t byte_size (void) const
+    { return definition->byte_size (); };
+
+  int numel (void) const
+    { return definition->numel (); };
+
+  dim_vector dims (void) const { return definition->dims (); }
+
+  int dimensions_string_req_first_space (int print_dims) const;
+
+  int dimensions_string_req_total_space (int print_dims) const;
+
+  std::string make_dimensions_string (int print_dims) const;
+
   int rows (void) const { return definition->rows (); }
   int columns (void) const { return definition->columns (); }
 
@@ -351,7 +389,8 @@
 
   void pop_context (void);
 
-  void print_symbol_info_line (std::ostream& os) const;
+  void print_symbol_info_line (std::ostream& os,
+			       std::list<whos_parameter>& params) const;
 
   void print_info (std::ostream& os,
 		   const std::string& prefix = std::string ()) const;
@@ -454,6 +493,11 @@
   int size (void) const;
 
   Array<symbol_record *>
+  subsymbol_list (const string_vector& pats = string_vector (),
+		  unsigned int type = SYMTAB_ALL_TYPES,
+		  unsigned int scope = SYMTAB_ALL_SCOPES) const;
+
+  Array<symbol_record *>
   symbol_list (const string_vector& pats = string_vector (),
 	       unsigned int type = SYMTAB_ALL_TYPES,
 	       unsigned int scope = SYMTAB_ALL_SCOPES) const;
@@ -511,6 +555,13 @@
 
   static unsigned long int symtab_count;
 
+  void
+  print_descriptor (std::ostream& os, 
+		    std::list<whos_parameter> params) const;
+
+  std::list<whos_parameter>
+  parse_whos_line_format (Array<symbol_record *>& symbols) const;
+
   unsigned int hash (const std::string& s);
 
   // No copying!
@@ -520,6 +571,9 @@
   symbol_table& operator = (const symbol_table&);
 };
 
+// Defines layout for the whos/who -long command.
+extern std::string Vwhos_line_format;
+
 #endif
 
 /*