changeset 3013:66a1cede95e7

[project @ 1997-06-02 19:35:05 by jwe]
author jwe
date Mon, 02 Jun 1997 19:41:17 +0000
parents 0ea30e0e86cc
children 38de16594cb4
files src/Makefile.in src/TEMPLATE-INST/Array-sym.cc src/help.cc src/load-save.cc src/oct-stream.cc src/pr-output.cc src/symtab.cc src/symtab.h src/variables.cc
diffstat 9 files changed, 446 insertions(+), 805 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -87,7 +87,7 @@
 	systime.h syswait.h token.h toplev.h unwind-prot.h utils.h \
 	variables.h version.h xdiv.h xpow.h $(OV_INCLUDES) $(PT_INCLUDES)
 
-TI_XSRC := Array-oc.cc Array-os.cc Array-tc.cc Map-fnc.cc \
+TI_XSRC := Array-oc.cc Array-os.cc Array-sym.cc Array-tc.cc Map-fnc.cc \
 	Map-tc.cc SLList-expr.cc SLList-misc.cc SLList-plot.cc \
 	SLList-tc.cc SLList-tm.cc SLStack-i.cc SLStack-pc.cc \
 	SLStack-str.cc SLStack-sym.cc SLStack-tok.cc \
new file mode 100644
--- /dev/null
+++ b/src/TEMPLATE-INST/Array-sym.cc
@@ -0,0 +1,40 @@
+/*
+
+Copyright (C) 1996, 1997 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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// Instantiate Arrays of octave_child objects.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "Array.h"
+#include "Array.cc"
+
+#include "symtab.h"
+
+template class Array<symbol_record *>;
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/help.cc
+++ b/src/help.cc
@@ -483,7 +483,7 @@
   do \
     { \
       int count; \
-      string_vector names = global_sym_tab->list (count, 0, 0, 1, type); \
+      string_vector names = global_sym_tab->name_list (count, 0, 0, 1, type); \
       display_symtab_names (octave_stdout, names, count, msg); \
     } \
   while (0)
--- a/src/load-save.cc
+++ b/src/load-save.cc
@@ -30,6 +30,7 @@
 
 #include <string>
 
+#include <iomanip.h>
 #include <iostream.h>
 #include <fstream.h>
 #include <strstream.h>
@@ -1355,17 +1356,18 @@
 
 // Return nonzero if NAME matches one of the given globbing PATTERNS.
 
-static int
+static bool
 matches_patterns (const string_vector& patterns, int pat_idx,
 		  int num_pat, const string& name)
 {
   for (int i = pat_idx; i < num_pat; i++)
     {
       glob_match pattern (patterns[i]);
+
       if (pattern.match (name))
-	return 1;
+	return true;
     }
-  return 0;
+  return false;
 }
 
 static int
@@ -1533,11 +1535,13 @@
 			      << "type               rows   cols   name\n"
 			      << "====               ====   ====   ====\n";
 
-			  string type = tc.type_name ();
-			  output_buf.form ("%-16s", type.c_str ());
-			  output_buf.form ("%7d", tc.rows ());
-			  output_buf.form ("%7d", tc.columns ());
-			  output_buf << "   ";
+			  output_buf
+			    << setiosflags (ios::left)
+			    << setw (16) << tc.type_name () . c_str ()
+			    << setiosflags (ios::right)
+			    << setw (7) << tc.rows ()
+			    << setw (7) << tc.columns ()
+			    << "   ";
 			}
 		      output_buf << name << "\n";
 		    }
--- a/src/oct-stream.cc
+++ b/src/oct-stream.cc
@@ -2639,8 +2639,13 @@
 
 	  string name = os->name ();
 
-	  buf.form ("  %4d     %-3s  %-9s  %s\n",
-		    i, mode.c_str (), arch.c_str (), name.c_str ());
+	  buf << "  "
+	      << setiosflags (ios::right)
+	      << setw (4) << i << "     "
+	      << setiosflags (ios::left)
+	      << setw (3) << mode.c_str () << "  "
+	      << setw (9) << arch.c_str () << "  "
+	      << name << "\n";
 	}
     }
 
--- a/src/pr-output.cc
+++ b/src/pr-output.cc
@@ -30,6 +30,7 @@
 
 #include <string>
 
+#include <iomanip.h>
 #include <iostream.h>
 #include <strstream.h>
 
@@ -882,7 +883,7 @@
       stmp[6] = (ctmp & 0x02) ? '1' : '0'; \
       stmp[7] = (ctmp & 0x01) ? '1' : '0'; \
       stmp[8] = '\0'; \
-      os.form ("%s", stmp); \
+      os << stmp; \
     } \
   while (0)
 
@@ -900,7 +901,7 @@
       stmp[6] = (ctmp & 0x40) ? '1' : '0'; \
       stmp[7] = (ctmp & 0x80) ? '1' : '0'; \
       stmp[8] = '\0'; \
-      os.form ("%s", stmp); \
+      os << stmp; \
     } \
   while (0)
 
@@ -929,22 +930,34 @@
 	  // XXX FIXME XXX -- is it correct to swap bytes for VAX
 	  // formats and not for Cray?
 
+	  // XXX FIXME XXX -- will bad things happen if we are
+	  // interrupted before resetting the format flags and fill
+	  // character?
+
 	  oct_mach_info::float_format flt_fmt =
 	    oct_mach_info::native_float_format ();
 
+	  char ofill = os.fill ('0');
+
+	  ios::fmtflags oflags = os.setf (ios::right);
+	  os.setf (ios::hex, ios::basefield);
+
 	  if (hex_format > 1
 	      || flt_fmt == oct_mach_info::ieee_big_endian
 	      || flt_fmt == oct_mach_info::cray
 	      || flt_fmt == oct_mach_info::unknown)
 	    {
 	      for (size_t i = 0; i < sizeof (double); i++)
-		os.form ("%02x", static_cast<int> (tmp.i[i]));
+		os << setw (2) << static_cast<int> (tmp.i[i]);
 	    }
 	  else
 	    {
 	      for (int i = sizeof (double) - 1; i >= 0; i--)
-		os.form ("%02x", static_cast<int> (tmp.i[i]));
+		os << setw (2) << static_cast<int> (tmp.i[i]);
 	    }
+
+	  os.fill (ofill);
+	  os.setf (oflags);	  
 	}
       else if (bit_format)
 	{
@@ -990,14 +1003,14 @@
 	    s = "Inf";
 
 	  if (fw > 0)
-	    os.form ("%*s", fw, s);
+	    os << setw (fw) << s;
 	  else
 	    os << s;
 	}
       else if (xisnan (d))
 	{
 	  if (fw > 0)
-	    os.form ("%*s", fw, "NaN");
+	    os << setw (fw) << "NaN";
 	  else
 	    os << "NaN";
 	}
@@ -1078,7 +1091,7 @@
 
       int num_cols = lim - col;
 
-      os.form ("%*s", extra_indent, "");
+      os << setw (extra_indent) << "";
 
       if (num_cols == 1)
 	os << " Column " << col + 1 << ":\n";
@@ -1226,7 +1239,7 @@
 
 	      for (int i = 0; i < nr; i++)
 		{
-		  os.form ("%*s", extra_indent, "");
+		  os << setw (extra_indent) << "";
 
 		  for (int j = col; j < lim; j++)
 		    {
@@ -1379,7 +1392,7 @@
 
 	      for (int i = 0; i < nr; i++)
 		{
-		  os.form ("%*s", extra_indent, "");
+		  os << setw (extra_indent) << "";
 
 		  for (int j = col; j < lim; j++)
 		    {
@@ -1476,7 +1489,7 @@
 	      pr_col_num_header (os, total_width, max_width, lim, col,
 				 extra_indent);
 
-	      os.form ("%*s", extra_indent, "");
+	      os << setw (extra_indent) << "";
 
 	      for (int i = col; i < lim; i++)
 		{
--- a/src/symtab.cc
+++ b/src/symtab.cc
@@ -28,7 +28,11 @@
 #include <config.h>
 #endif
 
+#include <cassert>
 #include <cctype>
+#include <climits>
+
+#include <iomanip.h>
 
 #include "glob-match.h"
 #include "str-vec.h"
@@ -36,196 +40,18 @@
 #include "error.h"
 #include "oct-lvalue.h"
 #include "ov.h"
+#include "pager.h"
 #include "symtab.h"
 #include "utils.h"
 #include "variables.h"
 
-// Variables and functions.
-
-symbol_def::symbol_def (void)
-{
-  init_state ();
-}
-
-symbol_def::symbol_def (const octave_value& val, unsigned int sym_type)
-{
-  init_state ();
-  definition = val;
-  type = sym_type;
-}
-
-void
-symbol_def::init_state (void)
-{
-  type = UNKNOWN;
-  eternal = 0;
-  read_only = 0;
-
-  next_elem = 0;
-  count = 0;
-}
-
-bool
-symbol_def::is_variable (void) const
-{
-  return (type & USER_VARIABLE || type & BUILTIN_VARIABLE);
-}
-
-bool
-symbol_def::is_function (void) const
-{
-  return (type & USER_FUNCTION || type & BUILTIN_FUNCTION);
-}
-
-bool
-symbol_def::is_user_variable (void) const
-{
-  return (type & USER_VARIABLE);
-}
-
-bool
-symbol_def::is_text_function (void) const
-{
-  return (type & TEXT_FUNCTION);
-}
-
-bool
-symbol_def::is_mapper_function (void) const
-{
-  return (type & MAPPER_FUNCTION);
-}
-
-bool
-symbol_def::is_user_function (void) const
-{
-  return (type & USER_FUNCTION);
-}
-
-bool
-symbol_def::is_builtin_variable (void) const
-{
-  return (type & BUILTIN_VARIABLE);
-}
-
-bool
-symbol_def::is_builtin_function (void) const
-{
-  return (type & BUILTIN_FUNCTION);
-}
-
-// XXX FIXME XXX
-bool
-symbol_def::is_map_element (const string& /* elts */) const
-{
-  return false;
-}
-
-void
-symbol_def::define (const octave_value& val, unsigned int sym_type)
-{
-  definition = val;
-
-  type = sym_type;
-}
-
-void
-symbol_def::protect (void)
-{
-  read_only = 1;
-}
-
-void
-symbol_def::unprotect (void)
-{
-  read_only = 0;
-
-}
-
-void
-symbol_def::make_eternal (void)
-{
-  eternal = 1;
-}
-
-octave_value&
-symbol_def::def (void)
-{
-  return definition;
-}
-
-string
-symbol_def::help (void) const
-{
-  return help_string;
-}
-
-void
-symbol_def::document (const string& h)
-{
-  help_string = h;
-}
-
-int
-maybe_delete (symbol_def *def)
-{
-  int count = 0;
-  if (def && def->count > 0)
-    {
-      def->count--;
-      count = def->count;
-      if (def->count == 0)
-	delete def;
-    }
-  return count;
-}
+octave_allocator
+symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def));
 
 // Individual records in a symbol table.
 
-symbol_record::symbol_record (void)
-{
-  init_state ();
-}
-
-symbol_record::symbol_record (const string& n, symbol_record *nxt)
-{
-  init_state ();
-  nm = n;
-  next_elem = nxt;
-}
-
-void
-symbol_record::init_state (void)
-{
-  formal_param = 0;
-  linked_to_global = 0;
-  tagged_static = 0;
-  sv_fcn = 0;
-  definition = 0;
-  next_elem = 0;
-}
-
-string
-symbol_record::name (void) const
-{
-  return nm;
-}
-
-string
-symbol_record::help (void) const
-{
-  string retval;
-  if (definition)
-    retval = definition->help ();
-  return retval;
-}
-
-octave_value&
-symbol_record::def (void)
-{
-  static octave_value foo;
-
-  return definition ? definition->def () : foo;
-}
+// XXX FIXME XXX -- there are lots of places below where we should
+// probably be temporarily ignoring interrupts.
 
 void
 symbol_record::rename (const string& new_name)
@@ -234,270 +60,104 @@
     nm = new_name;
 }
 
-bool
-symbol_record::is_function (void) const
-{
-  return definition ? definition->is_function () : false;
-}
-
-bool
-symbol_record::is_text_function (void) const
-{
-  return definition ? definition->is_text_function () : false;
-}
-
-bool
-symbol_record::is_mapper_function (void) const
-{
-  return definition ? definition->is_mapper_function () : false;
-}
-
-bool
-symbol_record::is_user_function (void) const
+void
+symbol_record::define (const octave_value& v, unsigned int sym_type)
 {
-  return definition ? definition->is_user_function () : false;
-}
-
-bool
-symbol_record::is_builtin_function (void) const
-{
-  return definition ? definition->is_builtin_function () : false;
-}
-
-bool
-symbol_record::is_variable (void) const
-{
-  return definition ? definition->is_variable () : false;
-}
-
-bool
-symbol_record::is_user_variable (void) const
-{
-  return definition ? definition->is_user_variable () : false;
-}
+  if (! (is_variable () && read_only_error ("redefine")))
+    {
+      if (is_function ())
+	push_def (new symbol_def ());
 
-bool
-symbol_record::is_builtin_variable (void) const
-{
-  return definition ? definition->is_builtin_variable () : false;
-}
-
-bool
-symbol_record::is_map_element (const string& elts) const
-{
-  return definition ? definition->is_map_element (elts) : false;
-}
-
-unsigned int
-symbol_record::type (void) const
-{
-  return definition ? definition->type : false;
-}
+      if (definition->type () == symbol_record::BUILTIN_VARIABLE)
+	sym_type = symbol_record::BUILTIN_VARIABLE;
 
-bool
-symbol_record::is_defined (void) const
-{
-  return (definition != 0);
-}
-
-bool
-symbol_record::is_read_only (void) const
-{
-  return definition ? definition->read_only : false;
-}
-
-bool
-symbol_record::is_eternal (void) const
-{
-  return definition ? definition->eternal : false;
-}
-
-void
-symbol_record::protect (void)
-{
-  if (definition)
-    {
-      definition->protect ();
-
-      if (! is_defined ())
-	warning ("protecting undefined variable `%s'", nm.c_str ());
+      definition->define (v, sym_type);
     }
 }
 
 void
-symbol_record::unprotect (void)
-{
-  if (definition)
-    definition->unprotect ();
-}
-
-void
-symbol_record::make_eternal (void)
+symbol_record::define_builtin_var (const octave_value& v)
 {
-  if (definition)
-    {
-      definition->make_eternal ();
+  define (v, symbol_record::BUILTIN_VARIABLE);
 
-      if (! is_defined ())
-	warning ("giving eternal life to undefined variable `%s'",
-		 nm.c_str ());
-    }
+  if (chg_fcn)
+    chg_fcn ();
 }
 
-void
-symbol_record::set_sv_function (sv_function f)
+bool
+symbol_record::define_as_fcn (const octave_value& v)
 {
-  sv_fcn = f;
-}
+  bool retval = false;
 
-int
-symbol_record::define (const octave_value& v, unsigned int sym_type)
-{
-  int retval = 0;
-
-  if (! (is_variable () && read_only_error ("redefine")))
+  if (! (is_variable () || read_only_error ("redefine")))
     {
-      if (! definition)
-	{
-	  definition = new symbol_def ();
-	  definition->count = 1;
-	}
-      else if (is_function ())
-	{
-	  push_def (new symbol_def ());
-	  definition->count = 1;
-	}
+      replace_all_defs (new symbol_def (v, symbol_record::BUILTIN_FUNCTION));
 
-      if (definition->symbol_type () == symbol_def::BUILTIN_VARIABLE)
-	sym_type = symbol_def::BUILTIN_VARIABLE;
-
-      definition->define (v, sym_type);
+      retval = true;
     }
 
   return retval;
 }
 
-int
-symbol_record::define_builtin_var (const octave_value& v)
+bool
+symbol_record::define (octave_function *f, unsigned int sym_type)
 {
-  int retval = define (v, symbol_def::BUILTIN_VARIABLE);
+  bool retval = false;
 
-  if (sv_fcn)
-    sv_fcn ();
+  if (! read_only_error ("redefine"))
+    {
+      octave_value tmp (f);
+
+      replace_all_defs (new symbol_def (tmp, sym_type));
+
+      retval = true;
+    }
 
   return retval;
 }
 
-int
-symbol_record::define_as_fcn (const octave_value& v)
-{
-  if (is_variable () && read_only_error ("redefine"))
-    return 0;
-
-  if (is_variable ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  if (is_function ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  push_def (new symbol_def (v, symbol_def::BUILTIN_FUNCTION));
-
-  definition->count = 1;
-
-  return 1;
-}
-
-int
-symbol_record::define (octave_function *f, unsigned int sym_type)
-{
-  if (read_only_error ("redefine"))
-    return 0;
-
-  if (is_variable ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  if (is_function ())
-    {
-      symbol_def *old_def = pop_def ();
-      maybe_delete (old_def);
-    }
-
-  octave_value tmp (f);
-
-  push_def (new symbol_def (tmp, sym_type));
-
-  definition->count = 1;
-
-  return 1;
-}
-
 void
-symbol_record::document (const string& h)
-{
-  if (definition)
-    {
-      definition->document (h);
-
-      if (! is_defined ())
-	warning ("documenting undefined variable `%s'", nm.c_str ());
-    }
-}
-
-int
 symbol_record::clear (void)
 {
-  int count = 0;
   if (linked_to_global)
     {
-      count = maybe_delete (definition);
-      definition = 0;
+      if (--definition->count <= 0)
+	delete definition;
+
+      definition = new symbol_def ();
+
       linked_to_global = 0;
     }
   else if (! tagged_static)
     {
-      symbol_def *old_def = pop_def ();
-      count = maybe_delete (old_def);
+      remove_top_def ();
+
+      if (! definition)
+	definition = new symbol_def ();
     }
-  return count;
 }
 
 void
-symbol_record::alias (symbol_record *s, bool force)
+symbol_record::alias (symbol_record *s, bool /* force */)
 {
-  sv_fcn = s->sv_fcn;
+  chg_fcn = s->chg_fcn;
 
-  if (force && ! s->definition)
-    {
-      s->definition = new symbol_def ();
-      definition = s->definition;
-      definition->count = 2; // Yes, this is correct.
-    }
-  else if (s->definition)
-    {
-      definition = s->definition;
-      definition->count++;
-    }
+  replace_all_defs (s->definition);
+
+  definition->count++;
 }
 
 void
 symbol_record::mark_as_formal_parameter (void)
 {
-  formal_param = 1;
-}
-
-bool
-symbol_record::is_formal_parameter (void) const
-{
-  return formal_param;
+  if (is_linked_to_global ())
+    error ("can't mark global variable `%s' as function parameter",
+	   nm.c_str ());
+  else if (is_static ())
+    error ("can't mark static variable `%s' as function paraemter",
+	   nm.c_str ());
+  else
+    formal_param = 1;
 }
 
 void
@@ -511,12 +171,6 @@
     linked_to_global = 1;
 }
 
-bool
-symbol_record::is_linked_to_global (void) const
-{
-  return linked_to_global;
-}
-
 void
 symbol_record::mark_as_static (void)
 {
@@ -529,9 +183,35 @@
 }
 
 bool
-symbol_record::is_static (void) const
+symbol_record::hides_fcn (void) const
 {
-  return tagged_static;
+  bool retval = false;
+
+  if (is_variable () && is_defined ())
+    {
+      symbol_def *hidden_def = definition->next_elem;
+
+      if (hidden_def && hidden_def->is_builtin_function ())
+	retval = true;
+    }
+
+  return retval;
+}
+
+bool
+symbol_record::hides_builtin (void) const
+{
+  bool retval = false;
+
+  if (is_variable () && is_defined ())
+    {
+      symbol_def *hidden_def = definition->next_elem;
+
+      if (hidden_def && hidden_def->is_user_function ())
+	retval = true;
+    }
+
+  return retval;
 }
 
 octave_value&
@@ -560,19 +240,7 @@
 	}
     }
 
-  return octave_lvalue (&(def ()), sv_fcn);
-}
-
-symbol_record *
-symbol_record::next (void) const
-{
-  return next_elem;
-}
-
-void
-symbol_record::chain (symbol_record *s)
-{
-  next_elem = s;
+  return octave_lvalue (&(def ()), chg_fcn);
 }
 
 void
@@ -581,9 +249,11 @@
   if (! is_static ())
     {
       context.push (definition);
-      definition = 0;
+
+      definition = new symbol_def ();
 
       global_link_context.push (static_cast<unsigned int> (linked_to_global));
+
       linked_to_global = 0;
     }
 }
@@ -597,45 +267,59 @@
 
   if (! context.empty ())
     {
-      if (is_variable ())
-	{
-	  symbol_def *old_def = pop_def ();
-	  maybe_delete (old_def);
-	}
+      replace_all_defs (context.pop ());
 
-      if (is_function ())
-	{
-	  symbol_def *old_def = pop_def ();
-	  maybe_delete (old_def);
-	}
-
-      definition = context.pop ();
       linked_to_global = global_link_context.pop ();
     }
 }
 
-int
+void
+symbol_record::print_symbol_info_line (ostream& os)
+{
+  os << (is_read_only () ? " r-" : " rw")
+     << (is_eternal () ? "-" : "d")
+#if 0
+     << (hides_fcn () ? "f" : (hides_builtin () ? "F" : "-"))
+#endif
+     << "  "
+     << setiosflags (ios::left) << setw (24) << type_name () . c_str ();
+
+  os << resetiosflags (ios::left);
+
+  int nr = rows ();
+  int nc = columns ();
+
+  if (nr < 0)
+    os << "      -";
+  else
+    os << setiosflags (ios::right) << setw (7) << nr;
+
+  if (nc < 0)
+    os << "      -";
+  else
+    os << setiosflags (ios::right) << setw (7) << nc;
+
+  os << resetiosflags (ios::right);
+
+  os << "  " << name () << "\n";
+}
+
+bool
 symbol_record::read_only_error (const char *action)
 {
   if (is_read_only ())
     {
       if (is_variable ())
-	{
-	  ::error ("can't %s read-only constant `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only constant `%s'", action, nm.c_str ());
       else if (is_function ())
-	{
-	  ::error ("can't %s read-only function `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only function `%s'", action, nm.c_str ());
       else
-	{
-	  ::error ("can't %s read-only symbol `%s'", action, nm.c_str ());
-	}
+	::error ("can't %s read-only symbol `%s'", action, nm.c_str ());
 
-      return 1;
+      return true;
     }
   else
-    return 0;
+    return false;
 }
 
 void
@@ -644,172 +328,39 @@
   if (! sd)
     return;
 
+  assert (definition == 0 || definition->next_elem == 0);
+
   sd->next_elem = definition;
+
   definition = sd;
 }
 
-symbol_def *
-symbol_record::pop_def (void)
+void
+symbol_record::remove_top_def (void)
 {
   symbol_def *top = definition;
-  if (definition)
-    definition = definition->next_elem;
-  return top;
-}
 
-// A structure for handling verbose information about a symbol_record.
-
-symbol_record_info::symbol_record_info (void)
-  : initialized (0), nr (-1), nc (-1), type (symbol_def::UNKNOWN),
-    hides (SR_INFO_NONE), eternal (0), read_only (0), nm (),
-    const_type () { }
-
-symbol_record_info::symbol_record_info (symbol_record& sr)
-  : initialized (0), nr (-1), nc (-1), type (sr.type ()),
-    hides (SR_INFO_NONE), eternal (0), read_only (0), nm (),
-    const_type ()
-{
-  if (sr.is_variable () && sr.is_defined ())
-    {
-      octave_value tmp = sr.def ();
-
-      const_type = tmp.type_name ();
-
-      nr = tmp.rows ();
-      nc = tmp.columns ();
-
-      symbol_def *sr_def = sr.definition;
-      symbol_def *hidden_def = sr_def->next_elem;
+  definition = definition->next_elem;
 
-      if (hidden_def)
-	{
-	  if (hidden_def->is_user_function ())
-	    hides = SR_INFO_USER_FUNCTION;
-	  else if (hidden_def->is_builtin_function ())
-	    hides = SR_INFO_BUILTIN_FUNCTION;
-	}
-    }
-
-  eternal = sr.is_eternal ();
-  read_only = sr.is_read_only ();
-
-  nm = sr.name ();
-
-  initialized = 1;
-}
-
-symbol_record_info::symbol_record_info (const symbol_record_info& s)
-  : initialized (s.initialized), nr (s.nr), nc (s.nc), type (s.type),
-    hides (s.hides), eternal (s.eternal), read_only (s.read_only),
-    nm (s.nm), const_type (s.const_type) { }
-
-symbol_record_info&
-symbol_record_info::operator = (const symbol_record_info& s)
-{
-  if (this != &s)
-    {
-      initialized = s.initialized;
-      nr = s.nr;
-      nc = s.nc;
-      type = s.type;
-      hides = s.hides;
-      eternal = s.eternal;
-      read_only = s.read_only;
-      nm = s.nm;
-      const_type = s.const_type;
-    }
-  return *this;
+  if (--top->count <= 0)
+    delete top;
 }
 
-bool
-symbol_record_info::is_defined (void) const
-{
-  return initialized;
-}
-
-bool
-symbol_record_info::is_read_only (void) const
-{
-  return read_only;
-}
-
-bool
-symbol_record_info::is_eternal (void) const
+void
+symbol_record::replace_all_defs (symbol_def *sd)
 {
-  return eternal;
-}
-
-bool
-symbol_record_info::hides_fcn (void) const
-{
-  return (hides & SR_INFO_USER_FUNCTION);
-}
-
-bool
-symbol_record_info::hides_builtin (void) const
-{
-  return (hides & SR_INFO_BUILTIN_FUNCTION);
-}
-
-string
-symbol_record_info::type_name (void) const
-{
-  string retval;
+  while (definition)
+    remove_top_def ();
 
-  if (type == symbol_def::USER_FUNCTION)
-    retval = "user function";
-  else if (type & symbol_def::BUILTIN_FUNCTION)
-    {
-      if (type & symbol_def::TEXT_FUNCTION)
-	retval = "text function";
-      else if (type & symbol_def::MAPPER_FUNCTION)
-	retval = "mapper function";
-      else
-	retval = "builtin function";
-    }
-  else
-    retval = const_type;
-
-  return retval;
-}
-
-bool
-symbol_record_info::is_function (void) const
-{
-  return (type == symbol_def::USER_FUNCTION
-	  || type == symbol_def::BUILTIN_FUNCTION
-	  || symbol_def::TEXT_FUNCTION
-	  || symbol_def::MAPPER_FUNCTION);
-}
-
-int
-symbol_record_info::rows (void) const
-{
-  return nr;
-}
-
-int
-symbol_record_info::columns (void) const
-{
-  return nc;
-}
-
-string
-symbol_record_info::name (void) const
-{
-  return nm;
+  push_def (sd);
 }
 
 // A symbol table.
 
-symbol_table::symbol_table (void)
-{
-}
-
 symbol_record *
 symbol_table::lookup (const string& nm, bool insert, bool warn)
 {
-  int index = hash (nm) & HASH_MASK;
+  unsigned int index = hash (nm);
 
   symbol_record *ptr = table[index].next ();
 
@@ -817,15 +368,17 @@
     {
       if (ptr->name () == nm)
 	return ptr;
+
       ptr = ptr->next ();
     }
 
   if (insert)
     {
-      symbol_record *new_sym;
-      new_sym = new symbol_record (nm, table[index].next ());
-      table[index].chain (new_sym);
-      return new_sym;
+      symbol_record *sr = new symbol_record (nm, table[index].next ());
+
+      table[index].chain (sr);
+
+      return sr;
     }
   else if (warn)
     warning ("lookup: symbol`%s' not found", nm.c_str ());
@@ -836,7 +389,7 @@
 void
 symbol_table::rename (const string& old_name, const string& new_name)
 {
-  int index = hash (old_name) & HASH_MASK;
+  unsigned int index = hash (old_name);
 
   symbol_record *prev = &table[index];
   symbol_record *ptr = prev->next ();
@@ -851,7 +404,7 @@
 	    {
 	      prev->chain (ptr->next ());
 
-	      index = hash (new_name) & HASH_MASK;
+	      index = hash (new_name);
 	      table[index].chain (ptr);
 
 	      return;
@@ -871,7 +424,7 @@
 void
 symbol_table::clear (bool clear_user_functions)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -888,10 +441,10 @@
     }
 }
 
-int
+bool
 symbol_table::clear (const string& nm, bool clear_user_functions)
 {
-  int index = hash (nm) & HASH_MASK;
+  unsigned int index = hash (nm);
 
   symbol_record *ptr = table[index].next ();
 
@@ -902,72 +455,63 @@
 	      || (clear_user_functions && ptr->is_user_function ())))
 	{
 	  ptr->clear ();
-	  return 1;
+	  return true;
 	}
       ptr = ptr->next ();
     }
 
-  return 0;
+  return false;
 }
 
 int
 symbol_table::size (void) const
 {
   int count = 0;
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  count++;
 	  ptr = ptr->next ();
 	}
     }
+
   return count;
 }
 
-static inline int
-pstrcmp (char **a, char **b)
+static bool
+matches_patterns (const string& name, const string_vector& pats)
 {
-  return strcmp (*a, *b);
-}
+  int npats = pats.length ();
 
-static inline int
-symbol_record_info_cmp (symbol_record_info *a, symbol_record_info *b)
-{
-  return (a->name () == b->name ());
+  if (npats == 0)
+    return true;
+
+  glob_match pattern (pats);
+
+  return pattern.match (name);
 }
 
-static int
-matches_patterns (const string& name, const string_vector& pats, int npats)
-{
-  for (int i = 0; i < npats; i++)
-    {
-      glob_match pattern (pats[i]);
-      if (pattern.match (name))
-	return 1;
-    }
-
-  return 0;
-}
-
-// This function should probably share code with symbol_table::list.
-// XXX FIXME XXX
-
-symbol_record_info *
-symbol_table::long_list (int& count, const string_vector& pats,
-			 int npats, bool sort, unsigned int type,
-			 unsigned int scope) const 
+Array<symbol_record *>
+symbol_table::symbol_list (int& count, const string_vector& pats,
+			   unsigned int type, unsigned int scope) const
 {
   count = 0;
+
   int n = size ();
+
   if (n == 0)
     return 0;
 
-  symbol_record_info *symbols = new symbol_record_info [n+1];
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  Array<symbol_record *> symbols (n);
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  assert (count < n);
@@ -979,48 +523,8 @@
 	  string my_name = ptr->name ();
 
 	  if ((type & my_type) && (scope & my_scope)
-	      && (npats == 0 || matches_patterns (my_name, pats, npats)))
-	    symbols[count++] = symbol_record_info (*ptr);
-
-	  ptr = ptr->next ();
-	}
-    }
-  symbols[count] = symbol_record_info ();
-
-  if (sort && symbols)
-    qsort (symbols, count, sizeof (symbol_record_info),
-	   symbol_record_info_cmp);
-
-  return symbols;
-}
-
-string_vector
-symbol_table::list (int& count, const string_vector& pats, int npats,
-		    bool sort, unsigned int type, unsigned int scope) const
-{
-  count = 0;
-  int n = size ();
-  if (n == 0)
-    return 0;
-
-  string_vector symbols (n);
-
-  for (int i = 0; i < HASH_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 ();
-
-	  string my_name = ptr->name ();
-
-	  if ((type & my_type) && (scope & my_scope)
-	      && (npats == 0 || matches_patterns (my_name, pats, npats)))
-	    symbols[count++] = ptr->name ();
+	      && matches_patterns (my_name, pats))
+	    symbols(count++) = ptr;
 
 	  ptr = ptr->next ();
 	}
@@ -1028,10 +532,87 @@
 
   symbols.resize (count);
 
-  if (sort && ! symbols.empty ())
-    symbols.qsort ();
+  return symbols;
+}
+
+string_vector
+symbol_table::name_list (int& count, const string_vector& pats, bool sort,
+			 unsigned int type, unsigned int scope) const
+{
+  Array<symbol_record *> symbols
+    = symbol_list (count, pats, type, scope);
+
+  string_vector names;
+
+  int n = symbols.length ();
+
+  if (n > 0)
+    {
+      names.resize (n);
+
+      for (int i = 0; i < n; i++)
+	names[i] = symbols(i)->name ();
+    }
+
+  if (sort)
+    names.qsort ();
+
+  return names;
+}
+
+static int
+maybe_list_cmp_fcn (symbol_record **a_arg, symbol_record **b_arg)
+{
+  string a = (*a_arg)->name ();
+  string b = (*b_arg)->name ();
+
+  return a.compare (b);
+}
 
-  return symbols;
+int
+symbol_table::maybe_list (const char *header, const string_vector& argv,
+			  ostream& os, bool show_verbose,
+			  unsigned type, unsigned scope)
+{
+  int count;
+
+  int status = 0;
+
+  if (show_verbose)
+    {
+      Array<symbol_record *> symbols = symbol_list (count, argv, type, scope);
+
+      int len = symbols.length ();
+
+      if (len > 0 && count > 0)
+	{
+	  os << "\n" << header << "\n\n"
+		     << "prot  type                       rows   cols  name\n"
+		     << "====  ====                       ====   ====  ====\n";
+
+	  symbols.qsort (maybe_list_cmp_fcn);
+
+	  for (int i = 0; i < len; i++)
+	    symbols(i)->print_symbol_info_line (os);
+
+	  status = 1;
+	}
+    }
+  else
+    {
+      string_vector symbols = name_list (count, argv, 1, type, scope);
+
+      if (symbols.length () > 0 && count > 0)
+	{
+	  os << "\n" << header << "\n\n";
+
+	  symbols.list_in_columns (os);
+
+	  status = 1;
+	}
+    }
+
+  return status;
 }
 
 symbol_record **
@@ -1044,9 +625,11 @@
     return 0;
 
   symbol_record **symbols = new symbol_record * [n+1];
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
+
       while (ptr)
 	{
 	  assert (count < n);
@@ -1074,7 +657,7 @@
 void
 symbol_table::push_context (void)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -1089,7 +672,7 @@
 void
 symbol_table::pop_context (void)
 {
-  for (int i = 0; i < HASH_TABLE_SIZE; i++)
+  for (unsigned int i = 0; i < table_size; i++)
     {
       symbol_record *ptr = table[i].next ();
 
@@ -1101,36 +684,67 @@
     }
 }
 
+void
+symbol_table::print_stats (void)
+{
+  int count = 0;
+  int empty_chains = 0;
+  int max_chain_length = 0;
+  int min_chain_length = INT_MAX;
+
+  for (unsigned int i = 0; i < table_size; i++)
+    {
+      int num_this_chain = 0;
+
+      symbol_record *ptr = table[i].next ();
+
+      if (ptr)
+	octave_stdout << "chain number " << i << ":\n";
+      else
+	{
+	  empty_chains++;
+	  min_chain_length = 0;
+	}
+
+      while (ptr)
+	{
+	  num_this_chain++;
+
+	  octave_stdout << "  " << ptr->name () << "\n";
+
+	  ptr = ptr->next ();
+	}
+
+      count += num_this_chain;
+
+      if (num_this_chain > max_chain_length)
+	max_chain_length = num_this_chain;
+
+      if (num_this_chain < min_chain_length)
+	min_chain_length = num_this_chain;
+
+      if (num_this_chain > 0)
+	octave_stdout << "\n";
+    }
+
+  octave_stdout << "max chain length: " << max_chain_length << "\n";
+  octave_stdout << "min chain length: " << min_chain_length << "\n";
+  octave_stdout << "empty chains:     " << empty_chains << "\n";
+  octave_stdout << "total chains:     " << table_size << "\n";
+  octave_stdout << "total symbols:    " << count << "\n";
+}
+
 // Chris Torek's fave hash function.
 
 unsigned int
 symbol_table::hash (const string& str)
 {
   unsigned int h = 0;
+
   for (unsigned int i = 0; i < str.length (); i++)
     h = h * 33 + str[i];
-  return h;
-}
 
-// Return nonzero if S is a valid identifier.
-
-bool
-valid_identifier (const char *s)
-{
-  if (! s || ! (isalnum (*s) || *s == '_'))
-     return false;
-
-  while (*++s != '\0')
-    if (! (isalnum (*s) || *s == '_'))
-      return false;
-
-  return true;
-}
-
-bool
-valid_identifier (const string& s)
-{
-  return valid_identifier (s.c_str ());
+  return h & (table_size - 1);
 }
 
 /*
--- a/src/symtab.h
+++ b/src/symtab.h
@@ -121,6 +121,11 @@
     bool is_eternal (void) const
       { return eternal; }
 
+    int rows (void) const { return definition.rows (); }
+    int columns (void) const { return definition.columns (); }
+
+    string type_name (void) const { return definition.type_name (); }
+
     void define (const octave_value& val, unsigned int sym_type)
       {
 	definition = val;
@@ -269,6 +274,14 @@
   void mark_as_static (void);
   bool is_static (void) const { return tagged_static; }
 
+  bool hides_fcn (void) const;
+  bool hides_builtin (void) const;
+
+  int rows (void) const { return definition->rows (); }
+  int columns (void) const { return definition->columns (); }
+
+  string type_name (void) const { return definition->type_name (); }
+
   octave_value& variable_value (void);
   octave_lvalue variable_reference (void);
 
@@ -280,6 +293,8 @@
 
   void pop_context (void);
 
+  void print_symbol_info_line (ostream& os);
+
 private:
 
   unsigned int formal_param : 1;
@@ -311,55 +326,6 @@
   symbol_record& operator = (const symbol_record& s);
 };
 
-#if 0
-// A structure for handling verbose information about a symbol_record.
-
-class
-symbol_record_info
-{
-public:
-
-  symbol_record_info (void);
-  symbol_record_info (symbol_record& s);
-
-  symbol_record_info (const symbol_record_info& s);
-
-  ~symbol_record_info (void) { }
-
-  symbol_record_info& operator = (const symbol_record_info& s);
-
-  bool is_defined (void) const;
-  bool is_read_only (void) const;
-  bool is_eternal (void) const;
-  bool hides_fcn (void) const;
-  bool hides_builtin (void) const;
-  string type_name (void) const;
-  bool is_function (void) const;
-  int rows (void) const;
-  int columns (void) const;
-  string name (void) const;
-
-  enum HIDES
-    {
-      SR_INFO_NONE = 0,
-      SR_INFO_USER_FUNCTION = 1,
-      SR_INFO_BUILTIN_FUNCTION = 2
-    };
-
-private:
-
-  bool initialized;
-  int nr;
-  int nc;
-  unsigned int type : 6;
-  unsigned int hides : 2;
-  unsigned int eternal : 1;
-  unsigned int read_only : 1;
-  string nm;
-  string const_type;
-};
-#endif
-
 // A symbol table.
 
 #define SYMTAB_LOCAL_SCOPE 1
@@ -403,23 +369,20 @@
 
   int size (void) const;
 
-#if 0
-  symbol_record_info *
-  long_list (int& count, const string_vector& pats = string_vector (),
-	     int npats = 0, bool sort = false,
-	     unsigned int type = SYMTAB_ALL_TYPES,
-	     unsigned int scope = SYMTAB_ALL_SCOPES) const;
-#endif
+  Array<symbol_record *>
+  symbol_list (int& count, const string_vector& pats = string_vector (),
+	       unsigned int type = SYMTAB_ALL_TYPES,
+	       unsigned int scope = SYMTAB_ALL_SCOPES) const;
+
 
   string_vector
-  list (int& count, const string_vector& pats = string_vector (),
-	int npats = 0, bool sort = false,
-	unsigned int type = SYMTAB_ALL_TYPES,
-	unsigned int scope = SYMTAB_ALL_SCOPES) const;
+  name_list (int& count, const string_vector& pats = string_vector (),
+	     bool sort = false, unsigned int type = SYMTAB_ALL_TYPES,
+	     unsigned int scope = SYMTAB_ALL_SCOPES) const;
 
 
   int maybe_list (const char *header, const string_vector& argv,
-		  int argc, ostream& os, bool show_verbose,
+		  ostream& os, bool show_verbose,
 		  unsigned type, unsigned scope);
   
   symbol_record **glob (int& count, const string& pat = string ("*"),
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -1156,12 +1156,12 @@
 
   key = names (keyword_help (), key_len);
 
-  glb = global_sym_tab->list (glb_len);
+  glb = global_sym_tab->name_list (glb_len);
 
-  top = top_level_sym_tab->list (top_len);
+  top = top_level_sym_tab->name_list (top_len);
 
   if (top_level_sym_tab != curr_sym_tab)
-    lcl = curr_sym_tab->list (lcl_len);
+    lcl = curr_sym_tab->name_list (lcl_len);
 
   ffl = octave_fcn_file_name_cache::list_no_suffix ();
   int ffl_len = ffl.length ();
@@ -1302,18 +1302,18 @@
   if (show_builtins)
     {
       pad_after += global_sym_tab->maybe_list
-	("*** built-in variables:", pats, npats, octave_stdout,
+	("*** built-in variables:", pats, octave_stdout,
 	 show_verbose, symbol_record::BUILTIN_VARIABLE, SYMTAB_ALL_SCOPES);
 
       pad_after += global_sym_tab->maybe_list
-	("*** built-in functions:", pats, npats, octave_stdout,
+	("*** built-in functions:", pats, octave_stdout,
 	 show_verbose, symbol_record::BUILTIN_FUNCTION, SYMTAB_ALL_SCOPES);
     }
 
   if (show_functions)
     {
       pad_after += global_sym_tab->maybe_list
-	("*** currently compiled functions:", pats, npats,
+	("*** currently compiled functions:", pats,
 	 octave_stdout, show_verbose, symbol_record::USER_FUNCTION,
 	 SYMTAB_ALL_SCOPES);
     }
@@ -1321,11 +1321,11 @@
   if (show_variables)
     {
       pad_after += curr_sym_tab->maybe_list
-	("*** local user variables:", pats, npats, octave_stdout,
+	("*** local user variables:", pats, octave_stdout,
 	 show_verbose, symbol_record::USER_VARIABLE, SYMTAB_LOCAL_SCOPE);
 
       pad_after += curr_sym_tab->maybe_list
-	("*** globally visible user variables:", pats, npats,
+	("*** globally visible user variables:", pats,
 	 octave_stdout, show_verbose, symbol_record::USER_VARIABLE,
 	 SYMTAB_GLOBAL_SCOPE);
     }
@@ -1645,17 +1645,19 @@
 
       if (argc > 0)
 	{
-	  lvars = curr_sym_tab->list (lcount, 0, 0, 0,
-				      SYMTAB_VARIABLES,
-				      SYMTAB_LOCAL_SCOPE);
+	  string_vector tmp;
+
+	  lvars = curr_sym_tab->name_list (lcount, tmp, false,
+					   SYMTAB_VARIABLES,
+					   SYMTAB_LOCAL_SCOPE);
 
-	  gvars = curr_sym_tab->list (gcount, 0, 0, 0,
-				      SYMTAB_VARIABLES,
-				      SYMTAB_GLOBAL_SCOPE);
+	  gvars = curr_sym_tab->name_list (gcount, tmp, false,
+					   SYMTAB_VARIABLES,
+					   SYMTAB_GLOBAL_SCOPE);
 
-	  fcns = global_sym_tab->list (fcount, 0, 0, 0,
-				       symbol_record::USER_FUNCTION,
-				       SYMTAB_ALL_SCOPES);
+	  fcns = global_sym_tab->name_list (fcount, tmp, false,
+					    symbol_record::USER_FUNCTION,
+					    SYMTAB_ALL_SCOPES);
 	}
 
       // XXX FIXME XXX -- this needs to be optimized to avoid the