diff src/variables.cc @ 7336:745a8299c2b5

[project @ 2007-12-28 20:56:55 by jwe]
author jwe
date Fri, 28 Dec 2007 20:56:58 +0000
parents 97db94ae2cf0
children 0fa079d04772
line wrap: on
line diff
--- a/src/variables.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/variables.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -28,6 +28,7 @@
 #include <cstdio>
 #include <cstring>
 
+#include <iomanip>
 #include <set>
 #include <string>
 
@@ -63,51 +64,32 @@
 // since they were last compiled?
 static int Vignore_function_time_stamp = 1;
 
-// Symbol table for symbols at the top level.
-symbol_table *top_level_sym_tab = 0;
-
-// Symbol table for the current scope.
-symbol_table *curr_sym_tab = 0;
-
-// Symbol table for the current caller scope.
-symbol_table *curr_caller_sym_tab = 0;
-
-// Symbol table for global symbols.
-symbol_table *global_sym_tab = 0;
-
-// Symbol table for functions and built-in symbols.
-symbol_table *fbi_sym_tab = 0;
-
-bool
-at_top_level (void)
-{
-  return (curr_sym_tab == top_level_sym_tab);
-}
-
-// Initialization.
-
-// Create the initial symbol tables and set the current scope at the
-// top level.
-
-void
-initialize_symbol_tables (void)
-{
-  if (! fbi_sym_tab)
-    fbi_sym_tab = new symbol_table (2048, "FBI");
-
-  if (! global_sym_tab)
-    global_sym_tab = new symbol_table (2048, "GLOBAL");
-
-  if (! top_level_sym_tab)
-    top_level_sym_tab = new symbol_table (4096, "TOP");
-
-  curr_caller_sym_tab = curr_sym_tab = top_level_sym_tab;
-}
+// Defines layout for the whos/who -long command
+static std::string Vwhos_line_format
+  = "  %a:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\n";
 
 void
 clear_mex_functions (void)
 {
-  fbi_sym_tab->clear_mex_functions ();
+  symbol_table::clear_mex_functions ();
+}
+
+void
+clear_function (const std::string& nm)
+{
+  symbol_table::clear_function (nm);
+}
+
+void
+clear_variable (const std::string& nm)
+{
+  symbol_table::clear_variable (nm);
+}
+
+void
+clear_symbol (const std::string& nm)
+{
+  symbol_table::clear_symbol (nm);
 }
 
 // Attributes of variables and functions.
@@ -116,13 +98,7 @@
 
 static std::set <std::string> command_set;
 
-static inline bool
-is_marked_as_command (const std::string& s)
-{
-  return command_set.find (s) != command_set.end ();
-}
-
-static inline void
+void
 mark_as_command (const std::string& s)
 {
   command_set.insert (s);
@@ -132,11 +108,6 @@
 unmark_command (const std::string& s)
 {
   command_set.erase (s);
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    sr->unmark_command ();
 }
 
 DEFCMD (mark_as_command, args, ,
@@ -148,7 +119,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -182,7 +153,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -210,26 +181,10 @@
 bool
 is_command_name (const std::string& s)
 {
-  bool retval = false;
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    {
-      if (sr->is_command ())
-	retval = true;
-      else if (is_marked_as_command (s))
-	{
-	  sr->mark_as_command ();
-	  retval = true;
-	}
-    }
-  else
-    retval = is_marked_as_command (s);
-
-  return retval;
+  return command_set.find (s) != command_set.end ();
 }
 
+
 DEFCMD (iscommand, args, ,
 "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} iscommand (@var{name})\n\
@@ -274,12 +229,6 @@
 
 static std::set <std::string> rawcommand_set;
 
-bool
-is_marked_as_rawcommand (const std::string& s)
-{
-  return rawcommand_set.find (s) != rawcommand_set.end ();
-}
-
 void
 mark_as_rawcommand (const std::string& s)
 {
@@ -291,11 +240,6 @@
 unmark_rawcommand (const std::string& s)
 {
   rawcommand_set.erase (s);
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    sr->unmark_rawcommand ();
 }
 
 DEFCMD (mark_as_rawcommand, args, ,
@@ -314,7 +258,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -350,7 +294,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -378,24 +322,7 @@
 bool
 is_rawcommand_name (const std::string& s)
 {
-  bool retval = false;
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    {
-      if (sr->is_rawcommand ())
-	retval = true;
-      else if (is_marked_as_rawcommand (s))
-	{
-	  sr->mark_as_rawcommand ();
-	  retval = true;
-	}
-    }
-  else
-    retval = is_marked_as_rawcommand (s);
-
-  return retval;
+  return rawcommand_set.find (s) != rawcommand_set.end ();
 }
 
 DEFCMD (israwcommand, args, ,
@@ -439,33 +366,6 @@
   return retval;
 }
 
-// Is this a built-in function?
-
-bool
-is_builtin_function_name (const std::string& s)
-{
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-  return (sr && sr->is_builtin_function ());
-}
-
-// Is this a mapper function?
-
-bool
-is_mapper_function_name (const std::string& s)
-{
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-  return (sr && sr->is_mapper_function ());
-}
-
-// Is this function globally in this scope?
-
-bool
-is_globally_visible (const std::string& name)
-{
-  symbol_record *sr = curr_sym_tab->lookup (name);
-  return (sr && sr->is_linked_to_global ());
-}
-
 // Is this octave_value a valid function?
 
 octave_function *
@@ -474,28 +374,17 @@
 {
   octave_function *ans = 0;
 
-  symbol_record *sr = 0;
-
   if (! fcn_name.empty ())
     {
-      sr = fbi_sym_tab->lookup (fcn_name, true);
-
-      lookup (sr, false);
+      octave_value val = symbol_table::find_function (fcn_name);
+
+      if (val.is_defined ())
+	ans = val.function_value (true);
     }
 
-  if (sr)
-    {
-      octave_value tmp = sr->def ();
-      ans = tmp.function_value (true);
-    }
-
-  if (! sr || ! ans || ! sr->is_function ())
-    {
-      if (warn)
-	error ("%s: the symbol `%s' is not valid as a function",
-	       warn_for.c_str (), fcn_name.c_str ());
-      ans = 0;
-    }
+  if (! ans && warn)
+    error ("%s: the symbol `%s' is not valid as a function",
+	   warn_for.c_str (), fcn_name.c_str ());
 
   return ans;
 }
@@ -613,12 +502,9 @@
 
   if (! name.empty ())
     {
-      symbol_record *sr = curr_sym_tab->lookup (name);
-
-      if (! sr)
-	sr = fbi_sym_tab->lookup (name);
-
-      retval = (sr  && sr->is_variable ());
+      octave_value val = symbol_table::varval (name);
+
+      retval = val.is_defined ();
     }
 
   return retval;
@@ -733,11 +619,7 @@
       return retval;
     }
 
-  symbol_record *sr = curr_sym_tab->lookup (name);
-
-  retval = (sr && sr->is_linked_to_global ());
-
-  return retval;
+  return symbol_table::is_global (name);
 }
 
 DEFUN (isglobal, args, ,
@@ -787,20 +669,21 @@
   // name that is visible in the current scope will be in the local
   // symbol table.
 
-  symbol_record *sr = curr_sym_tab->lookup (symbol_name);
-
-  if (! (sr && sr->is_defined ()))
-    sr = fbi_sym_tab->lookup (symbol_name);
-
-  if (sr && sr->is_defined ())
+  octave_value_list evaluated_args;
+  bool args_evaluated;
+
+  octave_value val = symbol_table::find (symbol_name, 0, string_vector (),
+					 evaluated_args, args_evaluated);
+
+  if (val.is_defined ())
     {
       bool not_a_struct = struct_elts.empty ();
-      bool var_ok = not_a_struct || sr->is_map_element (struct_elts);
+      bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */;
 
       if (! retval
 	  && var_ok
 	  && (type == "any" || type == "var")
-	  && sr->is_user_variable ())
+	  && val.is_constant ())
 	{
 	  retval = 1;
 	}
@@ -808,7 +691,7 @@
       if (! retval
 	  && (type == "any" || type == "builtin"))
 	{
-	  if (not_a_struct && sr->is_builtin_function ())
+	  if (not_a_struct && val.is_builtin_function ())
 	    {
 	      retval = 5;
 	    }
@@ -817,13 +700,12 @@
       if (! retval
 	  && not_a_struct
 	  && (type == "any" || type == "file")
-	  && (sr->is_user_function () || sr->is_dld_function ()))
+	  && (val.is_user_function () || val.is_dld_function ()))
 	{
-	  octave_value t = sr->def ();
-	  octave_function *f = t.function_value (true);
+	  octave_function *f = val.function_value (true);
 	  std::string s = f ? f->fcn_file_name () : std::string ();
 
-	  retval = s.empty () ? 103 : (sr->is_user_function () ? 2 : 3);
+	  retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3);
 	}
     }
 
@@ -962,289 +844,29 @@
   return retval;
 }
 
-bool
-fcn_out_of_date (octave_function *fcn, const std::string& ff, time_t tp)
-{
-  bool retval = false;
-
-  fcn->mark_fcn_file_up_to_date (octave_time ());
-
-  if (! (Vignore_function_time_stamp == 2
-	 || (Vignore_function_time_stamp && fcn->is_system_fcn_file ())))
-    {
-      file_stat fs (ff);
-
-      if (fs && fs.is_newer (tp))
-	retval = true;
-    }
-
-  return retval;
-}
-
-// Is there a corresponding function file that is newer than the
-// symbol definition?
-
-static bool
-symbol_out_of_date (symbol_record *sr)
-{
-  bool retval = false;
-
-  if (sr)
-    {
-      octave_value ans = sr->def ();
-
-      octave_function *fcn = ans.function_value (true);
-
-      if (fcn)
-	{
-	  std::string ff = fcn->fcn_file_name ();
-
-	  if (! ff.empty ())
-	    {
-	      octave_time tc = fcn->time_checked ();
-
-	      bool relative = fcn->is_relative ();
-
-	      if (tc < Vlast_prompt_time
-		  || (relative && tc < Vlast_chdir_time))
-		{
-		  octave_time ottp = fcn->time_parsed ();
-		  time_t tp = ottp.unix_time ();
-
-		  std::string nm = fcn->is_nested_function ()
-		    ? fcn->parent_fcn_name () : fcn->name ();
-
-		  // FIXME -- the following code is repeated
-		  // in load_fcn_from_file in parse.y.
-
-		  int nm_len = nm.length ();
-
-		  std::string file;
-
-		  if (octave_env::absolute_pathname (nm)
-		      && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
-					  || nm.substr (nm_len-4) == ".mex"))
-			  || (nm_len > 2 && nm.substr (nm_len-4) == ".m")))
-		    {
-		      file = nm;
-		    }
-		  else
-		    {
-		      file = lookup_autoload (nm);
-
-		      if (file.empty ())
-			file = load_path::find_fcn (nm);
-
-		      file = octave_env::make_absolute (file, octave_env::getcwd ());
-		    }
-
-		  if (file.empty ())
-		    {
-		      // Can't see this function now, so we should
-		      // clear it.
-
-		      sr->clear ();
-
-		      retval = true;
-		    }
-		  else if (same_file (file, ff))
-		    {
-		      retval = fcn_out_of_date (fcn, ff, tp);
-		    }
-		  else
-		    {
-		      // Check the full function name.  Maybe we already
-		      // parsed it.
-
-		      symbol_record *full_sr = fbi_sym_tab->lookup (file);
-
-		      if (full_sr)
-			{
-			  octave_value v = full_sr->def ();
-
-			  if (v.is_function ())
-			    {
-			      // OK, swap the aliases around.
-
-			      // FIXME -- this is a bit
-			      // tricky, so maybe some refactoring is
-			      // in order here too...
-
-			      symbol_record *short_sr = fbi_sym_tab->lookup (nm);
-
-			      if (short_sr)
-				short_sr->alias (full_sr);
-
-			      // Make local symbol table entry point
-			      // to correct global function too.
-
-			      sr->alias (full_sr);
-
-			      fcn = v.function_value ();
-
-			      retval = fcn_out_of_date (fcn, file, tp);
-			    }
-			  else
-			    retval = true;
-			}
-		      else
-			retval = true;
-		    }
-		}
-	    }
-	}
-    }
-
-  return retval;
-}
-
-bool
-lookup (symbol_record *sym_rec, bool exec_script)
-{
-  bool script_executed = false;
-
-  if (! sym_rec->is_linked_to_global ())
-    {
-      if (sym_rec->is_defined ())
-	{
-	  if (sym_rec->is_function () && symbol_out_of_date (sym_rec))
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	}
-      else if (! sym_rec->is_formal_parameter ())
-	{
-	  link_to_builtin_or_function (sym_rec);
-
-	  if (! sym_rec->is_defined ())
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	  else if (sym_rec->is_function () && symbol_out_of_date (sym_rec))
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	}
-    }
-
-  return script_executed;
-}
-
-// Get the symbol record for the given name that is visible in the
-// current scope.  Reread any function definitions that appear to be
-// out of date.  If a function is available in a file but is not
-// currently loaded, this will load it and insert the name in the
-// current symbol table.
-
-symbol_record *
-lookup_by_name (const std::string& nm, bool exec_script)
-{
-  symbol_record *sym_rec = curr_sym_tab->lookup (nm, true);
-
-  lookup (sym_rec, exec_script);
-
-  return sym_rec;
-}
-
-octave_value
-lookup_function (const std::string& nm, const std::string& parent)
-{
-  octave_value retval;
-
-  symbol_record *sr = 0;
-
-  if (! parent.empty ())
-    sr = fbi_sym_tab->lookup (parent + ":" + nm);
-
-  if (! sr || ! sr->is_function ())
-    {
-      if (curr_parent_function)
-	sr = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm);
-
-      if (! sr || ! sr->is_function ())
-	sr = fbi_sym_tab->lookup (nm, true);
-
-      if (sr && ! sr->is_function ())
-	load_fcn_from_file (sr, false);
-    }
-
-  if (sr)
-    {
-      octave_value v = sr->def ();
-
-      if (v.is_function ())
-	retval = v;
-    }
-
-  return retval;
-}
-
-octave_value
-lookup_user_function (const std::string& nm)
-{
-  octave_value retval;
-
-  symbol_record *sr = 0;
-
-  if (curr_parent_function)
-    {
-      std::string parent = curr_parent_function->name ();
-
-      sr = fbi_sym_tab->lookup (parent + ":" + nm);
-    }
-
-  if (! sr || ! sr->is_user_function ())
-    {
-      sr = fbi_sym_tab->lookup (nm, true);
-
-      if (sr && ! sr->is_user_function ())
-	load_fcn_from_file (sr, false);
-    }
-
-  if (sr)
-    retval = sr->def ();
-
-  return retval;
-}
-
 octave_value
 lookup_function_handle (const std::string& nm)
 {
-  octave_value retval;
-
-  symbol_record *sr = curr_sym_tab->lookup (nm, true);
-
-  if (sr && sr->def ().is_function_handle ())
-    retval = sr->def ();
-
-  return retval;
+  octave_value val = symbol_table::varval (nm);
+
+  return val.is_function_handle () ? val : octave_value ();
 }
 
 octave_value
 get_global_value (const std::string& nm, bool silent)
 {
-  octave_value retval;
-
-  symbol_record *sr = global_sym_tab->lookup (nm);
-
-  if (sr)
-    {
-      octave_value sr_def = sr->def ();
-
-      if (sr_def.is_defined ())
-	retval = sr_def;
-      else if (! silent)
-	error ("get_global_by_name: undefined symbol `%s'", nm.c_str ());
-    }
-  else if (! silent)
-    error ("get_global_by_name: unknown symbol `%s'", nm.c_str ());
-
-  return retval;
+  octave_value val = symbol_table::varval (nm, symbol_table::global_scope ());
+
+  if (val.is_undefined () && ! silent)
+    error ("get_global_by_name: undefined symbol `%s'", nm.c_str ());
+
+  return val;
 }
 
 void
 set_global_value (const std::string& nm, const octave_value& val)
 {
-  symbol_record *sr = global_sym_tab->lookup (nm, true);
-
-  if (sr)
-    sr->define (val);
-  else
-    panic_impossible ();
+  symbol_table::varref (nm, symbol_table::global_scope ()) = val;
 }
 
 // Variable values.
@@ -1415,174 +1037,609 @@
   return retval;
 }
 
-// Global stuff and links to builtin variables and functions.
-
-// Make the definition of the symbol record sr be the same as the
-// definition of the global variable of the same name, creating it if
-// it doesn't already exist.
-
-void
-link_to_global_variable (symbol_record *sr)
+struct
+symbol_record_name_compare
+{
+  bool operator () (const symbol_table::symbol_record& a,
+		    const symbol_table::symbol_record& b)
+  {
+    std::string a_nm = a.name ();
+    std::string b_nm = b.name ();
+
+    return a_nm.compare (b_nm);
+  }
+};
+
+struct
+whos_parameter
 {
-  if (! sr->is_linked_to_global ())
+  char command;
+  char modifier;
+  int parameter_length;
+  int first_parameter_length;
+  int dimensions;
+  int balance;
+  std::string text;
+  std::string line;
+};
+
+static void
+print_descriptor (std::ostream& os, std::list<whos_parameter> params)
+{
+  // This method prints a line of information on a given symbol
+  std::list<whos_parameter>::iterator i = params.begin ();
+  std::ostringstream param_buf;
+
+  while (i != params.end ())
     {
-      sr->mark_as_linked_to_global ();
-
-      if (! error_state)
+      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
 	{
-	  std::string nm = sr->name ();
-
-	  symbol_record *gsr = global_sym_tab->lookup (nm, true);
-
-	  // Make sure this symbol is a variable.
-
-	  if (! gsr->is_user_variable ())
-	    gsr->define (octave_value ());
-
-	  sr->alias (gsr);
+	  os << param.text;
+	  param_buf << param.line;
+	  i++;
 	}
     }
+
+  os << param_buf.str ();
 }
 
-// Make the definition of the symbol record sr be the same as the
-// definition of the builtin variable of the same name.
-
-// Make the definition of the symbol record sr be the same as the
-// definition of the builtin function, or user function of the same
-// name, provided that the name has not been used as a formal parameter.
-
-void
-link_to_builtin_or_function (symbol_record *sr)
-{
-  std::string nm = sr->name ();
-
-  symbol_record *tmp_sym = 0;
-
-  octave_function *fcn = octave_call_stack::current ();
-
-  std::string parent = fcn ? fcn->parent_fcn_name () : std::string ();
-
-  if (! parent.empty ())
-    tmp_sym = fbi_sym_tab->lookup (parent + ":" + nm);
-
-  if (! tmp_sym && curr_parent_function)
-    tmp_sym = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm);
-
-  if (! tmp_sym)
-    tmp_sym = fbi_sym_tab->lookup (nm);
-
-  if (tmp_sym
-      && tmp_sym->is_function ()
-      && ! tmp_sym->is_formal_parameter ())
-    sr->alias (tmp_sym);
-}
-
-// Force a link to a function in the current symbol table.  This is
-// used just after defining a function to avoid different behavior
-// depending on whether or not the function has been evaluated after
-// being defined.
+// Calculate how much space needs to be reserved for the first part of
+// the dimensions string.  For example,
 //
-// Return without doing anything if there isn't a function with the
-// given name defined in the global symbol table.
-
-void
-force_link_to_function (const std::string& id_name)
-{
-  symbol_record *fsr = fbi_sym_tab->lookup (id_name, true);
-  if (fsr->is_function ())
-    {
-      curr_sym_tab->clear (id_name);
-      symbol_record *csr = curr_sym_tab->lookup (id_name, true);
-      csr->alias (fsr);
-    }
-}
-
-DEFUN (document, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} document (@var{symbol}, @var{text})\n\
-Set the documentation string for @var{symbol} to @var{text}.\n\
-@end deftypefn")
+//   mat is a 12x3 matrix
+//            ^^  => 2 columns
+
+static int
+dimensions_string_req_first_space (const dim_vector& dims, int print_dims)
 {
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 2)
+  int first_param_space = 0;
+
+  // Calculating dimensions.
+
+  std::string dim_str = "";
+  std::stringstream ss;
+  long dim = dims.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 << dims (0);
+	 
+	  dim_str = ss.str ();
+	  first_param_space = dim_str.length ();
+	}
+    }
+  else
     {
-      std::string name = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  std::string help = args(1).string_value ();
-
-	  if (! error_state)
+      // Printing dimension string as: a-D.
+
+      ss << dim;
+
+      dim_str = ss.str ();
+      first_param_space = dim_str.length ();
+    }
+
+  return first_param_space;
+}
+
+// Make the dimensions-string.  For example: mat is a 2x3 matrix.
+//                                                    ^^^
+//
+// FIXME -- why not just use the dim_vector::str () method?
+
+std::string
+make_dimensions_string (const dim_vector& dims, int print_dims)
+{
+  // Calculating dimensions.
+
+  std::string dim_str = "";
+  std::stringstream ss;
+  long dim = dims.length ();
+
+  // 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 (is_command_name (name)
-		  || is_mapper_function_name (name)
-		  || is_builtin_function_name (name))
-		error ("document: can't redefine help for built-in functions");
-	      else
+	      if (i == 0)
 		{
-		  symbol_record *sym_rec = curr_sym_tab->lookup (name);
-
-		  if (sym_rec)
-		    sym_rec->document (help);
+		  if (dim == 1)
+		    {
+		      // Looks like this is not going to happen in
+		      // Octave, but ...
+
+		      ss << "1x" << dims (i);
+		    }
 		  else
-		    error ("document: no such symbol `%s'", name.c_str ());
+		    ss << dims (i);
 		}
+	      else if (i < dim && dim != 1)
+		ss << "x" << dims (i);
 	    }
 	}
     }
   else
-    print_usage ();
-
-  return retval;
+    {
+      // Printing dimension string as: a-D.
+
+      ss << dim << "-D";
+    }
+
+  dim_str = ss.str ();
+
+  return dim_str;
 }
 
-// FIXME -- this function is duplicated in symtab.cc with the
-// name maybe_list_cmp_fcn.
+// Calculate how much space needs to be reserved for the
+// dimensions string.  For example,
+//
+//   mat is a 12x3 matrix
+//            ^^^^ => 4 columns
+//
+// FIXME -- why not just use the dim_vector::str () method?
 
 static int
-symbol_record_name_compare (const void *a_arg, const void *b_arg)
+dimensions_string_req_total_space (const dim_vector& dims, int print_dims)
+{
+  std::string dim_str = "";
+  std::stringstream ss;
+
+  ss << make_dimensions_string (dims, print_dims);
+  dim_str = ss.str ();
+
+  return dim_str.length ();
+}
+
+static std::list<whos_parameter>
+parse_whos_line_format (const std::list<symbol_table::symbol_record>& symbols)
 {
-  const symbol_record *a = *(static_cast<symbol_record *const*> (a_arg));
-  const symbol_record *b = *(static_cast<symbol_record *const*> (b_arg));
-
-  std::string a_nm = a->name ();
-  std::string b_nm = b->name ();
-
-  return a_nm.compare (b_nm);
+  // 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;
+
+  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 ();
+
+  // Calculating necessary spacing for name column,
+  // bytes column, elements column and class column
+
+  for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+       p != symbols.end (); p++)
+    {
+      std::stringstream ss1, ss2;
+      std::string str;
+
+      str = p->name ();
+      param_length(pos_n) = ((str.length ()
+			      > static_cast<size_t> (param_length(pos_n)))
+			     ? str.length () : param_length(pos_n));
+
+      octave_value val = p->varval ();
+
+      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.capacity ();
+      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 (Vwhos_line_format[idx] == '%')
+        {
+	  bool error_encountered = 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 ();
+
+	  // FIXME -- use iostream functions instead of sscanf!
+
+	  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_encountered = 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 (), '=');
+
+	      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;
+	    }
+	  else
+	    {
+	      error ("whos_line_format: '%c' is not a command",
+		     param.command);
+	      error_encountered = 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 first, rest = 0, total;
+	      param.dimensions = c;
+	      first = param.first_parameter_length;
+	      total = param.parameter_length;
+
+	      for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+		   p != symbols.end (); p++)
+		{
+		  octave_value val = p->varval ();
+		  dim_vector dims = val.dims ();
+		  int first1 = dimensions_string_req_first_space (dims, param.dimensions);
+		  int total1 = dimensions_string_req_total_space (dims, 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_encountered = 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_encountered)
+	    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;
+}
+
+void
+print_symbol_info_line (std::ostream& os,
+			const symbol_table::symbol_record& sr,
+			std::list<whos_parameter>& params)
+{
+  octave_value val = sr.varval ();
+  dim_vector dims = val.dims ();
+
+  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 (dims, param.dimensions);
+		  int back = param.parameter_length
+		    - dimensions_string_req_total_space (dims, param.dimensions)
+		    - 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)
+		     << make_dimensions_string (dims, 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 'a':
+	      {
+		char tmp[5];
+
+		tmp[0] = (sr.is_automatic () ? 'a' : ' ');
+		tmp[1] = (sr.is_formal () ? 'f' : ' ');
+		tmp[2] = (sr.is_global () ? 'g' : ' ');
+		tmp[3] = (sr.is_persistent () ? 'p' : ' ');
+		tmp[4] = 0;
+
+		os << tmp;
+	      }
+	      break;
+
+	    case 'b':
+	      os << val.byte_size ();
+	      break;
+
+	    case 'c':
+	      os << val.class_name ();
+	      break;
+
+	    case 'e':
+	      os << val.capacity ();
+	      break;
+
+	    case 'n':
+	      os << sr.name ();
+	      break;
+
+	    case 's':
+	      if (param.modifier != 'c')
+		os << make_dimensions_string (dims, param.dimensions);
+	      break;
+
+	    case 't':
+	      os << val.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++;
+	}
+    }
 }
 
 static octave_value
-do_who (int argc, const string_vector& argv, int return_list)
+do_who (int argc, const string_vector& argv, bool return_list,
+	bool verbose = false)
 {
   octave_value retval;
 
-  bool show_builtins = false;
-  bool show_functions = false;
-  bool show_variables = false;
-  bool show_verbose = false;
-
   std::string my_name = argv[0];
 
+  bool global_only = false;
+
   int i;
   for (i = 1; i < argc; i++)
     {
-      if (argv[i] == "-all" || argv[i] == "-a")
+      if (argv[i] == "-regexp" || argv[i] == "-file")
 	{
-	  show_builtins = true;
-	  show_functions = true;
-	  show_variables = true;
+	  error ("%s: `%s' option not implemented", my_name.c_str (),
+		 argv[i].c_str ());
+
+	  return retval;
 	}
-      else if (argv[i] == "-builtins" || argv[i] == "-b")
-	show_builtins = true;
-      else if (argv[i] == "-functions" || argv[i] == "-f")
-	show_functions = true;
-      else if (argv[i] == "-long" || argv[i] == "-l")
-	show_verbose = true;
-      else if (argv[i] == "-variables" || argv[i] == "-v")
-	show_variables = true;
+      else if (argv[i] == "global")
+	global_only = true;
       else if (argv[i][0] == '-')
 	warning ("%s: unrecognized option `%s'", my_name.c_str (),
 		 argv[i].c_str ());
@@ -1590,99 +1647,27 @@
 	break;
     }
 
-  // If no options were specified to select the type of symbol to
-  // display, then set defaults.
-
-  if (! (show_builtins || show_functions || show_variables))
+  int npats = argc - i;
+  string_vector pats (npats > 0 ? npats : 1);
+  if (npats > 0)
     {
-      show_functions = at_top_level ();
-      show_variables = true;
+      for (int j = 0; j < npats; j++)
+	pats[j] = argv[i+j];
     }
-
-  int npats = argc - i;
-  string_vector pats (npats);
-  for (int j = 0; j < npats; j++)
-    pats[j] = argv[i+j];
-
-  // If the user specified -l and nothing else, show variables.  If
-  // evaluating this at the top level, also show functions.
-
-  if (show_verbose && ! (show_builtins || show_functions || show_variables))
-    {
-      show_functions = at_top_level ();
-      show_variables = 1;
-    }
+  else
+    pats[0] = "*";
+    
+  symbol_table::scope_id scope = global_only
+    ? symbol_table::global_scope () : symbol_table::current_scope ();
+
+  std::list<symbol_table::symbol_record> symbols
+    = symbol_table::glob_variables (pats, scope);
+
+  size_t symbols_len = symbols.size ();
 
   if (return_list)
     {
-      // FIXME -- maybe symbol_list should return a std::list
-      // object instead of an Array.
-
-      dim_vector dv (0, 0);
-
-      Array<symbol_record *> s3 (dv);
-      Array<symbol_record *> s4 (dv);
-      Array<symbol_record *> s5 (dv);
-      Array<symbol_record *> s6 (dv);
-      Array<symbol_record *> s7 (dv);
-      Array<symbol_record *> s8 (dv);
-
-      if (show_builtins)
-	{
-	  s3 = fbi_sym_tab->symbol_list (pats, symbol_record::BUILTIN_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_functions)
-	{
-	  s4 = fbi_sym_tab->symbol_list (pats, symbol_record::DLD_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-
-	  s5 = fbi_sym_tab->symbol_list (pats, symbol_record::USER_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-
-	  s6 = fbi_sym_tab->symbol_list (pats, symbol_record::MEX_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_variables)
-	{
-	  s7 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
-					  SYMTAB_LOCAL_SCOPE);
-
-	  s8 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
-					  SYMTAB_GLOBAL_SCOPE);
-	}
-
-      octave_idx_type s3_len = s3.length ();
-      octave_idx_type s4_len = s4.length ();
-      octave_idx_type s5_len = s5.length ();
-      octave_idx_type s6_len = s6.length ();
-      octave_idx_type s7_len = s7.length ();
-      octave_idx_type s8_len = s8.length ();
-
-      octave_idx_type symbols_len
-	= s3_len + s4_len + s5_len + s6_len + s7_len + s8_len;
-
-      Array<symbol_record *> symbols (dim_vector (symbols_len, 1));
-
-      octave_idx_type k = 0;
-
-      symbols.insert (s3, k, 0);
-      k += s3_len;
-      symbols.insert (s4, k, 0);
-      k += s4_len;
-      symbols.insert (s5, k, 0);
-      k += s5_len;
-      symbols.insert (s6, k, 0);
-      k += s6_len;
-      symbols.insert (s7, k, 0);
-      k += s7_len;
-      symbols.insert (s8, k, 0);
-
-      symbols.qsort (symbol_record_name_compare);
-
-      if (show_verbose)
+      if (verbose)
 	{
 	  Array<octave_value> name_info (symbols_len, 1);
 	  Array<octave_value> size_info (symbols_len, 1);
@@ -1693,9 +1678,12 @@
 	  Array<octave_value> complex_info (symbols_len, 1);
 	  Array<octave_value> nesting_info (symbols_len, 1);
 
-	  for (octave_idx_type j = 0; j < symbols_len; j++)
+	  std::list<symbol_table::symbol_record>::const_iterator p
+	    = symbols.begin ();
+
+	  for (size_t j = 0; j < symbols_len; j++)
 	    {
-	      symbol_record *sr = symbols(j);
+	      const symbol_table::symbol_record& sr = *p++;
 
 	      Octave_map ni;
 
@@ -1708,13 +1696,16 @@
 	      ni.assign ("function", caller_function_name);
 	      ni.assign ("level", 1);
 
-	      name_info(j) = sr->name ();
-	      size_info(j) = sr->size ();
-	      bytes_info(j) = sr->byte_size ();
-	      class_info(j) = sr->class_name ();
-	      global_info(j) = sr->is_linked_to_global ();
-	      sparse_info(j) = sr->is_sparse_type ();
-	      complex_info(j) = sr->is_complex_type ();
+	      name_info(j) = sr.name ();
+	      global_info(j) = sr.is_global ();
+
+	      octave_value val = sr.varval ();
+
+	      size_info(j) = val.size ();
+	      bytes_info(j) = val.byte_size ();
+	      class_info(j) = val.class_name ();
+	      sparse_info(j) = val.is_sparse_type ();
+	      complex_info(j) = val.is_complex_type ();
 	      nesting_info(j) = ni;
 	    }
 
@@ -1739,56 +1730,70 @@
 	    {
 	      names.resize (symbols_len);
 
-	      for (octave_idx_type j = 0; j < symbols_len; j++)
-		names[j] = symbols(j)->name ();
+	      std::list<symbol_table::symbol_record>::const_iterator p
+		= symbols.begin ();
+
+	      for (size_t j = 0; j < symbols_len; j++)
+		{
+		  names[j] = p->name ();
+		  p++;
+		}
 	    }
 
 	  retval = Cell (names);
 	}
     }
-  else
+  else if (symbols_len > 0)
     {
-      int pad_after = 0;
-
-      if (show_builtins)
-	{
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** built-in functions:", pats, octave_stdout,
-	     show_verbose, symbol_record::BUILTIN_FUNCTION, SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_functions)
+      if (global_only)
+	octave_stdout << "Global variables:\n\n";
+      else
+	octave_stdout << "Variables in the current scope:\n\n";
+
+      if (verbose)
 	{
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** dynamically linked functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::DLD_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
-
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** currently compiled functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::USER_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
-
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** mex functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::MEX_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
+	  size_t bytes = 0;
+	  size_t elements = 0;
+
+	  std::list<whos_parameter> params;
+
+	  params = parse_whos_line_format (symbols);
+
+	  print_descriptor (octave_stdout, params);
+
+	  octave_stdout << "\n";
+
+	  for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+	       p != symbols.end (); p++)
+	    {
+	      print_symbol_info_line (octave_stdout, *p, params);
+	      octave_value val = p->varval ();
+	      elements += val.capacity ();
+	      bytes += val.byte_size ();
+	    }
+
+	  octave_stdout << "\nTotal is " << elements
+			<< (elements == 1 ? " element" : " elements")
+			<< " using " << bytes
+			<< (bytes == 1 ? " byte" : " bytes") << "\n";
 	}
-
-      if (show_variables)
+      else
 	{
-	  pad_after += curr_sym_tab->maybe_list
-	    ("*** 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,
-	     octave_stdout, show_verbose, symbol_record::USER_VARIABLE,
-	     SYMTAB_GLOBAL_SCOPE);
+	  string_vector names (symbols_len);
+
+	  std::list<symbol_table::symbol_record>::const_iterator p
+	    = symbols.begin ();
+
+	  for (size_t j = 0; j < symbols_len; j++)
+	    {
+	      names[j] = p->name ();
+	      p++;
+	    }
+
+	  names.list_in_columns (octave_stdout);
 	}
 
-      if (pad_after)
-	octave_stdout << "\n";
+      octave_stdout << "\n";
     }
 
   return retval;
@@ -1840,10 +1845,8 @@
 
       string_vector argv = args.make_argv ("who");
 
-      if (error_state)
-	return retval;
-
-      retval = do_who (argc, argv, nargout == 1);
+      if (! error_state)
+	retval = do_who (argc, argv, nargout == 1);
     }
   else
     print_usage ();
@@ -1861,23 +1864,12 @@
 
   if (nargout < 2)
     {
-      int nargin = args.length ();
-
-      octave_value_list tmp_args;
-
-      for (int i = nargin; i > 0; i--)
-	tmp_args(i) = args(i-1);
-
-      tmp_args(0) = "-long";
-
-      int argc = tmp_args.length () + 1;
-
-      string_vector argv = tmp_args.make_argv ("whos");
-
-      if (error_state)
-	return retval;
-
-      retval = do_who (argc, argv, nargout == 1);
+      int argc = args.length () + 1;
+
+      string_vector argv = args.make_argv ("whos");
+
+      if (! error_state)
+	retval = do_who (argc, argv, nargout == 1, true);
     }
   else
     print_usage ();
@@ -1890,14 +1882,14 @@
 void
 bind_ans (const octave_value& val, bool print)
 {
-  symbol_record *sr = curr_sym_tab->lookup ("ans", true);
+  static std::string ans = "ans";
 
   if (val.is_defined ())
     {
-      sr->define (val);
+      symbol_table::varref (ans) = val;
 
       if (print)
-	val.print_with_name (octave_stdout, "ans");
+	val.print_with_name (octave_stdout, ans);
     }
 }
 
@@ -1912,61 +1904,59 @@
 }
 
 void 
-mlock (const std::string& nm)
+mlock (void)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm, true);
-
-  if (sr)
-    sr->mark_as_static ();
+  octave_function *fcn = octave_call_stack::caller ();
+
+  if (fcn)
+    fcn->lock ();
+  else
+    error ("mlock: invalid use outside a function");
 }
 
 void 
 munlock (const std::string& nm)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm);
-
-  if (sr && sr->is_static ())
-    sr->unmark_static ();
-  else
-    error ("munlock: %s is not locked", nm.c_str ());
+  octave_value val = symbol_table::find_function (nm);
+
+  if (val.is_defined ())
+    {
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	fcn->unlock ();
+    }
 }
 
 bool
 mislocked (const std::string& nm)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm);
-
-  return (sr && sr->is_static ());
+  bool retval = false;
+
+  octave_value val = symbol_table::find_function (nm);
+
+  if (val.is_defined ())
+    {
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	retval = fcn->islocked ();
+    }
+
+  return retval;
 }
 
 DEFCMD (mlock, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} mlock (@var{name})\n\
-Lock the named function into memory.  If no function is named\n\
-then lock in the current function.\n\
+Lock the current function into memory so that it can't be cleared.\n\
 @seealso{munlock, mislocked, persistent}\n\
 @end deftypefn")
 {
   octave_value_list retval;
 
-  if (args.length () == 1)
-    {
-      std::string name = args(0).string_value ();
-
-      if (! error_state)
-	mlock (name);
-      else
-	error ("mlock: expecting argument to be a function name");
-    }
-  else if (args.length () == 0)
-    {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
-
-      if (fcn)
-        mlock (fcn->name ());
-      else
-        error ("mlock: invalid use outside a function");
-    }
+  if (args.length () == 0)
+    mlock ();
   else
     print_usage ();
 
@@ -1994,10 +1984,10 @@
     }
   else if (args.length () == 0)
     {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
+      octave_function *fcn = octave_call_stack::caller ();
 
       if (fcn)
-        munlock (fcn->name ());
+        fcn->unlock ();
       else
         error ("munlock: invalid use outside a function");
     }
@@ -2029,10 +2019,10 @@
     }
   else if (args.length () == 0)
     {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
+      octave_function *fcn = octave_call_stack::caller ();
 
       if (fcn)
-        retval = mislocked (fcn->name ());
+        retval = fcn->islocked ();
       else
         error ("mislocked: invalid use outside a function");
     }
@@ -2069,14 +2059,6 @@
   return retval;
 }
 
-static inline bool
-is_local_variable (const std::string& nm)
-{
-  symbol_record *sr = curr_sym_tab->lookup (nm);
-
-  return (sr && sr->is_variable ());
-}
-
 static inline void
 maybe_warn_exclusive (bool exclusive)
 {
@@ -2084,136 +2066,17 @@
     warning ("clear: ignoring --exclusive option");
 }
 
-static inline void
-do_clear_all (void)
-{
-  curr_sym_tab->clear ();
-  fbi_sym_tab->clear_functions ();
-  global_sym_tab->clear ();
-}
-
-static inline void
-do_clear_functions (void)
-{
-  curr_sym_tab->clear_functions ();
-  fbi_sym_tab->clear_functions ();
-}
-
-static inline void
-do_clear_globals (void)
-{
-  curr_sym_tab->clear_globals ();
-  global_sym_tab->clear ();
-}
-
-static inline void
-do_clear_variables (void)
-{
-  curr_sym_tab->clear ();
-}
-
-static inline bool
-do_clear_function (const std::string& nm)
-{
-  bool b1 = curr_sym_tab->clear_function (nm);
-
-  bool b2 = fbi_sym_tab->clear_function (nm);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_global (const std::string& nm)
-{
-  bool b1 = curr_sym_tab->clear_global (nm);
-
-  bool b2 = global_sym_tab->clear_variable (nm);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_variable (const std::string& nm)
-{
-  return curr_sym_tab->clear_variable (nm);
-}
-
-static inline bool
-do_clear_symbol (const std::string& nm)
-{
-  bool cleared = curr_sym_tab->clear_variable (nm);
-
-  if (! cleared)
-    cleared = do_clear_function (nm);
-
-  return cleared;
-}
-
-static inline bool
-do_clear_function_pattern (const std::string& pat)
-{
-  bool b1 = curr_sym_tab->clear_function_pattern (pat);
-
-  bool b2 = fbi_sym_tab->clear_function_pattern (pat);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_global_pattern (const std::string& pat)
-{
-  bool b1 = curr_sym_tab->clear_global_pattern (pat);
-
-  bool b2 = global_sym_tab->clear_variable_pattern (pat);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_variable_pattern (const std::string& pat)
-{
-  return curr_sym_tab->clear_variable_pattern (pat);
-}
-
-static inline bool
-do_clear_symbol_pattern (const std::string& pat)
-{
-  // FIXME -- if we have a variable v1 and a function v2 and
-  // someone says clear v*, we will clear the variable but not the
-  // function.  Is that really what should happen?  (I think it is
-  // what Matlab does.)
-
-  bool cleared = curr_sym_tab->clear_variable_pattern (pat);
-
-  if (! cleared)
-    cleared = do_clear_function_pattern (pat);
-
-  return cleared;
-}
-
-static inline void
+static void
 do_clear_functions (const string_vector& argv, int argc, int idx,
 		    bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_functions ();
+    symbol_table::clear_functions ();
   else
     {
       if (exclusive)
 	{
-	  string_vector lfcns = curr_sym_tab->user_function_name_list ();
-
-	  int lcount = lfcns.length ();
-
-	  for (int i = 0; i < lcount; i++)
-	    {
-	      std::string nm = lfcns[i];
-
-	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_function (nm);
-	    }
-
-	  string_vector fcns = fbi_sym_tab->user_function_name_list ();
+	  string_vector fcns = symbol_table::user_function_names ();
 
 	  int fcount = fcns.length ();
 
@@ -2222,40 +2085,29 @@
 	      std::string nm = fcns[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_function (nm);
+		symbol_table::clear_function (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_function_pattern (argv[idx++]);
+	    symbol_table::clear_function_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_globals (const string_vector& argv, int argc, int idx,
 		  bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_globals ();
+    symbol_table::clear_variables(symbol_table::global_scope ());
   else
     {
       if (exclusive)
 	{
-	  string_vector lvars = curr_sym_tab->global_variable_name_list ();
-
-	  int lcount = lvars.length ();
-
-	  for (int i = 0; i < lcount; i++)
-	    {
-	      std::string nm = lvars[i];
-
-	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_global (nm);
-	    }
-
-	  string_vector gvars = global_sym_tab->global_variable_name_list ();
+	  string_vector gvars
+	    = symbol_table::variable_names (symbol_table::global_scope ());
 
 	  int gcount = gvars.length ();
 
@@ -2264,28 +2116,28 @@
 	      std::string nm = gvars[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_global (nm);
+		symbol_table::clear_global (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_global_pattern (argv[idx++]);
+	    symbol_table::clear_global_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_variables (const string_vector& argv, int argc, int idx,
 		    bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_variables ();
+    symbol_table::clear_variables ();
   else
     {
       if (exclusive)
 	{
-	  string_vector lvars = curr_sym_tab->variable_name_list ();
+	  string_vector lvars = symbol_table::variable_names ();
 
 	  int lcount = lvars.length ();
 
@@ -2294,23 +2146,23 @@
 	      std::string nm = lvars[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_variable (nm);
+		symbol_table::clear_variable (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_variable_pattern (argv[idx++]);
+	    symbol_table::clear_variable_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_symbols (const string_vector& argv, int argc, int idx,
 		  bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_variables ();
+    symbol_table::clear_variables ();
   else
     {
       if (exclusive)
@@ -2326,7 +2178,7 @@
       else
 	{
 	  while (idx < argc)
-	    do_clear_symbol_pattern (argv[idx++]);
+	    symbol_table::clear_symbol_pattern (argv[idx++]);
 	}
     }
 }
@@ -2338,25 +2190,29 @@
 
   for (; idx < argc; idx++)
     {
-      if (argv[idx] == "all" && ! is_local_variable ("all"))
+      if (argv[idx] == "all"
+	  && ! symbol_table::is_local_variable ("all"))
 	{
-	  do_clear_all ();
+	  symbol_table::clear_all ();
 	}
-      else if (argv[idx] == "functions" && ! is_local_variable ("functions"))
+      else if (argv[idx] == "functions"
+	       && ! symbol_table::is_local_variable ("functions"))
 	{
 	  do_clear_functions (argv, argc, ++idx);
 	}
-      else if (argv[idx] == "global" && ! is_local_variable ("global"))
+      else if (argv[idx] == "global"
+	       && ! symbol_table::is_local_variable ("global"))
 	{
 	  do_clear_globals (argv, argc, ++idx);
 	}
-      else if (argv[idx] == "variables" && ! is_local_variable ("variables"))
+      else if (argv[idx] == "variables"
+	       && ! symbol_table::is_local_variable ("variables"))
 	{
-	  do_clear_variables ();
+	  symbol_table::clear_variables ();
 	}
       else
 	{
-	  do_clear_symbol_pattern (argv[idx]);
+	  symbol_table::clear_symbol_pattern (argv[idx]);
 	}
     }
 }
@@ -2372,24 +2228,6 @@
     } \
   while (0)
 
-bool
-clear_function (const std::string& nm)
-{
-  return do_clear_function (nm);
-}
-
-bool
-clear_variable (const std::string& nm)
-{
-  return do_clear_variable (nm);
-}
-
-bool
-clear_symbol (const std::string& nm)
-{
-  return do_clear_symbol (nm);
-}
-
 DEFCMD (clear, args, ,
   "-*- texinfo -*-\n\
 @deffn {Command} clear [-x] pattern @dots{}\n\
@@ -2443,7 +2281,7 @@
     {
       if (argc == 1)
 	{
-	  do_clear_variables ();
+	  symbol_table::clear_variables ();
 	}
       else
 	{
@@ -2511,9 +2349,7 @@
 			warning
 			  ("clear: ignoring extra arguments after -all");
 
-		      curr_sym_tab->clear ();
-		      fbi_sym_tab->clear_functions ();
-		      global_sym_tab->clear ();
+		      symbol_table::clear_all ();
 		    }
 		  else if (clear_functions)
 		    {
@@ -2547,40 +2383,9 @@
 {
   octave_value_list retval;
 
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string arg = args(0).string_value ();
-
-      if (arg == "fbi")
-	fbi_sym_tab->print_info (octave_stdout);
-      else if (arg == "global")
-	global_sym_tab->print_info (octave_stdout);
-      else if (arg == "top-level")
-	top_level_sym_tab->print_info (octave_stdout);
-      else
-	{
-	  symbol_record *fsr = fbi_sym_tab->lookup (arg, true);
-
-	  if (fsr && fsr->is_user_function ())
-	    {
-	      octave_value tmp = fsr->def ();
-	      const octave_base_value& rep = tmp.get_rep ();
-	      
-	      const octave_user_function& fcn
-		= dynamic_cast<const octave_user_function&> (rep);
-
-	      fcn.print_symtab_info (octave_stdout);
-	    }
-	  else
-	    error ("no user-defined function named %s", arg.c_str ());
-	}
-    }
-  else if (nargin == 0)
-    curr_sym_tab->print_info (octave_stdout);
-  else
-    print_usage ();
+  // FIXME -- what should this function do now?  Print a summary for
+  // each scope?  Print the entire symbol table?  Accept a scope
+  // argument?
 
   return retval;
 }
@@ -2593,92 +2398,67 @@
 {
   octave_value_list retval;
 
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string symbol_name = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  symbol_record *sr = curr_sym_tab->lookup (symbol_name);
-
-	  if (sr)
-	    sr->print_info (octave_stdout);
-	  else
-	    error ("__print_symbol_info__: symbol %s not found",
-		   symbol_name.c_str ());
-	}
-      else
-	print_usage ();
-    }
-  else
-    print_usage ();
+  // FIXME -- what should this function do now?
 
   return retval;
 }
 
-DEFUN (ignore_function_time_stamp, args, nargout,
-    "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\
-Query or set the internal variable that controls whether Octave checks\n\
-the time stamp on files each time it looks up functions defined in\n\
-function files.  If the internal variable is set to @code{\"system\"},\n\
-Octave will not automatically recompile function files in subdirectories of\n\
-@file{@var{octave-home}/lib/@var{version}} if they have changed since\n\
-they were last compiled, but will recompile other function files in the\n\
-search path if they change.  If set to @code{\"all\"}, Octave will not\n\
-recompile any function files unless their definitions are removed with\n\
-@code{clear}.  If set to \"none\", Octave will always check time stamps\n\
-on files to determine whether functions defined in function files\n\
-need to be recompiled.\n\
+DEFUN (whos_line_format, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\
+@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\
+Query or set the format string used by the @code{whos}.\n\
+\n\
+The following escape sequences may be used in the format:\n\
+@table @code\n\
+@item %a\n\
+Prints attributes of variables (g=global, p=persistent,\n\
+f=formal parameter, a=automatic variable).\n\
+@item %b\n\
+Prints number of bytes occupied by variables.\n\
+@item %c\n\
+Prints class names of variables.\n\
+@item %e\n\
+Prints elements held by variables.\n\
+@item %n\n\
+Prints variable names.\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\
+\n\
+@example\n\
+%[modifier]<command>[:size_of_parameter[:center-specific[\n\
+       :print_dims[:balance]]]];\n\
+@end example\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\
+The default format is \"  %a:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\\n\".\n\
 @end deftypefn")
 {
-  octave_value retval;
-
-  if (nargout > 0)
-    {
-      switch (Vignore_function_time_stamp)
-	{
-	case 1:
-	  retval = "system";
-	  break;
-
-	case 2:
-	  retval = "all";
-	  break;
-
-	default:
-	  retval = "none";
-	  break;
-	}
-    }
-
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string sval = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  if (sval == "all")
-	    Vignore_function_time_stamp = 2;
-	  else if (sval == "system")
-	    Vignore_function_time_stamp = 1;
-	  else if (sval == "none")
-	    Vignore_function_time_stamp = 0;
-	  else
-	    error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\"");
-	}
-      else
-	error ("ignore_function_time_stamp: expecting argument to be character string");
-    }
-  else if (nargin > 1)
-    print_usage ();
-
-  return retval;
+  return SET_INTERNAL_VARIABLE (whos_line_format);
 }
 
 /*