diff src/help.cc @ 8575:f134925a1cfa

m-file implementation of help system
author Soren Hauberg <soren@hauberg.org>
date Thu, 22 Jan 2009 18:22:52 -0500
parents 8ba2ee57c594
children 540165304f00
line wrap: on
line diff
--- a/src/help.cc	Thu Jan 22 13:59:33 2009 -0500
+++ b/src/help.cc	Thu Jan 22 18:22:52 2009 -0500
@@ -86,258 +86,259 @@
 // functions.
 static bool Vsuppress_verbose_help_message = false;
 
-// FIXME -- maybe this should use string instead of char*.
+#include <map>
 
-struct help_list
-{
-  const char *name;
-  const char *help;
-};
+typedef std::map<std::string, std::string> map_type;
+typedef map_type::value_type pair_type;
+typedef map_type::const_iterator map_iter;
 
-static help_list operators[] =
+template<typename T, std::size_t z>
+std::size_t
+size (T const (&)[z])
 {
-  { "!",
-    "Logical not operator.  See also `~'.\n", },
+  return z;
+}
 
-  { "!=",
-    "Logical not equals operator.  See also `~' and `<>'.\n", },
+// FIXME -- The descriptions could easily be in texinfo -- should they?
+const static pair_type operators[] =
+{
+  pair_type ("!",
+    "Logical not operator.  See also `~'.\n"),
 
-  { "\"",
-    "String delimiter.\n", },
+  pair_type ("!=",
+    "Logical not equals operator.  See also `~='.\n"),
 
-  { "#",
-    "Begin comment character.  See also `%'.", },
+  pair_type ("\"",
+    "String delimiter.\n"),
+
+  pair_type ("#",
+    "Begin comment character.  See also `%'."),
 
-  { "%",
-    "Begin comment charcter.  See also `#'.", },
+  pair_type ("%",
+    "Begin comment charcter.  See also `#'."),
 
-  { "&",
-    "Logical and operator.  See also `&&'.", },
+  pair_type ("&",
+    "Element by element logical and operator.  See also `&&'."),
 
-  { "&&",
-    "Logical and operator.  See also `&'.", },
+  pair_type ("&&",
+    "Logical and operator (with short-circuit evaluation).  See also `&'."),
 
-  { "'",
+  pair_type ("'",
     "Matrix transpose operator.  For complex matrices, computes the\n\
 complex conjugate (Hermitian) transpose.  See also `.''\n\
 \n\
 The single quote character may also be used to delimit strings, but\n\
 it is better to use the double quote character, since that is never\n\
-ambiguous", },
-
-  { "(",
-    "Array index or function argument delimiter.", },
+ambiguous"),
 
-  { ")",
-    "Array index or function argument delimiter.", },
+  pair_type ("(",
+    "Array index or function argument delimiter."),
 
-  { "*",
-    "Multiplication operator.  See also `.*'", },
+  pair_type (")",
+    "Array index or function argument delimiter."),
 
-  { "**",
-    "Power operator.  See also `^', `.**', and `.^'", },
+  pair_type ("*",
+    "Multiplication operator.  See also `.*'"),
 
-  { "+",
-    "Addition operator.", },
+  pair_type ("**",
+    "Power operator.  See also `^', `.**', and `.^'"),
 
-  { "++",
+  pair_type ("+",
+    "Addition operator."),
+
+  pair_type ("++",
     "Increment operator.  As in C, may be applied as a prefix or postfix\n\
-operator.", },
-
-  { ",",
-    "Array index, function argument, or command separator.", },
+operator."),
 
-  { "-",
-    "Subtraction or unary negation operator.", },
+  pair_type (",",
+    "Array index, function argument, or command separator."),
 
-  { "--",
+  pair_type ("-",
+    "Subtraction or unary negation operator."),
+
+  pair_type ("--",
     "Decrement operator.  As in C, may be applied as a prefix or postfix\n\
-operator.", },
-
-  { ".'",
-    "Matrix transpose operator.  For complex matrices, computes the\n\
-transpose, *not* the complex conjugate transpose.  See also `''.", },
+operator."),
 
-  { ".*",
-    "Element by element multiplication operator.  See also `*'.", },
+  pair_type (".'",
+    "Matrix transpose operator.  For complex matrices, computes the\n\
+transpose, *not* the complex conjugate transpose.  See also `''."),
 
-  { ".**",
-    "Element by element power operator.  See also `**', `^', and `.^'.", },
+  pair_type (".*",
+    "Element by element multiplication operator.  See also `*'."),
 
-  { "./",
-    "Element by element division operator.  See also `/' and `\\'.", },
+  pair_type (".**",
+    "Element by element power operator.  See also `**', `^', and `.^'."),
 
-  { ".^",
-    "Element by element power operator.  See also `**', `^', and `.^'.", },
+  pair_type ("./",
+    "Element by element division operator.  See also `/' and `\\'."),
 
-  { "/",
-    "Right division.  See also `\\' and `./'.", },
+  pair_type (".^",
+    "Element by element power operator.  See also `**', `^', and `.^'."),
 
-  { ":",
-    "Select entire rows or columns of matrices.", },
+  pair_type ("/",
+    "Right division.  See also `\\' and `./'."),
 
-  { ";",
-    "Array row or command separator.  See also `,'.", },
+  pair_type (":",
+    "Select entire rows or columns of matrices."),
 
-  { "<",
-    "Less than operator.", },
+  pair_type (";",
+    "Array row or command separator.  See also `,'."),
 
-  { "<=",
-    "Less than or equals operator.", },
+  pair_type ("<",
+    "Less than operator."),
 
-  { "<>",
-    "Logical not equals operator.  See also `!=' and `~='.", },
+  pair_type ("<=",
+    "Less than or equals operator."),
 
-  { "=",
-    "Assignment operator.", },
+  pair_type ("=",
+    "Assignment operator."),
 
-  { "==",
-    "Equality test operator.", },
+  pair_type ("==",
+    "Equality test operator."),
 
-  { ">",
-    "Greater than operator.", },
+  pair_type (">",
+    "Greater than operator."),
 
-  { ">=",
-    "Greater than or equals operator.", },
+  pair_type (">=",
+    "Greater than or equals operator."),
 
-  { "[",
-    "Return list delimiter.  See also `]'.", },
+  pair_type ("[",
+    "Return list delimiter.  See also `]'."),
 
-  { "\\",
-    "Left division operator.  See also `/' and `./'.", },
+  pair_type ("\\",
+    "Left division operator.  See also `/' and `./'."),
 
-  { "]",
-    "Return list delimiter.  See also `['.", },
+  pair_type ("]",
+    "Return list delimiter.  See also `['."),
 
-  { "^",
-    "Power operator.  See also `**', `.^', and `.**.'", },
+  pair_type ("^",
+    "Power operator.  See also `**', `.^', and `.**.'"),
 
-  { "|",
-    "Logical or operator.  See also `||'.", },
+  pair_type ("|",
+    "Element by element logical or operator.  See also `||'."),
 
-  { "||",
-    "Logical or operator.  See also `|'.", },
+  pair_type ("||",
+    "Logical or operator (with short-circuit evaluation).  See also `|'."),
 
-  { "~",
-    "Logical not operator.  See also `!' and `~'.", },
+  pair_type ("~",
+    "Logical not operator.  See also `!' and `~'."),
 
-  { "~=",
-    "Logical not equals operator.  See also `<>' and `!='.", },
-
-  { 0, 0, },
+  pair_type ("~=",
+    "Logical not equals operator.  See also `!='."),
 };
 
-static help_list keywords[] =
+const static pair_type keywords[] =
 {
-  { "break",
+  pair_type ("break",
     "-*- texinfo -*-\n\
 @deffn Keyword break\n\
 Exit the innermost enclosing do, while or for loop.\n\
 @seealso{do, while, for, continue}\n\
-@end deffn", },
+@end deffn"),
 
-  { "case",
+  pair_type ("case",
     "-*- texinfo -*-\n\
 @deffn Keyword case @{@var{value}@}\n\
 A case statement in an switch. Octave cases are exclusive and do not\n\
 fall-through as do C-language cases. A switch statement must have at least\n\
 one case.  See @code{switch} for an example.\n\
 @seealso{switch}\n\
-@end deffn", },
+@end deffn"),
 
-  { "catch",
+  pair_type ("catch",
     "-*- texinfo -*-\n\
 @deffn Keyword catch\n\
 Begin the cleanup part of a try-catch block.\n\
 @seealso{try}\n\
-@end deffn", },
+@end deffn"),
 
-  { "continue",
+  pair_type ("continue",
     "-*- texinfo -*-\n\
 @deffn Keyword continue\n\
 Jump to the end of the innermost enclosing do, while or for loop.\n\
 @seealso{do, while, for, break}\n\
-@end deffn", },
+@end deffn"),
 
-  { "do",
+  pair_type ("do",
     "-*- texinfo -*-\n\
 @deffn Keyword do\n\
 Begin a do-until loop. This differs from a do-while loop in that the\n\
 body of the loop is executed at least once.\n\
 @seealso{while}\n\
-@end deffn", },
+@end deffn"),
 
-  { "else",
+  pair_type ("else",
     "-*- texinfo -*-\n\
 @deffn Keyword else\n\
 Alternate action for an if block.  See @code{if} for an example.\n\
 @seealso{if}\n\
-@end deffn", },
+@end deffn"),
 
-  { "elseif",
+  pair_type ("elseif",
     "-*- texinfo -*-\n\
 @deffn Keyword elseif (@var{condition})\n\
 Alternate conditional test for an if block.  See @code{if} for an example.\n\
 @seealso{if}\n\
-@end deffn", },
+@end deffn"),
 
-  { "end",
+  pair_type ("end",
     "-*- texinfo -*-\n\
 @deffn Keyword end\n\
 Mark the end of any @code{for}, @code{if}, @code{do}, @code{while}, or @code{function} block.\n\
 @seealso{for, if, do, while, function}\n\
-@end deffn", },
+@end deffn"),
 
-  { "end_try_catch",
+  pair_type ("end_try_catch",
     "-*- texinfo -*-\n\
 @deffn Keyword end_try_catch\n\
 Mark the end of an @code{try-catch} block.\n\
 @seealso{try, catch}\n\
-@end deffn", }, 
+@end deffn"), 
 
-  { "end_unwind_protect",
+  pair_type ("end_unwind_protect",
     "-*- texinfo -*-\n\
 @deffn Keyword end_unwind_protect\n\
 Mark the end of an unwind_protect block.\n\
 @seealso{unwind_protect}\n\
-@end deffn", }, 
+@end deffn"), 
 
-  { "endfor",
+  pair_type ("endfor",
     "-*- texinfo -*-\n\
 @deffn Keyword endfor\n\
 Mark the end of a for loop.  See @code{for} for an example.\n\
 @seealso{for}\n\
-@end deffn", },
+@end deffn"),
 
-  { "endfunction",
+  pair_type ("endfunction",
     "-*- texinfo -*-\n\
 @deffn Keyword endfunction\n\
 Mark the end of a function.\n\
 @seealso{function}\n\
-@end deffn", },
+@end deffn"),
 
-  { "endif",
+  pair_type ("endif",
     "-*- texinfo -*-\n\
 @deffn Keyword endif\n\
 Mark the end of an if block.  See @code{if} for an example.\n\
 @seealso{if}\n\
-@end deffn", },
+@end deffn"),
 
-  { "endswitch",
+  pair_type ("endswitch",
     "-*- texinfo -*-\n\
 @deffn Keyword endswitch\n\
 Mark the end of a switch block.  See @code{switch} for an example.\n\
 @seealso{switch}\n\
-@end deffn", },
+@end deffn"),
 
-  { "endwhile",
+  pair_type ("endwhile",
     "-*- texinfo -*-\n\
 @deffn Keyword endwhile\n\
 Mark the end of a while loop.  See @code{while} for an example.\n\
 @seealso{do, while}\n\
-@end deffn", },
+@end deffn"),
 
-  { "for",
+  pair_type ("for",
     "-*- texinfo -*-\n\
 @deffn Keyword for @var{i} = @var{range}\n\
 Begin a for loop.\n\
@@ -347,9 +348,9 @@
 endfor\n\
 @end example\n\
 @seealso{do, while}\n\
-@end deffn", },
+@end deffn"),
 
-  { "function",
+  pair_type ("function",
     "-*- texinfo -*-\n\
 @deffn Keyword function @var{outputs} = function (@var{input}, ...)\n\
 @deffnx Keyword function {} function (@var{input}, ...)\n\
@@ -357,9 +358,9 @@
 Begin a function body with @var{outputs} as results and @var{inputs} as\n\
 parameters.\n\
 @seealso{return}\n\
-@end deffn", },
+@end deffn"),
 
-  { "global",
+  pair_type ("global",
     "-*- texinfo -*-\n\
 @deffn Keyword global\n\
 Declare variables to have global scope.\n\
@@ -370,9 +371,9 @@
 endif\n\
 @end example\n\
 @seealso{persistent}\n\
-@end deffn", },
+@end deffn"),
 
-  { "if",
+  pair_type ("if",
     "-*- texinfo -*-\n\
 @deffn Keyword if (@var{cond}) @dots{} endif\n\
 @deffnx Keyword if (@var{cond}) @dots{} else @dots{} endif\n\
@@ -390,16 +391,16 @@
 endif\n\
 @end example\n\
 @seealso{switch}\n\
-@end deffn", },
+@end deffn"),
 
-  { "otherwise",
+  pair_type ("otherwise",
     "-*- texinfo -*-\n\
 @deffn Keyword otherwise\n\
 The default statement in a switch block (similar to else in an if block).\n\
 @seealso{switch}\n\
-@end deffn", },
+@end deffn"),
 
-  { "persistent",
+  pair_type ("persistent",
     "-*- texinfo -*-\n\
 @deffn Keyword persistent @var{var}\n\
 Declare variables as persistent.  A variable that has been declared\n\
@@ -408,30 +409,30 @@
 variables and global variables is that persistent variables are local in \n\
 scope to a particular function and are not visible elsewhere.\n\
 @seealso{global}\n\
-@end deffn", },
+@end deffn"),
 
-  { "replot",
+  pair_type ("replot",
     "-*- texinfo -*-\n\
 @deffn Keyword replot\n\
 Replot a graphic.\n\
 @seealso{plot}\n\
-@end deffn", },
+@end deffn"),
 
-  { "return",
+  pair_type ("return",
     "-*- texinfo -*-\n\
 @deffn Keyword return\n\
 Return from a function.\n\
 @seealso{function}\n\
-@end deffn", },
+@end deffn"),
 
-  { "static",
+  pair_type ("static",
     "-*- texinfo -*-\n\
 @deffn Keyword static\n\
 This function has been deprecated in favor of persistent.\n\
 @seealso{persistent}\n\
-@end deffn", },
+@end deffn"),
 
-  { "switch",
+  pair_type ("switch",
     "-*- texinfo -*-\n\
 @deffn Keyword switch @var{statement}\n\
 Begin a switch block.\n\
@@ -448,9 +449,9 @@
 endswitch\n\
 @end example\n\
 @seealso{if, case, otherwise}\n\
-@end deffn", },
+@end deffn"),
 
-  { "try",
+  pair_type ("try",
     "-*- texinfo -*-\n\
 @deffn Keyword try\n\
 Begin a try-catch block.\n\
@@ -460,16 +461,16 @@
 recommended to use the lasterr function to re-throw the error after cleanup\n\
 is completed).\n\
 @seealso{catch,unwind_protect}\n\
-@end deffn", }, 
+@end deffn"), 
 
-  { "until",
+  pair_type ("until",
     "-*- texinfo -*-\n\
 @deffn Keyword until\n\
 End a do-until loop.\n\
 @seealso{do}\n\
-@end deffn", },
+@end deffn"),
 
-  { "unwind_protect",
+  pair_type ("unwind_protect",
     "-*- texinfo -*-\n\
 @deffn Keyword unwind_protect\n\
 Begin an unwind_protect block.\n\
@@ -481,112 +482,82 @@
 unwind_protect_cleanup will be run with or without an error in the\n\
 unwind_protect block).\n\
 @seealso{unwind_protect_cleanup,try}\n\
-@end deffn", }, 
+@end deffn"), 
 
-  { "unwind_protect_cleanup",
+  pair_type ("unwind_protect_cleanup",
     "-*- texinfo -*-\n\
 @deffn Keyword unwind_protect_cleanup\n\
 Begin the cleanup section of an unwind_protect block.\n\
 @seealso{unwind_protect}\n\
-@end deffn", }, 
+@end deffn"), 
 
-  { "varargin",
+  pair_type ("varargin",
     "-*- texinfo -*-\n\
 @deffn Keyword varargin\n\
 Pass an arbitrary number of arguments into a function.\n\
 @seealso{varargout, nargin, nargout}\n\
-@end deffn", },
+@end deffn"),
 
-  { "varargout",
+  pair_type ("varargout",
     "-*- texinfo -*-\n\
 @deffn Keyword varargout\n\
 Pass an arbitrary number of arguments out of a function.\n\
 @seealso{varargin, nargin, nargout}\n\
-@end deffn", },
+@end deffn"),
 
-  { "while",
+  pair_type ("while",
     "-*- texinfo -*-\n\
 @deffn Keyword while\n\
 Begin a while loop.\n\
 @seealso{do}\n\
-@end deffn", },
-
-  { 0, 0, },
+@end deffn"),
 };
 
 // Return a copy of the operator or keyword names.
-
 static string_vector
-names (help_list *lst)
+names (const map_type& lst)
 {
-  string_vector retval;
-
-  int count = 0;
-  help_list *ptr = lst;
-  while (ptr->name)
-    {
-      count++;
-      ptr++;
-    }
-
-  if (count > 0)
-    {
-      retval.resize (count);
-
-      ptr = lst;
-      for (int i = 0; i < count; i++)
-	{
-	  retval[i] = ptr->name;
-	  ptr++;
-	}
-    }
-
+  string_vector retval (lst.size ());
+  int j = 0;
+  for (map_iter iter = lst.begin (); iter != lst.end (); iter ++)
+    retval [j++] = iter->first;
   return retval;
 }
 
-static help_list *
-operator_help (void)
-{
-  return operators;
-}
+const static map_type operators_map (operators, operators + size (operators));
+const static map_type keywords_map (keywords, keywords + size (keywords));
+const static string_vector keyword_names = names (keywords_map);
 
-static help_list *
-keyword_help (void)
-{
-  return keywords;
-}
-
-// It's not likely that this does the right thing now.  FIXME
+// FIXME -- It's not likely that this does the right thing now.
 
 string_vector
 make_name_list (void)
 {
-  string_vector key = names (keyword_help ());
-  int key_len = key.length ();
+  const int key_len = keyword_names.length ();
 
-  string_vector bif = symbol_table::built_in_function_names ();
-  int bif_len = bif.length ();
+  const string_vector bif = symbol_table::built_in_function_names ();
+  const int bif_len = bif.length ();
 
   // FIXME -- is this really necessary here?
-  string_vector glb = symbol_table::global_variable_names ();
-  int glb_len = glb.length ();
+  const string_vector glb = symbol_table::global_variable_names ();
+  const int glb_len = glb.length ();
 
   // FIXME -- is this really necessary here?
-  string_vector top = symbol_table::top_level_variable_names ();
-  int top_len = top.length ();
+  const string_vector top = symbol_table::top_level_variable_names ();
+  const int top_len = top.length ();
 
   string_vector lcl;
   if (! symbol_table::at_top_level ())
     lcl = symbol_table::variable_names ();
-  int lcl_len = lcl.length ();
+  const int lcl_len = lcl.length ();
 
-  string_vector ffl = load_path::fcn_names ();
-  int ffl_len = ffl.length ();
+  const string_vector ffl = load_path::fcn_names ();
+  const int ffl_len = ffl.length ();
 
-  string_vector afl = autoloaded_functions ();
-  int afl_len = afl.length ();
+  const string_vector afl = autoloaded_functions ();
+  const int afl_len = afl.length ();
 
-  int total_len = key_len + bif_len + glb_len + top_len + lcl_len
+  const int total_len = key_len + bif_len + glb_len + top_len + lcl_len
     + ffl_len + afl_len;
 
   string_vector list (total_len);
@@ -596,7 +567,7 @@
   int j = 0;
   int i = 0;
   for (i = 0; i < key_len; i++)
-    list[j++] = key[i];
+    list[j++] = keyword_names[i];
 
   for (i = 0; i < bif_len; i++)
     list[j++] = bif[i];
@@ -619,121 +590,14 @@
   return list;
 }
 
-void
-additional_help_message (std::ostream& os)
-{
-  if (! Vsuppress_verbose_help_message)
-    os << "\
-Additional help for built-in functions and operators is\n\
-available in the on-line version of the manual.  Use the command\n\
-`doc <topic>' to search the manual index.\n\
-\n\
-Help and information about Octave is also available on the WWW\n\
-at http://www.octave.org and via the help@octave.org\n\
-mailing list.\n"; 
-}
-
-// FIXME -- this needs a major overhaul to cope with new
-// symbol table stuff.
-
-static void
-display_names_from_help_list (std::ostream& os, help_list *list,
-			      const char *desc)
-{
-  string_vector symbols = names (list);
-
-  if (! symbols.empty ())
-    {
-      os << "\n*** " << desc << ":\n\n";
-
-      symbols.sort ();
-
-      symbols.list_in_columns (os);
-    }
-}
-
-static void
-display_symtab_names (std::ostream& os, const std::list<std::string>& names,
-		      const std::string& desc)
-{
-  if (! names.empty ())
-    {
-      os << "\n*** " << desc << ":\n\n";
-
-      string_vector sv (names);
-
-      sv.list_in_columns (os);
-    }
-}
-
-static void
-simple_help (void)
+static bool
+looks_like_html (const std::string& msg)
 {
-  octave_stdout << "Help is available for the topics listed below.\n";
-
-  additional_help_message (octave_stdout);
-
-  display_names_from_help_list (octave_stdout, operator_help (),
-				"operators");
-
-  display_names_from_help_list (octave_stdout, keyword_help (),
-				"reserved words");
-
-  display_symtab_names (octave_stdout,
-			symbol_table::built_in_function_names (),
-			"built-in functions");
-
-  // FIXME -- list functions defined on command line?
-
-  load_path::display (octave_stdout);
-
-  string_vector autoloaded = autoloaded_functions ();
-
-  if (! autoloaded.empty ())
-    {
-      octave_stdout << "\n*** autoloaded functions:\n\n";
-
-      autoloaded.sort ();
-
-      autoloaded.list_in_columns (octave_stdout);
-    }
-}
-
-static int
-try_info (const std::string& nm)
-{
-  int retval = -1;
-
-  warning ("please use `doc' instead of `help -i'");
-
-  octave_value_list args;
-  args(0) = nm;
-  octave_value_list result = feval ("doc", args, 1);
-
-  if (result.length () > 0)
-    retval = result(0).int_value ();
-
-  return retval;
-}
-
-static void
-help_from_info (const string_vector& argv, int idx, int argc)
-{
-  if (idx == argc)
-    try_info (std::string ());
-  else
-    {
-      for (int i = idx; i < argc; i++)
-	{
-	  int status = try_info (argv[i]);
-
-	  if (status == 127)
-	    break;
-	  else if (status != 0)
-	    message ("help", "`%s' is not indexed in the manual",
-		     argv[i].c_str ());
-	}
-    }
+  const size_t p1 = msg.find ('\n');
+  std::string t = msg.substr (0, p1);
+  const size_t p2 = t.find ("<html"); // FIXME: this comparison should be case-insensitive
+  
+   return (p2 != std::string::npos);
 }
 
 static bool
@@ -751,187 +615,6 @@
   return (p2 != std::string::npos);
 }
 
-void
-display_help_text (std::ostream& os, const std::string& msg)
-{
-  // Look for "-*- texinfo -*-" in first line of help message.  If it
-  // is present, use makeinfo to format the rest of the message before
-  // sending it to the output stream.  Otherwise, just print the
-  // message.
-
-  size_t pos;
-
-  if (looks_like_texinfo (msg, pos))
-    {
-      os.flush ();
-
-      std::string tmp_file_name = file_ops::tempnam ("", "");
-
-      int cols = command_editor::terminal_cols ();
-
-      if (cols > 16)
-	cols--;
-
-      if (cols > 64)
-	cols -= 7;
-
-      if (cols > 80)
-	cols = 72;
-
-      std::ostringstream buf;
-
-      // Use double quotes to quote the sed patterns for Windows.
-
-      buf << "sed -e \"s/^[#%][#%]* *//\" -e \"s/^ *@/@/\" | "
-	  << "\"" << Vmakeinfo_program << "\""
-	  << " -D \"VERSION " << OCTAVE_VERSION << "\""
-	  << " -D \"OCTAVEHOME " << OCTAVE_PREFIX << "\""
-	  << " -D \"TARGETHOSTTYPE " << OCTAVE_CANONICAL_HOST_TYPE << "\""
-	  << " --fill-column " << cols
-	  << " --no-warn"
-	  << " --no-validate"
-	  << " --no-headers"
-	  << " --force"
-	  << " --output \"" << tmp_file_name << "\"";
-
-      oprocstream filter (buf.str ());
-
-      if (filter && filter.is_open ())
-	{
-	  filter << "@macro seealso {args}\n"
-		 << "@sp 1\n"
-		 << "@noindent\n"
-		 << "See also: \\args\\.\n"
-                 << "@end macro\n";
-
-	  filter << msg.substr (pos+1) << std::endl;
-
-	  int status = filter.close ();
-
-	  std::ifstream tmp_file (tmp_file_name.c_str ());
-
-	  if (WIFEXITED (status) && WEXITSTATUS (status) == 0)
-	    {
-	      int c;
-	      while ((c = tmp_file.get ()) != EOF)
-		os << (char) c;
-
-	      tmp_file.close ();
-	    }
-	  else
-	    {
-	      warning ("help: Texinfo formatting filter exited abnormally");
-	      warning ("help: raw Texinfo source of help text follows...");
-	      warning ("help:\n\n%s\n\n", msg.c_str ());
-	    }
-
-	  file_ops::unlink (tmp_file_name);
-	}
-      else
-	os << msg;
-    }
-  else
-    os << msg;
-}
-
-void
-display_usage_text (std::ostream& os, const std::string& msg)
-{
-  std::string filtered_msg = msg;
-
-  size_t pos;
-
-  if (looks_like_texinfo (msg, pos))
-    {
-      std::ostringstream buf;
-
-      buf << "-*- texinfo -*-\n";
-
-      bool found_def = false;
-
-      size_t msg_len = msg.length ();
-
-      while (pos < msg_len)
-	{
-	  size_t new_pos = msg.find_first_of ('\n', pos);
-
-	  if (new_pos == std::string::npos)
-	    new_pos = msg_len-1;
-
-	  std::string line = msg.substr (pos, new_pos-pos+1);
-
-	  if (line.substr (0, 4) == "@def"
-	      || line.substr (0, 8) == "@end def")
-	    {
-	      found_def = true;
-	      buf << line;
-	    }
-
-	  pos = new_pos + 1;
-	}
-
-      if (found_def)
-	filtered_msg = buf.str ();
-    }
-
-  display_help_text (os, filtered_msg);
-}
-
-static bool
-raw_help_from_list (const help_list *list, const std::string& nm, 
-		    std::string& h, bool& symbol_found)
-{
-  bool retval = false;
-
-  const char *name;
-
-  while ((name = list->name) != 0)
-    {
-      if (strcmp (name, nm.c_str ()) == 0)
-	{
-	  symbol_found = true;
-
-	  h = list->help;
-
-	  if (h.length () > 0)
-	    retval = true;
-
-	  break;
-	}
-      list++;
-    }
-
-  return retval;;
-}
-
-static bool
-help_from_list (std::ostream& os, const help_list *list,
-		const std::string& nm, int usage, bool& symbol_found)
-{
-  bool retval = false;
-
-  std::string h;
-
-  if (raw_help_from_list (list, nm, h, symbol_found))
-    {
-      if (h.length () > 0)
-	{
-	  if (usage)
-	    os << "\nusage: ";
-	  else
-	    os << "\n*** " << nm << ":\n\n";
-
-	  display_help_text (os, h);
-
-	  os << "\n";
-
-	  retval = true;
-	}
-    }
-
-  return retval;
-}
-
 static bool
 raw_help_from_symbol_table (const std::string& nm, std::string& h, 
 			    std::string& w, bool& symbol_found)
@@ -967,45 +650,6 @@
 }
 
 static bool
-help_from_symbol_table (std::ostream& os, const std::string& nm,
-			bool& symbol_found)
-{
-  bool retval = false;
-
-  std::string h;
-  std::string w;
-
-  if (raw_help_from_symbol_table (nm, h, w, symbol_found))
-    {
-      if (h.length () > 0)
-	{
-	  std::string dispatch_help = symbol_table::help_for_dispatch (nm);
-
-	  if (! dispatch_help.empty ())
-	    {
-	      size_t pos = 0;
-
-	      std::string pfx = looks_like_texinfo (h, pos)
-		? std::string ("\n\n@noindent\n") : std::string ("\n\n");
-
-	      h += pfx + dispatch_help;
-	    }
-
-	  display_help_text (os, h);
-
-	  if (w.length () > 0 && ! Vsuppress_verbose_help_message)
-	    os << w << "\n";
-
-	  os << "\n";
-
-	  retval = true;
-	}
-    }
-
-  return retval;
-}
-
-static bool
 raw_help_from_file (const std::string& nm, std::string& h, 
 		    std::string& file, bool& symbol_found)
 {
@@ -1032,334 +676,134 @@
 }
 
 static bool
-help_from_file (std::ostream& os, const std::string& nm, bool& symbol_found)
+raw_help_from_map (const std::string& nm, std::string& h, 
+		   const map_type& map, bool& symbol_found)
 {
-  bool retval = false;
-
-  std::string h;
-  std::string file;
-
-  if (raw_help_from_file (nm, h, file, symbol_found))
-    {
-      if (h.length () > 0)
-	{
-	  // Strip extension
-	  size_t l = file.length ();
-	  if (l > 2 && file.substr (l-2) == ".m")
-	    {
-	      std::string tmp = file.substr (0, l - 2);
-
-	      if (file_stat (tmp + ".oct"))
-		file = tmp + ".oct";
-	      else if (file_stat (tmp + ".mex"))
-		file = tmp + ".mex";
-	    }
-
-	  os << nm << " is the file " << file << "\n\n";
-
-	  display_help_text (os, h);
-
-	  os << "\n";
-
-	  retval = true;
-	}
-    }
-
-  return retval;
+  map_iter idx = map.find (nm);
+  symbol_found = (idx != map.end ());
+  h = (symbol_found) ? idx->second : "";
+  return symbol_found;
 }
 
 std::string
-raw_help (const std::string& nm, bool &symbol_found)
+raw_help (const std::string& nm, bool& symbol_found)
 {
   std::string h;
   std::string w;
   std::string f;
 
-  (raw_help_from_list (operator_help (), nm, h, symbol_found)
-   || raw_help_from_list (keyword_help (), nm, h, symbol_found)
-   || raw_help_from_symbol_table (nm, h, w, symbol_found)
-   || raw_help_from_file (nm, h, f, symbol_found));
+  (raw_help_from_symbol_table (nm, h, w, symbol_found)
+   || raw_help_from_file (nm, h, f, symbol_found)
+   || raw_help_from_map (nm, h, operators_map, symbol_found)
+   || raw_help_from_map (nm, h, keywords_map, symbol_found));
 
   return h;
 }
 
 static void
-builtin_help (int argc, const string_vector& argv)
+do_get_help_text (const std::string name, std::string& text,
+		  std::string& format)
 {
-  help_list *op_help_list = operator_help ();
-  help_list *kw_help_list = keyword_help ();
-
-  for (int i = 1; i < argc; i++)
+  bool symbol_found = false;
+  text = raw_help (name, symbol_found);
+  
+  format = "Not found";
+  if (symbol_found)
     {
-      bool symbol_found = false;
-
-      if (help_from_list (octave_stdout, op_help_list, argv[i], 0,
-			  symbol_found))
-	continue;
-
-      if (help_from_list (octave_stdout, kw_help_list, argv[i], 0,
-			  symbol_found))
-	continue;
-
-      if (help_from_symbol_table (octave_stdout, argv[i], symbol_found))
-	continue;
-
-      if (error_state)
-	{
-	  octave_stdout << "\n";
-	  error_state = 0;
-	  continue;
-	}
-
-      if (help_from_file (octave_stdout, argv[i], symbol_found))
-	continue;
-
-      if (error_state)
-	{
-	  octave_stdout << "\n";
-	  error_state = 0;
-	  continue;
-	}
-
-      if (symbol_found)
-	octave_stdout << "\nhelp: `" << argv[i]
-		      << "' is not documented\n"; 
+      size_t idx = -1;
+      if (looks_like_texinfo (text, idx))
+        {
+          format = "texinfo";
+          text.erase (0, idx);
+        }
+      else if (looks_like_html (text))
+        {
+          format = "html";
+        }
       else
-	octave_stdout << "\nhelp: `" << argv[i]
-		      << "' not found\n"; 
+        {
+          format = "plain text";
+        }
     }
-  
-  additional_help_message (octave_stdout);
 }
 
-DEFCMD (help, args, ,
-  "-*- texinfo -*-\n\
-@deffn {Command} help @var{name}\n\
-Display the help text for @var{name}.\n\
-If invoked without any arguments, @code{help} prints a list\n\
-of all the available operators and functions.\n\
+DEFUN (get_help_text, args, , "-*- texinfo -*-\n\
+@deftypefn {Loadable Function} {[@var{text}, @var{format}] =} get_help_text (@var{name})\n\
+Returns the help text of a given function.\n\
 \n\
-For example, the command @kbd{help help} prints a short message\n\
-describing the @code{help} command.\n\
+This function returns the raw help text @var{text} and an indication of\n\
+its format for the function @var{name}. The format indication @var{format}\n\
+is a string that can be either @t{\"texinfo\"}, @t{\"html\"}, or\n\
+@t{\"plain text\"}.\n\
 \n\
-The help command can give you information about operators, but not the\n\
-comma and semicolons that are used as command separators.  To get help\n\
-for those, you must type @kbd{help comma} or @kbd{help semicolon}.\n\
-@seealso{doc, which, lookfor}\n\
-@end deffn")
+To convert the help text to other formats, use the @code{makeinfo} function.\n\
+\n\
+@seealso{makeinfo}\n\
+@end deftypefn\n")
 {
   octave_value_list retval;
 
-  int argc = args.length () + 1;
+  if (args.length () == 1)
+    {
+      const std::string name = args (0).string_value ();
 
-  string_vector argv = args.make_argv ("help");
-
-  if (error_state)
-    return retval;
+      if (! error_state)
+	{
+	  std::string text;
+	  std::string format;
 
-  if (argc == 1)
-    simple_help ();
+	  do_get_help_text (name, text, format);
+  
+	  retval(1) = format;
+	  retval(0) = text;
+	}
+      else
+	error ("get_help_text: invalid input");
+    }
   else
-    {
-      if (argv[1] == "-i")
-	help_from_info (argv, 2, argc);
-      else
-	builtin_help (argc, argv);
-    }
+    print_usage ();
 
   return retval;
 }
 
-static void
-display_file (std::ostream& os, const std::string& name,
-	      const std::string& fname, const std::string& type,
-	      bool pr_type_info, bool quiet)
-{
-  std::ifstream fs (fname.c_str (), std::ios::in);
-
-  if (fs)
-    {
-      if (pr_type_info && ! quiet)
-	os << name << " is the " << type << " defined from the file\n"
-	   << fname << ":\n\n";
-
-      char ch;
-
-      while (fs.get (ch))
-	os << ch;
-    }
-  else
-    os << "unable to open `" << fname << "' for reading!\n";
-}
-
-static void
-do_type (std::ostream& os, const std::string& name, bool pr_type_info,
-	 bool quiet, bool pr_orig_txt)
+DEFUN (__operators__, , , "-*- texinfo -*-\n\
+@deftypefn {Function File} __operators__ ()\n\
+Return a cell array of strings containing the names of all operators.\n\
+\n\
+This is an internal function and should not be used directly.\n\
+@end deftypefn\n")
 {
-  // FIXME -- should we bother with variables here (earlier versions
-  // of Octave displayed them)?
-
-  octave_value val = symbol_table::varval (name);
-
-  if (val.is_defined ())
-    {
-      if (pr_type_info && ! quiet)
-	os << name << " is a variable\n";
-
-      val.print_raw (os, pr_orig_txt);
-
-      if (pr_type_info)
-	os << "\n";
-    }
-  else
-    {
-      val = symbol_table::find_function (name);
-
-      if (val.is_defined ())
-	{
-	  octave_function *fcn = val.function_value ();
-
-	  if (fcn)
-	    {
-	      std::string fn = fcn->fcn_file_name ();
-
-	      if (fcn->is_builtin_function ())
-		os << name << " is a built-in function" << std::endl;
-	      else if (fcn->is_dld_function () || fcn->is_mex_function ())
-		os << name
-		  << " is a dyanmically loaded function from the file\n"
-		   << fn << std::endl;
-	      else if (pr_orig_txt && ! fn.empty ())
-		display_file (os, name, fn,
-			      val.is_user_script () ? "script" : "function",
-			      pr_type_info, quiet);
-	      else
-		{
-		  if (pr_type_info && ! quiet)
-		    {
-		      os << name;
-
-		      if (fcn->is_user_function ())
-			{
-			  if (fn.empty ())
-			    os << " is a command-line function:\n\n";
-			  else
-			    os << " is a "
-			       << (val.is_user_script ()
-				   ? std::string ("script")
-				   : std::string ("function"))
-			       << " defined from the file\n"
-			       << fn << ":\n\n";
-			}
-		    }
-
-		  tree_print_code tpc (os, "", pr_orig_txt);
-
-		  fcn->accept (tpc);
-		}
-	    }
-	}
-    }
+  return octave_value (Cell (names (operators_map)));
 }
 
-DEFCMD (type, args, nargout,
-  "-*- texinfo -*-\n\
+DEFUN (__keywords__, , , "-*- texinfo -*-\n\
+@deftypefn {Function File} __keywords__ ()\n\
+Return a cell array of strings containing the names of all keywords.\n\
 \n\
-@deffn {Command} type options name @dots{}\n\
-Display the definition of each @var{name} that refers to a function.\n\
-\n\
-Normally also displays whether each @var{name} is user-defined or built-in;\n\
-the @code{-q} option suppresses this behaviour.\n\
-@end deffn")
+This is an internal function and should not be used directly.\n\
+@end deftypefn\n")
 {
-  octave_value retval;
-
-  int argc = args.length () + 1;
-
-  string_vector argv = args.make_argv ("type");
-
-  if (! error_state)
-    {
-      if (argc > 1)
-	{
-	  // FIXME -- we should really use getopt ()
-
-	  bool quiet = false;
-	  bool pr_orig_txt = true;
-
-	  int idx;
-
-	  for (idx = 1; idx < argc; idx++)
-	    {
-	      if (argv[idx] == "-q" || argv[idx] == "-quiet")
-		quiet = true;
-	      else if (argv[idx] == "-t" || argv[idx] == "-transformed")
-		pr_orig_txt = false;
-	      else
-		break;
-	    }
-
-	  if (idx < argc)
-	    {
-	      std::ostringstream output_buf;
-
-	      for (int i = idx; i < argc; i++)
-		{
-		  std::string id = argv[i];
-
-		  if (nargout == 0)
-		    do_type (octave_stdout, id, true, quiet, pr_orig_txt);
-		  else
-		    do_type (output_buf, id, false, quiet, pr_orig_txt);
-
-		  if (error_state)
-		    goto abort;
-		}
-
-	      if (nargout != 0)
-		retval = output_buf.str ();
-	    }
-	  else
-	    print_usage ();
-	}
-      else
-	print_usage ();
-    }
-
- abort:
-
-  return retval;
+  return octave_value (Cell (names (keywords_map)));
 }
 
-std::string
-do_which (const std::string& name)
+DEFUN (__builtins__, , , "-*- texinfo -*-\n\
+@deftypefn {Function File} __builtins__ ()\n\
+Return a cell array of strings containing the names of all builtin functions.\n\
+\n\
+This is an internal function and should not be used directly.\n\
+@end deftypefn\n")
 {
-  std::string retval;
-
-  octave_value val = symbol_table::find_function (name);
-
-  if (val.is_defined ())
-    {
-      octave_function *fcn = val.function_value ();
+  const string_vector bif = symbol_table::built_in_function_names ();
 
-      if (fcn)
-	{
-	  std::string fn = fcn->fcn_file_name ();
-
-	  retval = fn.empty ()
-	    ? (fcn->is_user_function ()
-	       ? "command-line function" : "built-in function")
-	    : fn;
-	}
-    }
-
-  return retval;
+  return octave_value (Cell (bif));
 }
 
-static void
-do_which (std::ostream& os, const std::string& name)
+static std::string
+do_which (const std::string& name, std::string& type)
 {
-  std::string desc;
+  std::string file;
+
+  type = std::string ();
 
   octave_value val = symbol_table::find_function (name);
 
@@ -1369,35 +813,43 @@
 
       if (fcn)
 	{
-	  desc = fcn->fcn_file_name ();
+	  file = fcn->fcn_file_name ();
 
-	  if (desc.empty ())
+	  if (file.empty ())
 	    {
 	      if (fcn->is_user_function ())
-		desc = "is a command-line function";
+		type = "command-line function";
 	      else
-		desc = "is a built-in function";
+		type = "built-in function";
 	    }
 	  else
-	    desc = "is the "
-	      + (val.is_user_script ()
-		 ? std::string ("script") : std::string ("function"))
-	      + " from the file " + desc;
+	    type = val.is_user_script ()
+	      ? std::string ("script") : std::string ("function");
 	}
-      
-      os << "which: `" << name << "' " << desc << std::endl;
     }
+
+  return file;
 }
 
-DEFCMD (which, args, nargout,
+std::string
+do_which (const std::string& name)
+{
+  std::string retval;
+
+  std::string type;
+
+  retval = do_which (name, type);
+
+  return retval;
+}
+
+DEFUN (__which__, args, ,
   "-*- texinfo -*-\n\
-@deffn {Command} which name @dots{}\n\
-Display the type of each @var{name}.  If @var{name} is defined from a\n\
-function file, the full name of the file is also displayed.\n\
-@seealso{help, lookfor}\n\
-@end deffn")
+@deftypefn {Built-in Function} {} __which__ (@var{name}, @dots{})\n\
+Undocumented internal function.\n\
+@end deftypefn")
 {
-  octave_value_list retval;
+  octave_value retval;
 
   string_vector argv = args.make_argv ("which");
 
@@ -1405,20 +857,32 @@
     {
       int argc = argv.length ();
 
-      if (nargout > 0)
-	retval.resize (argc-1, Matrix ());
-
       if (argc > 1)
 	{
+	  Octave_map m (dim_vector (1, argc-1));
+
+	  Cell names (1, argc-1);
+	  Cell files (1, argc-1);
+	  Cell types (1, argc-1);
+
 	  for (int i = 1; i < argc; i++)
 	    {
-	      std::string id = argv[i];
+	      std::string name = argv[i];
+
+	      std::string type;
+
+	      std::string file = do_which (name, type);
 
-	      if (nargout == 0)
-		do_which (octave_stdout, id);
-	      else
-		retval(i-1) = do_which (id);
+	      names(i-1) = name;
+	      files(i-1) = file;
+	      types(i-1) = type;
 	    }
+
+	  m.assign ("name", names);
+	  m.assign ("file", files);
+	  m.assign ("type", types);
+
+	  retval = m;
 	}
       else
 	print_usage ();
@@ -1427,757 +891,95 @@
   return retval;
 }
 
-// FIXME 
-// This function attempts to find the first sentence of a help string, though
-// given that the user can create the help in an arbitrary format, your
-// success might vary.. it works much better with help string formated in
-// texinfo. Using regex might make this function much simpler.
-
-std::string 
-first_help_sentence (const std::string& h, bool short_sentence = true)
+// FIXME -- Are we sure this function always does the right thing?
+inline bool
+file_is_in_dir (const std::string filename, const std::string dir)
 {
-  std::string retval;
-
-  size_t pos = 0;
-
-  if (looks_like_texinfo (h, pos))
-    { 
-     // Get the parsed help string.
-      pos = 0;
-      std::ostringstream os;
-      display_help_text (os, h);
-      std::string h2 = os.str ();
-
-      while (1)
-	{
-	  // Skip leading whitespace and get new line
-	  pos = h2.find_first_not_of ("\n\t ", pos);
-
-	  if (pos == std::string::npos)
-	    break;
-
-	  size_t new_pos = h2.find_first_of ('\n', pos);
-	  std::string line = h2.substr (pos, new_pos-pos);
-
-	  // Skip lines starting in "-"
-	  if (line.find_first_of ('-') == 0)
-	    {
-	      pos = new_pos + 1;
-	      continue;
-	    }
+  if (filename.find (dir) == 0)
+    {
+      const int dir_len = dir.size ();
+      const int filename_len = filename.size ();
+      const int max_allowed_seps = file_ops::is_dir_sep (dir [dir_len-1]) ? 0 : 1;
+      
+      int num_seps = 0;
+      for (int i = dir_len; i < filename_len; i++)
+        if (file_ops::is_dir_sep (filename [i]))
+          num_seps ++;
+      
+      return (num_seps <= max_allowed_seps);
+    }
+  else
+    return false;
+}
 
-	  break;
-	}
-
-      if (pos == std::string::npos)
-	return retval;
-
-      // At start of real text. Get first line with the sentence
-      size_t new_pos = h2.find_first_of ('\n', pos);
-      std::string line = h2.substr (pos, new_pos-pos);
-      size_t dot_pos;
-
-      while ((dot_pos = line.find_first_of ('.')) == std::string::npos)
-	{
-	  // Trim trailing blanks on line
-	  line.substr (0, line.find_last_not_of ("\n\t ") + 1);
-
-	  // Append next line
-	  size_t tmp_pos = h2.find_first_not_of ("\n\t ", new_pos + 1);
-	  if (tmp_pos == std::string::npos || h2.substr (tmp_pos, 1) == "\n")
-	    break;
+DEFUN (__list_functions__, args, , "-*- texinfo -*-\n\
+@deftypefn {Function File} {@var{retval} =} __list_functions__ ()\n\
+@deftypefnx{Function File} {@var{retval} =} __list_functions__ (@var{directory})\n\
+Return the functions available in a given directory.\n\
+\n\
+The function returns a cell array of strings containing the names of all\n\
+functions available in said directory. If no directory is given, the current\n\
+path is searched.\n\
+\n\
+This is an internal function and should not be used directly.\n\
+@seealso{path}\n\
+@end deftypefn\n")
+{
+  octave_value_list retval;
 
-	  new_pos = h2.find_first_of ('\n', tmp_pos);
-	  std::string next = h2.substr (tmp_pos, new_pos-tmp_pos);
-
-	  if (short_sentence)
-	    {
-	      if ((tmp_pos = next.find_first_of ('.')) != std::string::npos)
-		{
-		  line = line + " " + next;
-		  dot_pos = line.find_first_of ('.');
-		}
-	      break;
-	    }
-	  else
-	    line = line + " " + next;
-	}
-
-      if (dot_pos == std::string::npos)
-	retval = line;
-      else
-	retval = line.substr (0, dot_pos + 1);
+  // Get list of functions
+  const string_vector ffl = load_path::fcn_names ();
+  const int ffl_len = ffl.length ();
+  const string_vector afl = autoloaded_functions ();
+  const int afl_len = afl.length ();
+  
+  if (args.length () == 0)
+    {
+      Cell C (ffl_len + afl_len, 1);
+      int j = 0;
+      for (int i = 0; i < ffl_len; i++)
+        C (j++, 0) = octave_value (ffl [i]);
+      for (int i = 0; i < afl_len; i++)
+        C (j++, 0) = octave_value (afl [i]);
+            
+      retval.append (octave_value (C));
     }
   else
     {
-      std::string _upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-      std::string _lower = "abcdefghijklmnopqrstuvwxyz";
-      std::string _alpha = _upper + _lower + "_";
-      std::string _alphanum = _alpha + "1234567890";
-      pos = 0;
-
-      while (1)
-	{
-	  // Skip leading whitespace and get new line
-	  pos = h.find_first_not_of ("\n\t ", pos);
-
-	  if (pos == std::string::npos)
-	    break;
-
-	  size_t new_pos = h.find_first_of ('\n', pos);
-	  std::string line = h.substr (pos, new_pos-pos);
-
-	  // Make a lower case copy to simplify some tests
-	  std::string lower = line;
-	  std::transform (lower.begin (), lower.end (), lower.begin (), tolower);
-
-	  // Skip lines starting in "-" or "Usage"
-	  if (lower.find_first_of ('-') == 0
-	      || lower.substr (0, 5) == "usage")
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  size_t line_pos = 0;
-	  size_t tmp_pos = 0;
-
-	  // chop " blah : "
-	  tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of 
-					     (_alphanum, line_pos));
-	  if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == ":")
-	    line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " function "
-	  if (lower.substr (line_pos, 8) == "function")
-	    line_pos =  line.find_first_not_of ("\t ", line_pos + 8);
-	  
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " [a,b] = "
-	  if (line.substr (line_pos, 1) == "[")
-	    {
-	      tmp_pos = line.find_first_not_of 
-		("\t ", line.find_first_of ("]", line_pos) + 1);
-
-	      if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "=")
-		line_pos = line.find_first_not_of ("\t ",tmp_pos + 1);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " a = "
-	  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
-	    {
-	      tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of 
-						(_alphanum, line_pos));
-	      if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "=")
-		line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = new_pos + 1;
-	      continue;
-	    }
-
-	  // chop " f(x) "
-	  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
-	    {
-	      tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of 
-						(_alphanum, line_pos));
-	      if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "(")
-		line_pos = line.find_first_not_of ("\t ", line.find_first_of 
-						   (")", tmp_pos) + 1);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " ; "
-	  if (line.substr (line_pos, 1) == ":"
-	      || line.substr (line_pos, 1) == ";")
-	    line_pos = line.find_first_not_of ("\t ", line_pos + 1);
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " BLAH "
-	  if (line.length () > line_pos + 2
-	      && line.find_first_of (_upper, line_pos) == line_pos
-	      && line.find_first_of (_upper, line_pos+1) == line_pos + 1)
-	    line_pos = line.find_first_not_of ("\t ", line.find_first_not_of 
-			(_upper + "0123456789_", line_pos));
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " blah --- "
-	  tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of 
-					     (_alphanum, line_pos));
-	  if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "-")
-	    {
-	      tmp_pos = line.find_first_not_of ("-", tmp_pos);
-	      if (line.substr (tmp_pos, 1) == " "
-		  || line.substr (tmp_pos, 1) == "\t")
-		line_pos = line.find_first_not_of ("\t ", tmp_pos);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " blah <TAB> "
-	  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
-	    {
-	      tmp_pos = line.find_first_not_of (" ", line.find_first_not_of 
-						(_alphanum, line_pos));
-	      if (tmp_pos != std::string::npos && line.substr (tmp_pos, 1) == "\t")
-		line_pos = line.find_first_not_of ("\t ", line.find_first_of 
-						   (")", tmp_pos) + 1);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // chop " blah  "
-	  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
-	    {
-	      tmp_pos = line.find_first_not_of (_alphanum, line_pos);
-
-	      if (tmp_pos != std::string::npos
-		  && (line.substr (tmp_pos, 2) == "\t\t"
-		      || line.substr (tmp_pos, 2) == "\t "
-		      || line.substr (tmp_pos, 2) == " \t"
-		      || line.substr (tmp_pos, 2) == " "))
-		line_pos = line.find_first_not_of ("\t ", tmp_pos);
-	    }
-
-	  if (line_pos == std::string::npos)
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // skip blah \n or \n blah
-	  // skip blank line
-	  // skip "# !/usr/bin/octave"
-	  if ((line.substr (line_pos , 2) == "or"
-	       && line.find_first_not_of ("\n\t ", line_pos + 2) == std::string::npos)
-	      || line.find_first_not_of ("\n\t ", line_pos) == std::string::npos
-	      || line.substr (line_pos, 2) == "!/")
-	    {
-	      pos = (new_pos == std::string::npos ? std::string::npos : new_pos + 1);
-	      continue;
-	    }
-
-	  // Got the start of first sentence, break.
-	  pos = pos + line_pos;
-	  break;
-	}
-
-      if (pos == std::string::npos)
-	return retval;
-
-      // At start of real text. Get first line with the sentence
-      size_t new_pos = h.find_first_of ('\n', pos);
-      std::string line = h.substr (pos, new_pos-pos);
-      size_t dot_pos;
-
-      while ((dot_pos = line.find_first_of ('.')) == std::string::npos)
-	{
-	  // Trim trailing blanks on line
-	  line = line.substr (0, line.find_last_not_of ("\n\t ") + 1);
-
-	  // Append next line
-	  size_t tmp_pos = h.find_first_not_of ("\t ", new_pos + 1);
-	  if (tmp_pos == std::string::npos || h.substr (tmp_pos, 1) == "\n")
-	    break;
-
-	  new_pos = h.find_first_of ('\n', tmp_pos);
-	  std::string next = h.substr (tmp_pos, new_pos-tmp_pos);
-
-	  if (short_sentence)
-	    {
-	      // Only add the next line if it terminates the sentence, then break
-	      if ((tmp_pos = next.find_first_of ('.')) != std::string::npos)
-		{
-		  line = line + " " + next;
-		  dot_pos = line.find_first_of ('.');
-		}
-	      break;
-	    }
-	  else
-	    line = line + " " + next;
-	}
-
-      if (dot_pos == std::string::npos)
-	retval = line;
+      // Get input
+      std::string dir = args (0).string_value ();
+      if (error_state)
+        error ("__list_functions__: input must be a string");
       else
-	retval = line.substr (0, dot_pos + 1);
-    }
-
-  return retval;
-}
-
-static void
-print_lookfor (const std::string& name, const std::string& line)
-{
-  const size_t deflen = 20;
-
-  size_t max_width = command_editor::terminal_cols () - deflen;
-  if (max_width < deflen)
-    max_width = deflen;
-
-  size_t name_len = name.length ();
-
-  size_t width = max_width;
-  if (name_len > deflen)
-    {
-      width = command_editor::terminal_cols () - name_len;
-      if (width < deflen)
-	width = deflen;
-    }
-
-  size_t pad_len = deflen > name_len ? deflen - name_len + 1 : 1;
-  octave_stdout << name << std::string (pad_len, ' ');
-
-  size_t pos = 0;
-
-  while (1)
-    {
-      size_t new_pos = line.find_first_of ("\n\t ", pos);
-      size_t end_pos = new_pos;
-
-      if (line.length () - pos < width)
-	new_pos = end_pos = std::string::npos;
-      else
-	while (new_pos != std::string::npos && new_pos - pos < width)
-	  {
-	    end_pos = new_pos;
-	    new_pos = line.find_first_of ("\n\t ", new_pos + 1);
-	  }
-
-      octave_stdout << line.substr (pos, end_pos-pos) << std::endl;
-		  
-      if (end_pos == std::string::npos)
-	break;
-
-      pos = end_pos + 1;
-      width = max_width;
-      octave_stdout << std::string (deflen + 1, ' ');
-    }
-}
-
-DEFCMD (lookfor, args, nargout, 
-  "-*- texinfo -*-\n\
-@deffn {Command} lookfor @var{str}\n\
-@deffnx {Command} lookfor -all @var{str}\n\
-@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor (@var{str})\n\
-@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor ('-all', @var{str})\n\
-Search for the string @var{str} in all of the functions found in the\n\
-function search path.  By default @code{lookfor} searches for @var{str}\n\
-in the first sentence of the help string of each function found. The entire\n\
-help string of each function found in the path can be searched if\n\
-the '-all' argument is supplied. All searches are case insensitive.\n\
-\n\
-Called with no output arguments, @code{lookfor} prints the list of matching\n\
-functions to the terminal. Otherwise the output arguments @var{fun} and\n\
-@var{helpstring} define the matching functions and the first sentence of\n\
-each of their help strings.\n\
-\n\
-Note that the ability of @code{lookfor} to correctly identify the first\n\
-sentence of the help of the functions is dependent on the format of the\n\
-functions help. All of the functions in Octave itself will correctly\n\
-find the first sentence, but the same cannot be guaranteed for other\n\
-functions. Therefore the use of the '-all' argument might be necessary\n\
-to find related functions that are not part of Octave.\n\
-@seealso{help, which}\n\
-@end deffn")
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-  bool first_sentence_only = true;
-
-  if (nargin != 1 && nargin != 2)
-    {
-      print_usage ();
-      return retval;
-    }
-
-  string_vector ret[2];
-
-  std::string txt;
-
-  if (args(0).is_string ())
-    {
-      txt = args(0).string_value ();
+        {
+          dir = file_ops::canonicalize_file_name (dir);
+          
+          // FIXME -- This seems very inefficient. Is there a better way?
+          std::list<std::string> list;
+          for (int i = 0; i < ffl_len; i++)
+            {
+              const std::string filename = do_which (ffl [i]);
+              if (file_is_in_dir (filename, dir))
+                list.push_back (ffl [i]);
+            }
+          for (int i = 0; i < afl_len; i++)
+            {
+              const std::string filename = do_which (afl [i]);
+              if (file_is_in_dir (filename, dir))
+                list.push_back (afl [i]);
+            }
+            
+          Cell C (list.size (), 1);
+          int j = 0;
+          for (std::list<std::string>::const_iterator iter = list.begin ();
+               iter != list.end (); iter++)
+            {
+              C (j++, 0) = octave_value (*iter);
+            }
 
-      if (nargin == 2)
-	{
-	  if (args(1).is_string ())
-	    {
-	      std::string tmp = args(1).string_value ();
-
-	      if (txt.substr(0,1) == "-")
-		{
-		  txt = tmp;
-		  tmp = args(0).string_value ();
-		}
-
-	      if (tmp == "-all")
-		first_sentence_only = false;
-	      else
-		error ("lookfor: unrecognized option argument");
-	    }
-	  else
-	    error ("lookfor: arguments must be a string");
-	}
-    }
-  else
-    error ("lookfor: argument must be a string");
-
-  if (!error_state)
-    {
-      // All tests in lower case
-      std::transform (txt.begin (), txt.end (), txt.begin (), tolower);
-
-      help_list *ptr = keyword_help ();
-      while (ptr->name)
-	{
-	  std::string name = ptr->name;
-	  std::string h = ptr->help;
-
-	  if (name.find (txt) != std::string::npos)
-	    {
-	      if (nargout)
-		{
-		  ret[0].append (name);
-		  ret[1].append (first_help_sentence (h));
-		}
-	      else
-		print_lookfor (name, first_help_sentence (h));
-	    }
-	  else
-	    {
-	      std::string s;
-
-	      if (first_sentence_only)
-		s = first_help_sentence (h);
-	      else
-		s = h;
-	      
-	      std::transform (s.begin (), s.end (), s.begin (), tolower);
-
-	      if (s.length () > 0 && s.find (txt) != std::string::npos)
-		{
-		  if (nargout)
-		    {
-		      ret[0].append (name);
-		      ret[1].append (first_help_sentence (h));
-		    }
-		  else
-		    print_lookfor (name, first_help_sentence (h));
-		}
-	    }
-
-	  OCTAVE_QUIT;
-
-	  ptr++;
-	}
-
-      ptr = operator_help ();
-      while (ptr->name)
-	{
-	  std::string name = ptr->name;
-	  std::string h = ptr->help;
-
-	  if (name.find (txt) != std::string::npos)
-	    {
-	      if (nargout)
-		{
-		  ret[0].append (name);
-		  ret[1].append (first_help_sentence (h));
-		}
-	      else
-		print_lookfor (name, first_help_sentence (h));
-	    }
-	  else
-	    {
-	      std::string s;
-	      if (first_sentence_only)
-		s = first_help_sentence (h);
-	      else
-		s = h;
-	      
-	      std::transform (s.begin (), s.end (), s.begin (), tolower);
-
-	      if (s.length () > 0 && s.find (txt) != std::string::npos)
-		{
-		  if (nargout)
-		    {
-		      ret[0].append (name);
-		      ret[1].append (first_help_sentence (h));
-		    }
-		  else
-		    print_lookfor (name, first_help_sentence (h));
-		}
-	    }
-
-	  OCTAVE_QUIT;
-
-	  ptr++;
-	}
-
-      string_vector names;
-
-#ifdef OLD_SYMTAB
-      // Check the symbol record table
-      names = fbi_sym_tab->name_list (string_vector (), true);
-
-      for (octave_idx_type i = 0; i < names.length (); i++)
-	{
-	  std::string name = names (i);
-
-	  OCTAVE_QUIT;
-
-	  symbol_record *sr = lookup_by_name (name, 0);
-	  if (sr && sr->is_defined ()
-	      && sr->type_name () != "overloaded function")
-	    {
-	      std::string h = sr->help ();
-
-	      if (name.find (txt) != std::string::npos)
-		{
-		  if (nargout)
-		    {
-		      ret[0].append (name);
-		      ret[1].append (first_help_sentence (h));
-		    }
-		  else
-		    print_lookfor (name, first_help_sentence (h));
-		}
-	      else
-		{
-		  std::string s;
-
-		  if (first_sentence_only)
-		    s = first_help_sentence (h);
-		  else
-		    s = h;
-	      
-		  std::transform (s.begin (), s.end (), s.begin (), tolower);
-
-		  if (s.length () > 0 && s.find (txt) != std::string::npos)
-		    {
-		      if (nargout)
-			{
-			  ret[0].append (name);
-			  ret[1].append (first_help_sentence (h));
-			}
-		      else
-			print_lookfor (name, first_help_sentence (h));
-		    }
-		}
-	    }
-	}
-#endif
-
-      string_vector dirs = load_path::dirs ();
-
-      int len = dirs.length ();
-
-      for (int i = 0; i < len; i++)
-	{
-	  names = load_path::files (dirs[i]);
-
-	  if (! names.empty ())
-	    {
-	      for (int j = 0; j < names.length (); j++)
-		{
-		  std::string name = names (j);
-
-		  OCTAVE_QUIT;
-
-		  // Strip extension
-		  size_t l = name.length ();
-		  if (l > 4 && name.substr (l-4) == ".oct")
-		    name = name.substr (0, l - 4);
-		  else if (l > 2 && name.substr (l-2) == ".m")
-		    name = name.substr (0, l - 2);
-		  else
-		    continue;
-
-#ifdef OLD_SYMTAB
-		  // Check if already in symbol table
-		  symbol_record *sr = fbi_sym_tab->lookup (name);
-
-		  if (!sr)
-		    {
-		      // Check if this version is first in the path
-
-		      std::string file_name = load_path::find_fcn (name);
-		      
-		      std::string dir = dirs[i];
-
-		      if (! file_ops::is_dir_sep (dir[dir.length()-1]))
-			dir += file_ops::dir_sep_str ();
-
-		      if (file_name == dir + name + ".oct"
-			  || file_name == dir + name + ".m")
-			{
-			  bool symbol_found;
-
-			  std::string h;
-			  if (file_name == dir + name + ".oct")
-			    {
-			      // oct-file. Must load to get help
-			      sr = lookup_by_name (name, false);
-
-			      if (sr && sr->is_defined ())
-				h = sr->help ();
-			    }
-			  else
-			    h = get_help_from_file (file_name, symbol_found);
-
-			  if (name.find (txt) != std::string::npos)
-			    {
-			      if (nargout)
-				{
-				  ret[0].append (name);
-				  ret[1].append (first_help_sentence (h));
-				}
-			      else
-				print_lookfor (name, first_help_sentence (h));
-			    }
-			  else
-			    {
-			      std::string s;
-			      if (first_sentence_only)
-				s = first_help_sentence (h);
-			      else
-				s = h;
-
-			      std::transform (s.begin (), s.end (), s.begin (), tolower);
-
-			      if (s.length () > 0 && s.find (txt) != std::string::npos)
-				{
-				  if (nargout)
-				    {
-				      ret[0].append (name);
-				      ret[1].append (first_help_sentence (h));
-				    }
-				  else
-				    print_lookfor (name, first_help_sentence (h));
-				}
-			    }
-			}
-		    }
-#endif
-
-		  // Check if this function has autoloaded functions attached to it
-		  std::string file_name = load_path::find_fcn (name);
-
-		  string_vector autoload_fcns = reverse_lookup_autoload (file_name);
-
-		  if (! autoload_fcns.empty ())
-		    {
-		      for (int k = 0; k < autoload_fcns.length (); k++)
-			{
-			  std::string aname = autoload_fcns (k);
-
-#ifdef OLD_SYMTAB
-			  // Check if already in symbol table
-			  sr = fbi_sym_tab->lookup (aname);
-
-			  if (!sr)
-			    {
-			      // Must load to get help
-			      sr = lookup_by_name (aname, false);
-
-			      std::string h;
-			      if (sr && sr->is_defined ())
-				h = sr->help ();
-
-			      if (aname.find (txt) != std::string::npos)
-				{
-				  if (nargout)
-				    {
-				      ret[0].append (aname);
-				      ret[1].append (first_help_sentence (h));
-				    }
-				  else
-				    print_lookfor (aname, first_help_sentence (h));
-				}
-			      else
-				{
-				  std::string s;
-				  if (first_sentence_only)
-				    s = first_help_sentence (h);
-				  else
-				    s = h;
-
-				  std::transform (s.begin (), s.end (), s.begin (), 
-					     tolower);
-
-				  if (s.length () > 0 && s.find (txt) != std::string::npos)
-				    {
-				      if (nargout)
-					{
-					  ret[0].append (aname);
-					  ret[1].append (first_help_sentence (h));
-					}
-				      else
-					print_lookfor (aname, first_help_sentence (h));
-				    }
-				}
-			    }
-#endif
-			}
-		    }
-		}
-	    }
-	}
-
-      if (nargout != 0)
-	{
-	  retval (1) = ret[1];
-	  retval (0) = ret[0];
-	}
-    }
-  else
-    {
-      error ("lookfor: argument must be a string");
-    }
+          retval.append (octave_value (C));
+        }
+    }  
 
   return retval;
 }