changeset 22198:f6181638f6c5

search docstrings file for built-in and dld function help text (bug #48554) Load help text as needed from the built-in docstrings file for built-in and dynamically loaded .oct file functions. * help.h, help.cc (install_built_in_docstrings): Delete. (raw_help_from_docstrings_file): New static function. (raw_help): Call raw_help_from_docstrings_file if help text is not found or if it is marked as external. * mk-builtins.sh: Don't emit call to install_built_in_docstrings.
author John W. Eaton <jwe@octave.org>
date Tue, 02 Aug 2016 03:10:51 -0400
parents e43d83253e28
children af0dca907fae
files build-aux/mk-builtins.sh libinterp/corefcn/help.cc libinterp/corefcn/help.h
diffstat 3 files changed, 123 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/build-aux/mk-builtins.sh	Mon Aug 01 12:40:18 2016 -0400
+++ b/build-aux/mk-builtins.sh	Tue Aug 02 03:10:51 2016 -0400
@@ -214,10 +214,7 @@
   done
 
   cat << \EOF
-
-  install_built_in_docstrings ();
 }
-
 EOF
 
 fi
--- a/libinterp/corefcn/help.cc	Mon Aug 01 12:40:18 2016 -0400
+++ b/libinterp/corefcn/help.cc	Tue Aug 02 03:10:51 2016 -0400
@@ -28,8 +28,9 @@
 #include <cstring>
 
 #include <algorithm>
+#include <fstream>
 #include <iostream>
-#include <fstream>
+#include <map>
 #include <sstream>
 #include <string>
 
@@ -967,6 +968,123 @@
   return symbol_found;
 }
 
+static bool
+raw_help_from_docstrings_file (const std::string& nm, std::string& h,
+                               bool& symbol_found)
+{
+  typedef std::pair<std::streampos, std::streamoff> txt_limits_type;
+  typedef std::map<std::string, txt_limits_type> help_txt_map_type;
+
+  static help_txt_map_type help_txt_map;
+  static bool initialized = false;
+
+  h = "";
+  symbol_found = false;
+
+  // FIXME: Should we cache the timestamp of the file and reload the
+  // offsets if it changes?  Or just warn about that?  Or just ignore
+  // it, and assume it won't change?
+
+  if (! initialized)
+    {
+      std::string fname = Vbuilt_in_docstrings_file;
+
+      std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+
+      if (! file)
+        error ("failed to open docstrings file: %s", fname.c_str ());
+
+      // Ignore header;
+      file.ignore (std::numeric_limits<std::streamsize>::max(), 0x1d);
+
+      if (file.eof ())
+        error ("invalid built-in-docstrings file!");
+
+      // FIXME: eliminate fixed buffer size.
+      size_t bufsize = 1000;
+      OCTAVE_LOCAL_BUFFER (char, buf, bufsize);
+
+      while (! file.eof ())
+        {
+          std::string name;
+          int i = 0;
+          int c;
+          while (file && (c = file.get ()) != std::istream::traits_type::eof ())
+            {
+              if (c == '\n' || c == '\r')
+                {
+                  buf[i] = '\0';
+                  name = buf;
+                  break;
+                }
+              else
+                buf[i++] = c;
+            }
+
+          // Skip @c FILENAME which is part of current DOCSTRINGS
+          // syntax.  This may disappear if a specific format for
+          // docstring files is developed.
+          while (file
+                 && (c = file.get ()) != std::istream::traits_type::eof ()
+                 && c != '\n' && c != '\r')
+            ; // skip text
+
+          // skip newline characters
+          while (file
+                 && (c = file.get ()) != std::istream::traits_type::eof ()
+                 && c == '\n' && c == '\r')
+            ; // skip text
+
+          file.unget ();
+
+          // Position of beginning of help text.
+          std::streampos beg = file.tellg ();
+
+          // Skip help text.
+          file.ignore (std::numeric_limits<std::streamsize>::max(), 0x1d);
+ 
+          // Position of end of help text.
+          std::streamoff len = file.tellg () - beg - 1;
+
+          help_txt_map[name] = txt_limits_type (beg, len);
+        }
+
+      initialized = true;
+    }
+
+  help_txt_map_type::const_iterator it = help_txt_map.find (nm);
+
+  if (it != help_txt_map.end ())
+    {
+      txt_limits_type txt_limits = it->second;
+
+      std::streampos beg = txt_limits.first;
+      std::streamoff len = txt_limits.second;
+
+      std::string fname = Vbuilt_in_docstrings_file;
+
+      std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+
+      if (! file)
+        error ("failed to open docstrings file: %s", fname.c_str ());
+
+      file.seekg (beg);
+
+      size_t txt_len = len;
+      OCTAVE_LOCAL_BUFFER (char, buf, txt_len + 1);
+
+      file.read (buf, txt_len);
+
+      buf[txt_len] = '\0';
+
+      h = buf;
+
+      symbol_found = true;
+    }
+
+  return symbol_found;
+}
+
 std::string
 raw_help (const std::string& nm, bool& symbol_found)
 {
@@ -987,10 +1105,13 @@
           found = raw_help_from_map (nm, h, operators_map, symbol_found);
 
           if (! found)
-            raw_help_from_map (nm, h, keywords_map, symbol_found);
+            found = raw_help_from_map (nm, h, keywords_map, symbol_found);
         }
     }
 
+  if (! found || h == "external-doc")
+    raw_help_from_docstrings_file (nm, h, symbol_found);
+
   return h;
 }
 
@@ -1017,79 +1138,6 @@
   return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (built_in_docstrings_file);
 }
 
-void
-install_built_in_docstrings (void)
-{
-  std::string fname = Vbuilt_in_docstrings_file;
-
-  std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
-
-  if (file)
-    {
-      // Ignore header;
-      file.ignore (1000, 0x1d);
-
-      if (file.gcount () == 1000)
-        {
-          // We use std::cerr here instead of calling Octave's warning
-          // function because install_built_in_docstrings is called
-          // before the interpreter is initialized, so warning messages
-          // won't work properly.
-
-          std::cerr << "warning: is builtin-docstrings file corrupted?"
-                    << std::endl;
-          return;
-        }
-
-      // FIXME: eliminate fixed buffer size.
-      size_t bufsize = 100000;
-
-      OCTAVE_LOCAL_BUFFER (char, buf, bufsize);
-
-      while (! file.eof ())
-        {
-          file.getline (buf, bufsize, 0x1d);
-
-          std::string tmp (buf);
-
-          size_t pos = tmp.find ('\n');
-
-          std::string fcn = tmp.substr (0, pos);
-
-          octave_value ov = symbol_table::find_built_in_function (fcn);
-
-          if (ov.is_defined ())
-            {
-              octave_function *fp = ov.function_value ();
-
-              if (fp)
-                {
-                  tmp = tmp.substr (pos+1);
-
-                  // Strip @c FILENAME which is part of current DOCSTRINGS
-                  // syntax.  This may disappear if a specific format for
-                  // docstring files is developed.
-                  while (tmp.length () > 2 && tmp[0] == '@' && tmp[1] == 'c')
-                    {
-                      pos = tmp.find ('\n');
-                      tmp = tmp.substr (pos+1);
-                    }
-
-                  fp->document (tmp);
-                }
-            }
-        }
-    }
-  else
-    {
-      // See note above about using std::cerr instead of warning.
-
-      std::cerr << "warning: docstring file '" << fname << "' not found"
-                << std::endl;
-    }
-
-}
-
 static void
 do_get_help_text (const std::string& name, std::string& text,
                   std::string& format)
--- a/libinterp/corefcn/help.h	Mon Aug 01 12:40:18 2016 -0400
+++ b/libinterp/corefcn/help.h	Tue Aug 02 03:10:51 2016 -0400
@@ -34,8 +34,6 @@
 
 extern OCTINTERP_API std::string raw_help (const std::string&, bool&);
 
-extern OCTINTERP_API void install_built_in_docstrings (void);
-
 // Name of the doc cache file specified on the command line.
 // (--doc-cache-file file)
 extern OCTINTERP_API std::string Vdoc_cache_file;