GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
help.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cstdlib>
31 #include <cstring>
32 
33 #include <algorithm>
34 #include <fstream>
35 #include <istream>
36 #include <map>
37 #include <sstream>
38 #include <string>
39 
40 #include "cmd-edit.h"
41 #include "file-ops.h"
42 #include "file-stat.h"
43 #include "lo-sysdep.h"
44 #include "oct-env.h"
45 #include "oct-locbuf.h"
46 #include "str-vec.h"
47 
48 #include "Cell.h"
49 #include "builtin-defun-decls.h"
50 #include "defaults.h"
51 #include "defun.h"
52 #include "error.h"
53 #include "errwarn.h"
54 #include "help.h"
55 #include "input.h"
56 #include "interpreter-private.h"
57 #include "interpreter.h"
58 #include "load-path.h"
59 #include "ov-classdef.h"
60 #include "ov-fcn-handle.h"
61 #include "ov-usr-fcn.h"
62 #include "ovl.h"
63 #include "pager.h"
64 #include "parse.h"
65 #include "pathsearch.h"
66 #include "procstream.h"
67 #include "quit.h"
68 #include "sighandlers.h"
69 #include "symtab.h"
70 #include "unwind-prot.h"
71 #include "utils.h"
72 #include "variables.h"
73 #include "version.h"
74 
75 #include "default-defs.h"
76 
78 
79 const static char *const operators[] =
80 {
81  "!",
82  "~",
83  "!=",
84  "~=",
85  R"(")",
86  "#",
87  "%",
88  "#{",
89  "%{",
90  "#}",
91  "%}",
92  "...",
93  "&",
94  "&&",
95  "'",
96  "(",
97  ")",
98  "*",
99  "^",
100  "+",
101  "++",
102  ",",
103  "-",
104  "--",
105  ".'",
106  ".*",
107  ".^",
108  "./",
109  "/",
110  R"(.\)",
111  R"(\)",
112  ":",
113  ";",
114  "<",
115  "<=",
116  "=",
117  "==",
118  ">",
119  ">=",
120  "[",
121  "]",
122  "|",
123  "||",
124  nullptr
125 };
126 
127 const static string_vector operator_names (operators);
128 
129 static bool
130 looks_like_html (const std::string& msg)
131 {
132  const std::size_t p1 = msg.find ('\n');
133  std::string t = msg.substr (0, p1);
134  // FIXME: this comparison should be case-insensitive
135  const std::size_t p2 = t.find ("<html");
136 
137  return (p2 != std::string::npos);
138 }
139 
140 static bool
141 looks_like_texinfo (const std::string& msg, std::size_t& p1)
142 {
143  p1 = msg.find ('\n');
144 
145  std::string t = msg.substr (0, p1);
146 
147  if (p1 == std::string::npos)
148  p1 = 0;
149 
150  std::size_t p2 = t.find ("-*- texinfo -*-");
151 
152  return (p2 != std::string::npos);
153 }
154 
157  int nargout)
158 {
159  return set_internal_variable (m_built_in_docstrings_file, args, nargout,
160  "built_in_docstrings_file", false);
161 }
162 
164 help_system::doc_cache_file (const octave_value_list& args, int nargout)
165 {
166  return set_internal_variable (m_doc_cache_file, args, nargout,
167  "doc_cache_file", false);
168 }
169 
171 help_system::info_file (const octave_value_list& args, int nargout)
172 {
173  return set_internal_variable (m_info_file, args, nargout,
174  "info_file", false);
175 }
176 
178 help_system::info_program (const octave_value_list& args, int nargout)
179 {
180  return set_internal_variable (m_info_program, args, nargout,
181  "info_program", false);
182 }
183 
185 help_system::makeinfo_program (const octave_value_list& args, int nargout)
186 {
187  return set_internal_variable (m_makeinfo_program, args, nargout,
188  "makeinfo_program", false);
189 }
190 
193  int nargout)
194 {
195  return set_internal_variable (m_suppress_verbose_help_message, args,
196  nargout, "suppress_verbose_help_message");
197 }
198 
200 help_system::texi_macros_file (const octave_value_list& args, int nargout)
201 {
202  return set_internal_variable (m_texi_macros_file, args, nargout,
203  "texi_macros_file", false);
204 }
205 
206 std::string
207 help_system::raw_help (const std::string& nm, bool& symbol_found) const
208 {
209  std::string h;
210  std::string w;
211  std::string f;
212 
213  bool found;
214 
215  found = raw_help_from_symbol_table (nm, h, w, symbol_found);
216 
217  if (! found)
218  found = raw_help_from_file (nm, h, f, symbol_found);
219 
220  bool external_doc = h.compare (0, 12, "external-doc") == 0;
221 
222  if (! found || external_doc)
223  {
224  std::string tmp_nm = nm;
225 
226  if (external_doc && h.length () > 12 && h[12] == ':')
227  tmp_nm = h.substr (13);
228 
229  raw_help_from_docstrings_file (tmp_nm, h, symbol_found);
230  }
231 
232  return h;
233 }
234 
235 bool
236 help_system::get_which_info_from_fcn (const std::string& name, const octave_value& ov_fcn, std::string& file, std::string& type) const
237 {
238  file = "";
239  type = "";
240 
241  if (ov_fcn.is_function ())
242  {
243  octave_function *fcn = ov_fcn.function_value ();
244 
245  if (fcn)
246  {
247  if (fcn->is_classdef_meta ())
248  {
249  octave_classdef_meta *meta_obj
250  = dynamic_cast<octave_classdef_meta *> (fcn);
251 
252  file = meta_obj->file_name ();
253 
254  if (meta_obj->is_classdef_constructor ())
255  type = "class constructor";
256  else if (meta_obj->is_classdef_method ())
257  type = "class method";
258  else
259  type = "classdef meta object";
260  }
261  else
262  {
263  file = fcn->fcn_file_name ();
264 
265  if (! file.empty ())
266  type = ov_fcn.is_user_script () ? "script" : "function";
267  else
268  {
269  if (fcn->is_user_function ())
270  type = "command-line function";
271  else
272  {
273  file = fcn->src_file_name ();
274  type = "built-in function";
275  }
276  }
277  }
278 
279  return true;
280  }
281  else
282  {
283  // We might find a file that contains only a doc string.
284 
285  load_path& lp = m_interpreter.get_load_path ();
286 
287  file = lp.find_fcn_file (name);
288 
289  if (file.empty ())
290  return false;
291  }
292  }
293 
294  return false;
295 }
296 
297 // FIXME: There is a lot of duplication between the following function
298 // and help_system::raw_help_from_symbol_table. Some refactoring would
299 // probably be useful.
300 
301 std::string
302 help_system::which (const std::string& name,
303  std::string& type) const
304 {
305  std::string file;
306 
307  if (name.empty ())
308  return file;
309 
310  type = "";
311 
312  symbol_table& symtab = m_interpreter.get_symbol_table ();
313 
314  size_t pos = name.find ('.');
315 
316  if (pos == std::string::npos)
317  {
318  // Simple name. If not found, continue looking for packages and
319  // classes.
320 
321  octave_value ov_fcn = symtab.find_function (name);
322 
323  if (get_which_info_from_fcn (name, ov_fcn, file, type))
324  return file;
325  }
326 
327  // NAME contains '.' and must match the following pattern:
328  //
329  // (package.)*(package|classname).(property|method)*
330  //
331  // Start by looking up the full name. It could be either a package or
332  // a class and we are done. Otherwise, strip the final component and
333  // lookup that name. If it is a package, look for a function. If it
334  // is a class, look for a property or method.
335 
336  cdef_manager& cdm = m_interpreter.get_cdef_manager ();
337 
338  // FIXME: In the following search we may load classes. Is that really
339  // what we want, or should we just search the loadpath for
340  // +pkga/+pkgb/classname/file.m, etc. and attempt to extract help text
341  // without actually installing packages and classes into the fcn_info
342  // table?
343 
344  // Is NAME a class?
345 
346  cdef_class cls = cdm.find_class (name, false, true);
347 
348  if (cls.ok ())
349  {
350  // FIXME: Return documentation for the class or the class
351  // constructor?
352 
353  file = cls.file_name ();
354  type = "classdef class";
355 
356  return file;
357  }
358 
359  cdef_package pkg = cdm.find_package (name, false, true);
360 
361  if (pkg.ok ())
362  {
363  // FIXME: How to get the fill name of a package?
364  file = pkg.get_name ();
365  type = "package";
366 
367  return file;
368  }
369 
370  // Strip final component (might be a property or method name).
371 
372  pos = name.rfind ('.');
373  std::string prefix = name.substr (0, pos);
374  std::string nm = name.substr (pos+1);
375 
376  // Is PREFIX the name of a class?
377 
378  cls = cdm.find_class (prefix, false, true);
379 
380  if (cls.ok ())
381  {
382  // FIXME: Should we only find public methods here?
383 
384  octave_value ov_meth = cls.get_method (nm);
385 
386  if (get_which_info_from_fcn (nm, ov_meth, file, type))
387  return file;
388 
389  // FIXME: Should we only find public properties here?
390 
391  cdef_property prop = cls.find_property (nm);
392 
393  if (prop.ok ())
394  {
395  file = cls.file_name ();
396  type = "class property";
397 
398  return file;
399  }
400  }
401 
402  // Or is PREFIX the name of a package?
403 
404  pkg = cdm.find_package (prefix, false, true);
405 
406  if (pkg.ok ())
407  {
408  octave_value ov_fcn = pkg.find (nm);
409 
410  if (get_which_info_from_fcn (nm, ov_fcn, file, type))
411  return file;
412  }
413 
414  // File query.
415 
416  load_path& lp = m_interpreter.get_load_path ();
417 
418  // For compatibility: "file." queries "file".
419  if (name.size () > 1 && name[name.size () - 1] == '.')
420  file = lp.find_file (name.substr (0, name.size () - 1));
421  else
422  file = lp.find_file (name);
423 
424  file = sys::env::make_absolute (file);
425 
426  if (! file.empty ())
427  type = "file";
428 
429  return file;
430 }
431 
432 std::string
433 help_system::which (const std::string& name) const
434 {
435  std::string type;
436 
437  return which (name, type);
438 }
439 
442 {
443  const static string_vector keywords
444  = Fiskeyword ()(0).string_vector_value ();
445 
446  const static int key_len = keywords.numel ();
447 
448  symbol_table& symtab = m_interpreter.get_symbol_table ();
449 
450  const string_vector bif = symtab.built_in_function_names ();
451  const int bif_len = bif.numel ();
452 
453  const string_vector cfl = symtab.cmdline_function_names ();
454  const int cfl_len = cfl.numel ();
455 
456  const string_vector lcl = m_interpreter.variable_names ();
457  const int lcl_len = lcl.numel ();
458 
459  load_path& lp = m_interpreter.get_load_path ();
460 
461  const string_vector ffl = lp.fcn_names ();
462  const int ffl_len = ffl.numel ();
463 
464  const string_vector afl = m_interpreter.autoloaded_functions ();
465  const int afl_len = afl.numel ();
466 
467  const string_vector lfl = local_functions ();
468  const int lfl_len = lfl.numel ();
469 
470  const int total_len
471  = key_len + bif_len + cfl_len + lcl_len + ffl_len + afl_len + lfl_len;
472 
473  string_vector list (total_len);
474 
475  // Put all the symbols in one big list.
476 
477  int j = 0;
478  int i = 0;
479 
480  for (i = 0; i < key_len; i++)
481  list[j++] = keywords[i];
482 
483  for (i = 0; i < bif_len; i++)
484  list[j++] = bif[i];
485 
486  for (i = 0; i < cfl_len; i++)
487  list[j++] = cfl[i];
488 
489  for (i = 0; i < lcl_len; i++)
490  list[j++] = lcl[i];
491 
492  for (i = 0; i < ffl_len; i++)
493  list[j++] = ffl[i];
494 
495  for (i = 0; i < afl_len; i++)
496  list[j++] = afl[i];
497 
498  for (i = 0; i < lfl_len; i++)
499  list[j++] = lfl[i];
500 
501  return list;
502 }
503 
504 void
505 help_system::get_help_text (const std::string& name, std::string& text,
506  std::string& format) const
507 {
508  bool symbol_found = false;
509  text = raw_help (name, symbol_found);
510 
511  format = "Not found";
512  if (symbol_found)
513  {
514  std::size_t idx = -1;
515  if (text.empty ())
516  {
517  format = "Not documented";
518  }
519  else if (looks_like_texinfo (text, idx))
520  {
521  format = "texinfo";
522  text.erase (0, idx);
523  }
524  else if (looks_like_html (text))
525  {
526  format = "html";
527  }
528  else
529  {
530  format = "plain text";
531  }
532  }
533 }
534 
535 void
536 help_system::get_help_text_from_file (const std::string& fname,
537  std::string& text,
538  std::string& format) const
539 {
540  bool symbol_found = false;
541 
542  std::string f;
543 
544  raw_help_from_file (fname, text, f, symbol_found);
545 
546  format = "Not found";
547  if (symbol_found)
548  {
549  std::size_t idx = -1;
550  if (text.empty ())
551  {
552  format = "Not documented";
553  }
554  else if (looks_like_texinfo (text, idx))
555  {
556  format = "texinfo";
557  text.erase (0, idx);
558  }
559  else if (looks_like_html (text))
560  {
561  format = "html";
562  }
563  else
564  {
565  format = "plain text";
566  }
567  }
568 }
569 
570 std::string
571 help_system::init_built_in_docstrings_file ()
572 {
573  std::string df = sys::env::getenv ("OCTAVE_BUILT_IN_DOCSTRINGS_FILE");
574 
575  std::string dir_sep = sys::file_ops::dir_sep_str ();
576 
577  if (df.empty ())
578  df = config::oct_etc_dir () + dir_sep + "built-in-docstrings";
579 
580  return df;
581 }
582 
583 std::string
584 help_system::init_doc_cache_file ()
585 {
586  std::string def_file = config::prepend_octave_home (OCTAVE_DOC_CACHE_FILE);
587 
588  std::string env_file = sys::env::getenv ("OCTAVE_DOC_CACHE_FILE");
589 
590  return (env_file.empty () ? def_file : env_file);
591 }
592 
593 std::string
594 help_system::init_info_file ()
595 {
596  std::string std_info_file = config::prepend_octave_home (OCTAVE_INFOFILE);
597 
598  std::string oct_info_file = sys::env::getenv ("OCTAVE_INFO_FILE");
599 
600  return (oct_info_file.empty () ? std_info_file : oct_info_file);
601 }
602 
603 std::string
604 help_system::init_info_program ()
605 {
606  std::string info_prog = sys::env::getenv ("OCTAVE_INFO_PROGRAM");
607 
608  if (info_prog.empty ())
609  info_prog = "info";
610 
611  return info_prog;
612 }
613 
614 std::string
615 help_system::init_texi_macros_file ()
616 {
617  std::string def_file
619 
620  std::string env_file = sys::env::getenv ("OCTAVE_TEXI_MACROS_FILE");
621 
622  return (env_file.empty () ? def_file : env_file);
623 }
624 
625 // Return a vector of all functions from this file,
626 // for use in command line auto-completion.
628 help_system::local_functions () const
629 {
630  string_vector retval;
631 
632  tree_evaluator& tw = m_interpreter.get_evaluator ();
633 
634  octave_user_code *curr_fcn = tw.current_user_code ();
635 
636  if (! curr_fcn)
637  return retval;
638 
639  // All subfunctions are listed in the top-level function of this file.
640  // If curr_fcn is a subfunction, then there must be a parent and
641  // curr_fcn will always be valid in and after executing this loop.
642 
643  while (curr_fcn->is_subfunction ())
644  {
645  symbol_scope pscope = curr_fcn->parent_fcn_scope ();
646  curr_fcn = pscope.user_code ();
647  }
648 
649  // Get subfunctions.
650  const std::list<std::string> names = curr_fcn->subfunction_names ();
651 
652  std::size_t sz = names.size ();
653  retval.resize (sz);
654 
655  // Loop over them.
656  std::size_t i = 0;
657  for (const auto& nm : names)
658  retval(i++) = nm;
659 
660  return retval;
661 }
662 
663 static bool
664 get_help_from_fcn (const std::string& fcn_nm, const octave_value& ov_fcn, std::string& help, std::string& what, bool& symbol_found)
665 {
666  symbol_found = false;
667 
668  help = "";
669  what = "";
670 
671  if (ov_fcn.is_function ())
672  {
673  octave_function *fcn = ov_fcn.function_value ();
674 
675  help = fcn->doc_string (fcn_nm);
676  what = fcn->fcn_file_name ();
677 
678  if (what.empty ())
679  what = fcn->is_user_function () ? "command-line function" : "built-in function";
680 
681  symbol_found = true;
682  }
683 
684  return symbol_found;
685 }
686 
687 bool
688 help_system::raw_help_for_class (const cdef_class& cls,
689  const std::string& name,
690  std::string& help, std::string& what,
691  bool& symbol_found) const
692 {
693  if (cls.ok ())
694  {
695  // Is the class documented?
696  help = cls.doc_string ();
697 
698  if (! help.empty ())
699  {
700  what = "class";
701 
702  symbol_found = true;
703  return true;
704  }
705 
706  // Look for constructor.
707  std::size_t pos = name.rfind ('.');
708 
709  if (pos != std::string::npos)
710  {
711  std::string nm = name.substr (pos+1);
712 
713  octave_value ov_meth = cls.get_method (nm);
714 
715  if (get_help_from_fcn (nm, ov_meth, help, what, symbol_found))
716  {
717  what = "constructor";
718  return true;
719  }
720  }
721 
722  // We found a class, but no docstring for it or its constructor.
723  // Create a generic doc string.
724  help = name + " is an undocumented class";
725  what = "class";
726  symbol_found = true;
727  return true;
728  }
729 
730  return false;
731 }
732 
733 // FIXME: There is a lot of duplication between the following function
734 // and help_system::which. Some refactoring would probably be useful.
735 
736 bool
737 help_system::raw_help_from_symbol_table (const std::string& name, std::string& help, std::string& what, bool& symbol_found) const
738 {
739  symbol_table& symtab = m_interpreter.get_symbol_table ();
740 
741  size_t pos = name.find ('.');
742 
743  if (pos == std::string::npos)
744  {
745  // Simple name. If not found, continue looking for packages and
746  // classes.
747 
748  octave_value ov_fcn = symtab.find_function (name);
749 
750  // FIXME: it seems like there is a lot of potential for confusion
751  // because is_function can also return true for
752  // octave_classdef_meta objects.
753 
754  if (! ov_fcn.is_classdef_meta ()
755  && get_help_from_fcn (name, ov_fcn, help, what, symbol_found))
756  return true;
757  }
758 
759  // If NAME does not contain '.', then it should be a package or a
760  // class name.
761  //
762  // If NAME contains '.' it should match the following pattern:
763  //
764  // (package.)*(package|classname).(property|method)*
765  //
766  // Start by looking up the full name. It could be either a package or
767  // a class and we are done. Otherwise, strip the final component and
768  // lookup that name. If it is a package, look for a function. If it
769  // is a class, look for a property or method.
770 
771  cdef_manager& cdm = m_interpreter.get_cdef_manager ();
772 
773  // FIXME: In the following search we may load classes. Is that really
774  // what we want, or should we just search the loadpath for
775  // +pkga/+pkgb/classname/file.m, etc. and attempt to extract help text
776  // without actually installing packages and classes into the fcn_info
777  // table?
778 
779  // Is NAME a class?
780 
781  cdef_class cls = cdm.find_class (name, false, true);
782 
783  if (raw_help_for_class (cls, name, help, what, symbol_found))
784  return true;
785 
786  cdef_package pkg = cdm.find_package (name, false, true);
787 
788  if (pkg.ok ())
789  {
790  help = "package " + name;
791  what = "package";
792 
793  symbol_found = true;
794  return true;
795  }
796 
797  // Strip final component (might be a property or method name).
798 
799  pos = name.rfind ('.');
800  std::string prefix = name.substr (0, pos);
801  std::string nm = name.substr (pos+1);
802 
803  // Is PREFIX the name of a class?
804 
805  cls = cdm.find_class (prefix, false, true);
806 
807  bool found_class = cls.ok ();
808 
809  if (found_class)
810  {
811  // FIXME: Should we only find public methods here?
812 
813  octave_value ov_meth = cls.get_method (nm);
814 
815  if (get_help_from_fcn (nm, ov_meth, help, what, symbol_found))
816  return true;
817 
818  // FIXME: Should we only find public properties here?
819 
820  cdef_property prop = cls.find_property (nm);
821 
822  if (prop.ok ())
823  {
824  // FIXME: is it supposed to be possible to document
825  // properties?
826 
827  help = prop.doc_string ();
828  what = "class property";
829 
830  symbol_found = true;
831  return true;
832  }
833  }
834 
835  // Or is PREFIX the name of a package?
836 
837  pkg = cdm.find_package (prefix, false, true);
838 
839  if (pkg.ok ())
840  {
841  octave_value ov_fcn = pkg.find (nm);
842 
843  if (get_help_from_fcn (nm, ov_fcn, help, what, symbol_found))
844  return true;
845  }
846 
847  if (nm == "m" && raw_help_for_class (cls, prefix, help, what, symbol_found))
848  return true;
849 
850  return false;
851 }
852 
853 bool
854 help_system::raw_help_from_file (const std::string& nm,
855  std::string& h, std::string& file,
856  bool& symbol_found) const
857 {
858  bool retval = false;
859 
860  h = get_help_from_file (nm, symbol_found, file);
861 
862  if (h.length () > 0)
863  retval = true;
864 
865  return retval;
866 }
867 
868 bool
869 help_system::raw_help_from_docstrings_file (const std::string& nm,
870  std::string& h,
871  bool& symbol_found) const
872 {
873  typedef std::pair<std::streampos, std::streamoff> txt_limits_type;
874  typedef std::map<std::string, txt_limits_type> help_txt_map_type;
875 
876  static help_txt_map_type help_txt_map;
877  static bool initialized = false;
878 
879  h = "";
880  symbol_found = false;
881 
882  // FIXME: Should we cache the timestamp of the file and reload the
883  // offsets if it changes? Or just warn about that? Or just ignore
884  // it, and assume it won't change?
885 
886  if (! initialized)
887  {
888  std::ifstream file = sys::ifstream (m_built_in_docstrings_file.c_str (),
889  std::ios::in | std::ios::binary);
890 
891  if (! file)
892  error ("failed to open docstrings file: %s",
893  m_built_in_docstrings_file.c_str ());
894 
895  // Ignore header;
896  file.ignore (std::numeric_limits<std::streamsize>::max(), 0x1d);
897 
898  if (file.eof ())
899  error ("invalid built-in-docstrings file!");
900 
901  // FIXME: eliminate fixed buffer size.
902  std::size_t bufsize = 1000;
903  OCTAVE_LOCAL_BUFFER (char, buf, bufsize);
904 
905  while (! file.eof ())
906  {
907  std::string name;
908  int i = 0;
909  int c;
910  while (file
911  && (c = file.get ()) != std::istream::traits_type::eof ())
912  {
913  if (c == '\n' || c == '\r')
914  {
915  buf[i] = '\0';
916  name = buf;
917  break;
918  }
919  else
920  buf[i++] = c;
921  }
922 
923  // Skip @c FILENAME which is part of current DOCSTRINGS
924  // syntax. This may disappear if a specific format for
925  // docstring files is developed.
926  while (file
927  && (c = file.get ()) != std::istream::traits_type::eof ()
928  && c != '\n' && c != '\r')
929  ; // skip text
930 
931  // skip newline characters
932  while (file
933  && (c = file.get ()) != std::istream::traits_type::eof ()
934  && (c == '\n' || c == '\r'))
935  ; // skip text
936 
937  file.unget ();
938 
939  // Position of beginning of help text.
940  std::streampos beg = file.tellg ();
941 
942  // Skip help text.
943  file.ignore (std::numeric_limits<std::streamsize>::max(), 0x1d);
944 
945  // Position of end of help text.
946  std::streamoff len;
947 
948  if (! file.eof ())
949  len = file.tellg () - beg - 1;
950  else
951  {
952  file.seekg (0, file.end);
953  len = file.tellg () - beg - 1;
954  file.setstate (file.eofbit); // reset eof flag
955  }
956 
957  help_txt_map[name] = txt_limits_type (beg, len);
958  }
959 
960  initialized = true;
961  }
962 
963  help_txt_map_type::const_iterator it = help_txt_map.find (nm);
964 
965  if (it != help_txt_map.end ())
966  {
967  txt_limits_type txt_limits = it->second;
968 
969  std::streampos beg = txt_limits.first;
970  std::streamoff len = txt_limits.second;
971 
972  std::ifstream file = sys::ifstream (m_built_in_docstrings_file.c_str (),
973  std::ios::in | std::ios::binary);
974 
975  if (! file)
976  error ("failed to open docstrings file: %s",
977  m_built_in_docstrings_file.c_str ());
978 
979  file.seekg (beg);
980 
981  std::size_t txt_len = len;
982  OCTAVE_LOCAL_BUFFER (char, buf, txt_len + 1);
983 
984  file.read (buf, txt_len);
985 
986  buf[txt_len] = '\0';
987 
988  h = buf;
989 
990  symbol_found = true;
991  }
992 
993  return symbol_found;
994 }
995 
996 // FIXME: It's not likely that this does the right thing now.
997 
1000 {
1001  help_system& help_sys = __get_help_system__ ();
1002 
1003  return help_sys.make_name_list ();
1004 }
1005 
1006 DEFMETHOD (get_help_text, interp, args, ,
1007  doc: /* -*- texinfo -*-
1008 @deftypefn {} {[@var{text}, @var{format}] =} get_help_text (@var{name})
1009 Return the raw help text of function @var{name}.
1010 
1011 The raw help text is returned in @var{text} and the format in @var{format}.
1012 The format is a string which is one of @qcode{"texinfo"}, @qcode{"html"}, or
1013 @w{@qcode{"plain text"}}.
1014 @seealso{get_help_text_from_file}
1015 @end deftypefn */)
1016 {
1017  if (args.length () != 1)
1018  print_usage ();
1019 
1020  const std::string name = args(0).xstring_value ("get_help_text: NAME must be a string");
1021 
1022  help_system& help_sys = interp.get_help_system ();
1023 
1024  std::string text, format;
1025 
1026  help_sys.get_help_text (name, text, format);
1027 
1028  return ovl (text, format);
1029 }
1030 
1031 DEFMETHOD (get_help_text_from_file, interp, args, ,
1032  doc: /* -*- texinfo -*-
1033 @deftypefn {} {[@var{text}, @var{format}] =} get_help_text_from_file (@var{fname})
1034 Return the raw help text from the file @var{fname}.
1035 
1036 The raw help text is returned in @var{text} and the format in @var{format}.
1037 The format is a string which is one of @qcode{"texinfo"}, @qcode{"html"}, or
1038 @w{@qcode{"plain text"}}.
1039 @seealso{get_help_text}
1040 @end deftypefn */)
1041 {
1042  if (args.length () != 1)
1043  print_usage ();
1044 
1045  const std::string fname = args(0).xstring_value ("get_help_text_from_file: NAME must be a string");
1046 
1047  help_system& help_sys = interp.get_help_system ();
1048 
1049  std::string text, format;
1050 
1051  help_sys.get_help_text_from_file (fname, text, format);
1052 
1053  return ovl (text, format);
1054 }
1055 
1056 // Return a cell array of strings containing the names of all operators.
1057 
1058 DEFUN (__operators__, , ,
1059  doc: /* -*- texinfo -*-
1060 @deftypefn {} {@var{cstr} =} __operators__ ()
1061 Return a cell array of strings of all possible Octave operators.
1062 @end deftypefn */)
1063 {
1064  return ovl (Cell (operator_names));
1065 }
1066 
1067 // Return a cell array of strings containing the names of all keywords.
1068 // iskeyword() function is located in lex.ll and is based on what the parser
1069 // thinks is a keyword.
1070 
1071 DEFALIAS (__keywords__, iskeyword)
1072 
1073 // Return a cell array of strings with the names of all builtin functions.
1074 
1075 DEFMETHOD (__builtins__, interp, , ,
1076  doc: /* -*- texinfo -*-
1077 @deftypefn {} {} __builtins__ ()
1078 Return a cell array of all builtin (compiled) functions available to Octave.
1079 @end deftypefn */)
1080 {
1081  symbol_table& symtab = interp.get_symbol_table ();
1082 
1083  const string_vector bif = symtab.built_in_function_names ();
1084 
1085  return ovl (Cell (bif));
1086 }
1087 
1088 DEFMETHOD (localfunctions, interp, args, ,
1089  doc: /* -*- texinfo -*-
1090 @deftypefn {} {@var{subfcn_list} =} localfunctions ()
1091 Return a list of all local functions, i.e., subfunctions, within the current
1092 file.
1093 
1094 The return value is a column cell array of function handles to all local
1095 functions accessible from the function from which @code{localfunctions} is
1096 called. Nested functions are @emph{not} included in the list.
1097 
1098 If the call is from the command line, an anonymous function, or a script,
1099 the return value is an empty cell array.
1100 
1101 @seealso{functions}
1102 @end deftypefn */)
1103 {
1104  if (args.length () != 0)
1105  print_usage ();
1106 
1107  Cell retval;
1108 
1109  // Find the main function we are in.
1110  tree_evaluator& tw = interp.get_evaluator ();
1111  octave_user_code *caller = tw.debug_user_code ();
1112 
1113  if (! caller)
1114  return ovl (retval);
1115 
1116  symbol_scope scope = caller->scope ();
1117 
1118  return ovl (Cell (scope.localfunctions ()));
1119 }
1120 
1121 /*
1122 %!test
1123 %! f = tempname (tempdir (), "oct_");
1124 %! [~, fcn_name] = fileparts (f);
1125 %! f = [f ".m"];
1126 %! save_path = path ();
1127 %! unwind_protect
1128 %! addpath (tempdir ());
1129 %! fid = fopen (f, "w+");
1130 %! fprintf (fid, "function z = %s\n z = localfunctions; end\n", fcn_name);
1131 %! fprintf (fid, "function z = b(x)\n z = x+1; end\n");
1132 %! fprintf (fid, "function z = c(x)\n z = 2*x; end\n");
1133 %! fclose (fid);
1134 %! d = eval (fcn_name);
1135 %! assert (size (d), [2, 1]);
1136 %! assert (d{1} (3), 4);
1137 %! assert (d{2} (3), 6);
1138 %! unwind_protect_cleanup
1139 %! unlink (f);
1140 %! path (save_path);
1141 %! end_unwind_protect
1142 */
1143 
1144 DEFMETHOD (__which__, interp, args, ,
1145  doc: /* -*- texinfo -*-
1146 @deftypefn {} {@var{var_struct} =} __which__ (@var{name}, @dots{})
1147 Undocumented internal function.
1148 @end deftypefn */)
1149 {
1150  help_system& help_sys = interp.get_help_system ();
1151 
1152  string_vector argv = args.make_argv ();
1153 
1154  int nargin = argv.numel ();
1155 
1156  octave_map m (dim_vector (1, nargin));
1157 
1158  Cell names (1, nargin);
1159  Cell files (1, nargin);
1160  Cell types (1, nargin);
1161 
1162  for (int i = 0; i < nargin; i++)
1163  {
1164  std::string name = argv[i];
1165 
1166  std::string type;
1167 
1168  std::string file = help_sys.which (name, type);
1169 
1170  names(i) = name;
1171  files(i) = file;
1172  types(i) = type;
1173  }
1174 
1175  m.assign ("name", names);
1176  m.assign ("file", files);
1177  m.assign ("type", types);
1178 
1179  return ovl (m);
1180 }
1181 
1182 // Return a cell array of strings containing the names of all
1183 // functions available in DIRECTORY. If no directory is given, search
1184 // the current path.
1185 
1186 DEFMETHOD (__list_functions__, interp, args, ,
1187  doc: /* -*- texinfo -*-
1188 @deftypefn {} {@var{retval} =} __list_functions__ ()
1189 @deftypefnx {} {@var{retval} =} __list_functions__ (@var{directory})
1190 Return a list of all functions (.m and .oct functions) in the load path.
1191 
1192 If the optional argument @var{directory} is given then list only the functions
1193 in that directory.
1194 @seealso{path}
1195 @end deftypefn */)
1196 {
1197  octave_value retval;
1198 
1199  load_path& lp = interp.get_load_path ();
1200 
1201  if (args.length () == 0)
1202  {
1203  // Get list of all functions
1204  string_vector ffl = lp.fcn_names ();
1205  string_vector afl = interp.autoloaded_functions ();
1206 
1207  retval = Cell (ffl.append (afl));
1208  }
1209  else
1210  {
1211  std::string dir = args(0).xstring_value ("__list_functions__: DIRECTORY argument must be a string");
1212 
1213  string_vector fl = lp.files (dir, true);
1214 
1215  // Return a sorted list with unique entries (in case of .m and .oct
1216  // versions of the same function in a given directory, for example).
1217  fl.sort (true);
1218 
1219  retval = Cell (fl);
1220  }
1221 
1222  return retval;
1223 }
1224 
1225 DEFMETHOD (built_in_docstrings_file, interp, args, nargout,
1226  doc: /* -*- texinfo -*-
1227 @deftypefn {} {@var{val} =} built_in_docstrings_file ()
1228 @deftypefnx {} {@var{old_val} =} built_in_docstrings_file (@var{new_val})
1229 @deftypefnx {} {@var{old_val} =} built_in_docstrings_file (@var{new_val}, "local")
1230 Query or set the internal variable that specifies the name of the
1231 file containing docstrings for built-in Octave functions.
1232 
1233 The default value is
1234 @file{@var{octave-home}/share/octave/@var{version}/etc/built-in-docstrings},
1235 in which @var{octave-home} is the root directory of the Octave installation,
1236 and @var{version} is the Octave version number. The default value may be
1237 overridden by the environment variable
1238 @w{@env{OCTAVE_BUILT_IN_DOCSTRINGS_FILE}}, or the command line argument
1239 @option{--built-in-docstrings-file FNAME}.
1240 
1241 Note: This variable is only used when Octave is initializing itself.
1242 Modifying it during a running session of Octave will have no effect.
1243 @end deftypefn */)
1244 {
1245  help_system& help_sys = interp.get_help_system ();
1246 
1247  return help_sys.built_in_docstrings_file (args, nargout);
1248 }
1249 
1250 DEFMETHOD (doc_cache_file, interp, args, nargout,
1251  doc: /* -*- texinfo -*-
1252 @deftypefn {} {@var{val} =} doc_cache_file ()
1253 @deftypefnx {} {@var{old_val} =} doc_cache_file (@var{new_val})
1254 @deftypefnx {} {@var{old_val} =} doc_cache_file (@var{new_val}, "local")
1255 Query or set the internal variable that specifies the name of the
1256 Octave documentation cache file.
1257 
1258 A cache file significantly improves the performance of the @code{lookfor}
1259 command. The default value is
1260 @file{@var{octave-home}/share/octave/@var{version}/etc/doc-cache},
1261 in which @var{octave-home} is the root directory of the Octave installation,
1262 and @var{version} is the Octave version number.
1263 The default value may be overridden by the environment variable
1264 @w{@env{OCTAVE_DOC_CACHE_FILE}}, or the command line argument
1265 @option{--doc-cache-file FNAME}.
1266 
1267 When called from inside a function with the @qcode{"local"} option, the
1268 variable is changed locally for the function and any subroutines it calls.
1269 The original variable value is restored when exiting the function.
1270 @seealso{doc_cache_create, lookfor, info_program, doc, help, makeinfo_program}
1271 @seealso{lookfor}
1272 @end deftypefn */)
1273 {
1274  help_system& help_sys = interp.get_help_system ();
1275 
1276  return help_sys.doc_cache_file (args, nargout);
1277 }
1278 
1279 DEFMETHOD (info_file, interp, args, nargout,
1280  doc: /* -*- texinfo -*-
1281 @deftypefn {} {@var{val} =} info_file ()
1282 @deftypefnx {} {@var{old_val} =} info_file (@var{new_val})
1283 @deftypefnx {} {@var{old_val} =} info_file (@var{new_val}, "local")
1284 Query or set the internal variable that specifies the name of the
1285 Octave info file.
1286 
1287 The default value is
1288 @file{@var{octave-home}/share/info/octave.info}, in
1289 which @var{octave-home} is the root directory of the Octave installation.
1290 The default value may be overridden by the environment variable
1291 @w{@env{OCTAVE_INFO_FILE}}, or the command line argument
1292 @option{--info-file FNAME}.
1293 
1294 When called from inside a function with the @qcode{"local"} option, the
1295 variable is changed locally for the function and any subroutines it calls.
1296 The original variable value is restored when exiting the function.
1297 @seealso{info_program, doc, help, makeinfo_program}
1298 @end deftypefn */)
1299 {
1300  help_system& help_sys = interp.get_help_system ();
1301 
1302  return help_sys.info_file (args, nargout);
1303 }
1304 
1305 DEFMETHOD (info_program, interp, args, nargout,
1306  doc: /* -*- texinfo -*-
1307 @deftypefn {} {@var{val} =} info_program ()
1308 @deftypefnx {} {@var{old_val} =} info_program (@var{new_val})
1309 @deftypefnx {} {@var{old_val} =} info_program (@var{new_val}, "local")
1310 Query or set the internal variable that specifies the name of the
1311 info program to run.
1312 
1313 The default value is @file{info}. The default value may be
1314 overridden by the environment variable @w{@env{OCTAVE_INFO_PROGRAM}}, or the
1315 command line argument @option{--info-program NAME}.
1316 
1317 When called from inside a function with the @qcode{"local"} option, the
1318 variable is changed locally for the function and any subroutines it calls.
1319 The original variable value is restored when exiting the function.
1320 @seealso{info_file, doc, help, makeinfo_program}
1321 @end deftypefn */)
1322 {
1323  help_system& help_sys = interp.get_help_system ();
1324 
1325  return help_sys.info_program (args, nargout);
1326 }
1327 
1328 DEFMETHOD (makeinfo_program, interp, args, nargout,
1329  doc: /* -*- texinfo -*-
1330 @deftypefn {} {@var{val} =} makeinfo_program ()
1331 @deftypefnx {} {@var{old_val} =} makeinfo_program (@var{new_val})
1332 @deftypefnx {} {@var{old_val} =} makeinfo_program (@var{new_val}, "local")
1333 Query or set the internal variable that specifies the name of the
1334 program that Octave runs to format help text containing
1335 Texinfo markup commands.
1336 
1337 The default value is @code{makeinfo}.
1338 
1339 When called from inside a function with the @qcode{"local"} option, the
1340 variable is changed locally for the function and any subroutines it calls.
1341 The original variable value is restored when exiting the function.
1342 @seealso{texi_macros_file, info_file, info_program, doc, help}
1343 @end deftypefn */)
1344 {
1345  help_system& help_sys = interp.get_help_system ();
1346 
1347  return help_sys.makeinfo_program (args, nargout);
1348 }
1349 
1350 DEFMETHOD (suppress_verbose_help_message, interp, args, nargout,
1351  doc: /* -*- texinfo -*-
1352 @deftypefn {} {@var{val} =} suppress_verbose_help_message ()
1353 @deftypefnx {} {@var{old_val} =} suppress_verbose_help_message (@var{new_val})
1354 @deftypefnx {} {@var{old_val} =} suppress_verbose_help_message (@var{new_val}, "local")
1355 Query or set the internal variable that controls whether Octave
1356 will add additional help information to the end of the output from
1357 the @code{help} command and usage messages for built-in commands.
1358 
1359 When called from inside a function with the @qcode{"local"} option, the
1360 variable is changed locally for the function and any subroutines it calls.
1361 The original variable value is restored when exiting the function.
1362 @end deftypefn */)
1363 {
1364  help_system& help_sys = interp.get_help_system ();
1365 
1366  return help_sys.suppress_verbose_help_message (args, nargout);
1367 }
1368 
1369 DEFMETHOD (texi_macros_file, interp, args, nargout,
1370  doc: /* -*- texinfo -*-
1371 @deftypefn {} {@var{val} =} texi_macros_file ()
1372 @deftypefnx {} {@var{old_val} =} texi_macros_file (@var{new_val})
1373 @deftypefnx {} {@var{old_val} =} texi_macros_file (@var{new_val}, "local")
1374 Query or set the internal variable that specifies the name of the
1375 file containing Texinfo macros that are prepended to documentation strings
1376 before they are passed to makeinfo.
1377 
1378 The default value is
1379 @file{@var{octave-home}/share/octave/@var{version}/etc/macros.texi},
1380 in which @var{octave-home} is the root directory of the Octave installation,
1381 and @var{version} is the Octave version number.
1382 The default value may be overridden by the environment variable
1383 @w{@env{OCTAVE_TEXI_MACROS_FILE}}, or the command line argument
1384 @option{--texi-macros-file FNAME}.
1385 
1386 When called from inside a function with the @qcode{"local"} option, the
1387 variable is changed locally for the function and any subroutines it calls.
1388 The original variable value is restored when exiting the function.
1389 @seealso{makeinfo_program}
1390 @end deftypefn */)
1391 {
1392  help_system& help_sys = interp.get_help_system ();
1393 
1394  return help_sys.texi_macros_file (args, nargout);
1395 }
1396 
1397 OCTAVE_END_NAMESPACE(octave)
octave_value_list Fiskeyword(const octave_value_list &=octave_value_list(), int=0)
Definition: lex.cc:4931
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
Definition: Cell.h:43
octave_value get_method(const std::string &nm) const
Definition: cdef-class.h:351
void file_name(const std::string &nm)
Definition: cdef-class.h:402
cdef_property find_property(const std::string &nm)
Definition: cdef-class.h:463
cdef_package find_package(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
cdef_class find_class(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
void doc_string(const std::string &txt)
Definition: cdef-object.h:694
bool ok() const
Definition: cdef-object.h:312
octave_value find(const std::string &nm)
Definition: cdef-package.h:213
std::string get_name() const
Definition: cdef-package.h:211
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
string_vector make_name_list() const
std::string texi_macros_file() const
Definition: help.h:121
void get_help_text_from_file(const std::string &fname, std::string &text, std::string &format) const
void get_help_text(const std::string &name, std::string &text, std::string &format) const
octave_value built_in_docstrings_file(const octave_value_list &args, int nargout)
std::string raw_help(const std::string &, bool &) const
std::string info_file() const
Definition: help.h:81
std::string info_program() const
Definition: help.h:90
bool suppress_verbose_help_message() const
Definition: help.h:109
std::string which(const std::string &name) const
octave_value info_file(const octave_value_list &args, int nargout)
octave_value info_program(const octave_value_list &args, int nargout)
std::string built_in_docstrings_file() const
Definition: help.h:63
octave_value suppress_verbose_help_message(const octave_value_list &args, int nargout)
std::string doc_cache_file() const
Definition: help.h:72
octave_value doc_cache_file(const octave_value_list &args, int nargout)
std::string makeinfo_program() const
Definition: help.h:99
octave_value makeinfo_program(const octave_value_list &args, int nargout)
octave_value texi_macros_file(const octave_value_list &args, int nargout)
std::list< std::string > autoloaded_functions() const
std::list< std::string > variable_names()
cdef_manager & get_cdef_manager()
Definition: interpreter.h:318
symbol_table & get_symbol_table()
Definition: interpreter.h:298
tree_evaluator & get_evaluator()
load_path & get_load_path()
Definition: interpreter.h:283
string_vector files(const std::string &dir, bool omit_exts=false) const
Definition: load-path.cc:869
string_vector fcn_names() const
Definition: load-path.cc:897
std::string find_file(const std::string &file) const
Definition: load-path.cc:575
std::string find_fcn_file(const std::string &fcn, const std::string &pack_name="")
Definition: load-path.h:129
virtual bool is_classdef_meta() const
Definition: ov-base.h:453
virtual bool is_user_function() const
Definition: ov-base.h:535
bool is_classdef_method(const std::string &cname="") const
Definition: ov-classdef.cc:443
std::string file_name() const
Definition: ov-classdef.cc:526
bool is_classdef_constructor(const std::string &cname="") const
Definition: ov-classdef.cc:463
virtual bool is_subfunction() const
Definition: ov-fcn.h:106
virtual octave::symbol_scope parent_fcn_scope() const
Definition: ov-fcn.h:84
virtual std::string doc_string(const std::string &="") const
Definition: ov-fcn.h:219
virtual std::string src_file_name() const
Definition: ov-fcn.h:77
virtual std::string fcn_file_name() const
Definition: ov-fcn.h:75
virtual std::list< std::string > subfunction_names() const
Definition: ov-fcn.h:199
octave::symbol_scope scope()
Definition: ov-usr-fcn.h:90
bool is_classdef_meta() const
Definition: ov.h:652
bool is_user_script() const
Definition: ov.h:780
bool is_function() const
Definition: ov.h:777
octave_function * function_value(bool silent=false) const
string_vector & append(const std::string &s)
Definition: str-vec.cc:110
string_vector & sort(bool make_uniq=false)
Definition: str-vec.cc:77
void resize(octave_idx_type n, const std::string &rfv="")
Definition: str-vec.h:95
octave_idx_type numel() const
Definition: str-vec.h:100
octave_user_code * user_code() const
Definition: symscope.h:613
std::list< octave_value > localfunctions() const
Definition: symscope.cc:383
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition: symtab.cc:254
std::list< std::string > cmdline_function_names()
Definition: symtab.cc:639
std::list< std::string > built_in_function_names()
Definition: symtab.cc:620
octave_user_code * current_user_code() const
Definition: pt-eval.cc:2543
octave_user_code * debug_user_code() const
Definition: pt-eval.cc:2555
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define OCTAVE_TEXI_MACROS_FILE
Definition: default-defs.h:184
#define OCTAVE_INFOFILE
Definition: default-defs.h:180
#define OCTAVE_DOC_CACHE_FILE
Definition: default-defs.h:188
std::string prepend_octave_home(const std::string &s)
std::string oct_etc_dir()
void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
#define DEFALIAS(alias, name)
Macro to define an alias for another existing function name.
Definition: defun.h:160
void() error(const char *fmt,...)
Definition: error.cc:988
std::string dir_sep_str()
string_vector make_name_list()
help_system & __get_help_system__()
bool iskeyword(const std::string &s)
Definition: lex.cc:1335
F77_RET_T const F77_DBLE const F77_DBLE * f
std::ifstream ifstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:621
T octave_idx_type m
Definition: mx-inlines.cc:781
std::complex< double > w(std::complex< double > z, double relerr=0)
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:583
std::string get_help_from_file(const std::string &nm, bool &symbol_found, std::string &full_file)
Definition: oct-parse.cc:10107
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219
std::size_t format(std::ostream &os, const char *fmt,...)
F77_RET_T len
Definition: xerbla.cc:61