# HG changeset patch # User John W. Eaton # Date 1257970274 18000 # Node ID 8e345f2fe4d60cc48355d130d14a18292f8f0126 # Parent bb70d16cca3b82544503f5b229660a2482e23ed7 improved support for Contents.m files diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,10 @@ +2009-11-11 John W. Eaton + + * help/help.m (help): Return immediately after calling do_contents. + (do_contents): Find all matching directories, not just the first. + Call get_help_text_from_file to avoid looking in path. + Handle printing here. + 2009-11-10 John W. Eaton * Makefile.am, audio/module.mk, deprecated/module.mk, diff --git a/scripts/help/help.m b/scripts/help/help.m --- a/scripts/help/help.m +++ b/scripts/help/help.m @@ -65,10 +65,8 @@ case "not documented" error ("help: `%s' is not documented\n", name); case "not found" - [text, status] = do_contents (name); - if (status != 0) - error ("help: `%s' not found\n", name); - endif + do_contents (name); + return; otherwise error ("help: internal error: unsupported help text format: '%s'\n", format); endswitch @@ -87,30 +85,40 @@ endfunction -function [text, status] = do_contents (name) - text = ""; - status = 1; +function do_contents (name) + + found = false; - d = find_dir_in_path (name); - if (!isempty (d)) - p = path (); - unwind_protect - ## Only include 'd' in the path, and then get the help text of 'Contents' - path (d); - [text, format] = get_help_text ("Contents"); + dlist = find_dir_in_path (name, "all"); + + for i = 1:numel (dlist) + fname = make_absolute_filename (fullfile (dlist{i}, "Contents.m")); + + [text, format] = get_help_text_from_file (fname); - ## Take action depending on help text format - switch (lower (format)) - case "plain text" - status = 0; - case "texinfo" - [text, status] = __makeinfo__ (text, "plain text"); - case "html" - [text, status] = strip_html_tags (text); - endswitch - unwind_protect_cleanup - ## Restore path - path (p); - end_unwind_protect + ## Take action depending on help text format + switch (lower (format)) + case "plain text" + status = 0; + case "texinfo" + [text, status] = __makeinfo__ (text, "plain text"); + case "html" + [text, status] = strip_html_tags (text); + endswitch + + if (! isempty (text)) + found = true; + ## Print text. + if (status != 0) + warning ("help: Texinfo formatting filter exited abnormally; raw Texinfo source of help text follows...\n"); + endif + printf ("%s:\n\n%s\n", fname, text); + endif + + endfor + + if (found) + puts (__additional_help_message__ ()); endif + endfunction diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2009-11-11 John W. Eaton + + * help.cc (do_get_help_text_from_file, Fget_help_text_from_file): + New functions. + (do_get_help_text): Pass NAME by const reference. + * utils.cc (find_dir_in_path): New optional argument "all". + * load-path.cc (load_path::do_find_matching_dirs): New function. + (load_path::do_find_dir): Perform match on absolute directory + names, but return name as it appears in dir_info_list. Adjust + dname_len after stripping directory separator. + * load-path.h (load_path::do_find_matching_dirs): Provide decl. + (load_path::find_matching_dirs): New function. + 2009-11-11 Shai Ayal * DLD-FUNCTIONS/fltk_backend.cc (Fl_Gl_Window::draw): diff --git a/src/help.cc b/src/help.cc --- a/src/help.cc +++ b/src/help.cc @@ -705,7 +705,7 @@ } static void -do_get_help_text (const std::string name, std::string& text, +do_get_help_text (const std::string& name, std::string& text, std::string& format) { bool symbol_found = false; @@ -774,6 +774,80 @@ return retval; } +static void +do_get_help_text_from_file (const std::string& fname, std::string& text, + std::string& format) +{ + bool symbol_found = false; + + std::string f; + + raw_help_from_file (fname, text, f, symbol_found); + + format = "Not found"; + if (symbol_found) + { + size_t idx = -1; + if (text.empty ()) + { + format = "Not documented"; + } + else if (looks_like_texinfo (text, idx)) + { + format = "texinfo"; + text.erase (0, idx); + } + else if (looks_like_html (text)) + { + format = "html"; + } + else + { + format = "plain text"; + } + } +} + +DEFUN (get_help_text_from_file, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{text}, @var{format}] =} get_help_text_from_file (@var{fname})\n\ +Returns the help text from the given file.\n\ +\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\ +To convert the help text to other formats, use the @code{makeinfo} function.\n\ +\n\ +@seealso{makeinfo}\n\ +@end deftypefn") +{ + octave_value_list retval; + + if (args.length () == 1) + { + const std::string fname = args(0).string_value (); + + if (! error_state) + { + std::string text; + std::string format; + + do_get_help_text_from_file (fname, text, format); + + retval(1) = format; + retval(0) = text; + } + else + error ("get_help_text_from_file: invalid input"); + } + else + print_usage (); + + return retval; +} + // Return a cell array of strings containing the names of all // operators. diff --git a/src/load-path.cc b/src/load-path.cc --- a/src/load-path.cc +++ b/src/load-path.cc @@ -1167,12 +1167,16 @@ p != dir_info_list.end (); p++) { - std::string dname = p->dir_name; + std::string dname + = octave_env::make_absolute (p->dir_name, octave_env::getcwd ()); size_t dname_len = dname.length (); if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ()) - dname = dname.substr (0, dname_len - 1); + { + dname = dname.substr (0, dname_len - 1); + dname_len--; + } size_t dir_len = dir.length (); @@ -1191,6 +1195,54 @@ return retval; } +string_vector +load_path::do_find_matching_dirs (const std::string& dir) const +{ + std::list retlist; + + if (dir.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos + && (octave_env::absolute_pathname (dir) + || octave_env::rooted_relative_pathname (dir))) + { + file_stat fs (dir); + + if (fs.exists () && fs.is_dir ()) + retlist.push_back (dir); + } + else + { + for (const_dir_info_list_iterator p = dir_info_list.begin (); + p != dir_info_list.end (); + p++) + { + std::string dname + = octave_env::make_absolute (p->dir_name, octave_env::getcwd ()); + + size_t dname_len = dname.length (); + + if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ()) + { + dname = dname.substr (0, dname_len - 1); + dname_len--; + } + + size_t dir_len = dir.length (); + + if (dname_len >= dir_len + && file_ops::is_dir_sep (dname[dname_len - dir_len - 1]) + && dir.compare (dname.substr (dname_len - dir_len)) == 0) + { + file_stat fs (p->dir_name); + + if (fs.exists () && fs.is_dir ()) + retlist.push_back (p->dir_name); + } + } + } + + return retlist; +} + std::string load_path::do_find_first_of (const string_vector& flist) const { diff --git a/src/load-path.h b/src/load-path.h --- a/src/load-path.h +++ b/src/load-path.h @@ -169,6 +169,12 @@ ? instance->do_find_dir (dir) : std::string (); } + static string_vector find_matching_dirs (const std::string& dir) + { + return instance_ok () + ? instance->do_find_matching_dirs (dir) : string_vector (); + } + static std::string find_first_of (const string_vector& files) { return instance_ok () ? @@ -479,6 +485,8 @@ std::string do_find_dir (const std::string& dir) const; + string_vector do_find_matching_dirs (const std::string& dir) const; + std::string do_find_first_of (const string_vector& files) const; string_vector do_find_all_first_of (const string_vector& files) const; diff --git a/src/utils.cc b/src/utils.cc --- a/src/utils.cc +++ b/src/utils.cc @@ -802,22 +802,34 @@ DEFUN (find_dir_in_path, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} find_dir_in_path (@var{dir})\n\ +@deftypefn {Built-in Function} {} find_dir_in_path (@var{dir}, \"all\")\n\ Return the full name of the path element matching @var{dir}. The\n\ match is performed at the end of each path element. For example, if\n\ @var{dir} is @code{\"foo/bar\"}, it matches the path element\n\ @code{\"/some/dir/foo/bar\"}, but not @code{\"/some/dir/foo/bar/baz\"}\n\ or @code{\"/some/dir/allfoo/bar\"}.\n\ +\n\ +The second argument is optional. If it is supplied, return a cell array\n\ +containing all the directory names that match.\n\ @end deftypefn") { octave_value retval = std::string (); - if (args.length () == 1) + int nargin = args.length (); + + std::string dir; + + if (nargin == 1 || nargin == 2) { - std::string dir = args(0).string_value (); + dir = args(0).string_value (); if (! error_state) - retval = load_path::find_dir (dir); + { + if (nargin == 1) + retval = load_path::find_dir (dir); + else if (nargin == 2) + retval = Cell (load_path::find_matching_dirs (dir)); + } else error ("find_dir_in_path: expecting argument to be a directory name"); }