GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
fcn-info.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2022 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 "file-ops.h"
31#include "file-stat.h"
32#include "oct-env.h"
33
34#include "defun.h"
35#include "fcn-info.h"
36#include "interpreter-private.h"
37#include "interpreter.h"
38#include "load-path.h"
39#include "ov-fcn.h"
40#include "ov-usr-fcn.h"
41#include "parse.h"
42#include "symscope.h"
43#include "symtab.h"
44#include "utils.h"
45
46// Should Octave always check to see if function files have changed
47// since they were last compiled?
49
50OCTAVE_NAMESPACE_BEGIN
51
54 {
55 octave_value retval;
56
57 load_path& lp
58 = __get_load_path__ ("fcn_info::fcn_info_rep::load_private_function");
59
60 std::string file_name = lp.find_private_fcn (dir_name, name);
61
62 if (file_name.empty ())
63 return retval;
64
65 octave_value ov_fcn = load_fcn_from_file (file_name, dir_name);
66
67 if (ov_fcn.is_undefined ())
68 return retval;
69
70 octave_function *tmpfcn = ov_fcn.function_value ();
71
72 if (! tmpfcn)
73 return retval;
74
75 std::string class_name;
76
77 std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
78
79 if (pos != std::string::npos)
80 {
81 std::string tmp = dir_name.substr (pos+1);
82
83 if (tmp[0] == '@')
84 class_name = tmp.substr (1);
85 }
86
87 tmpfcn->mark_as_private_function (class_name);
88
90
91 return ov_fcn;
92 }
93
96 {
97 octave_value retval;
98
99 std::string dir_name;
100
101 load_path& lp
102 = __get_load_path__ ("fcn_info::fcn_info_rep::load_class_constructor");
103
104 std::string file_name = lp.find_method (name, name, dir_name, package_name);
105
106 if (! file_name.empty ())
107 {
108 octave_value ov_fcn
109 = load_fcn_from_file (file_name, dir_name, name,
110 package_name);
111
112 if (ov_fcn.is_defined ())
113 {
114 // Note: ov_fcn may be an octave_classdef_meta object instead
115 // of the actual constructor function.
116
117 retval = ov_fcn;
118
119 class_constructors[name] = retval;
120 class_methods[name] = retval;
121 }
122 }
123 else
124 {
125 // Classdef constructors can be defined anywhere in the path, not
126 // necessarily in @-folders. Look for a normal function and load it.
127 // If the loaded function is a classdef constructor, store it as such
128 // and restore function_on_path to its previous value.
129
130 octave_value old_function_on_path = function_on_path;
131
132 octave_value maybe_cdef_ctor = find_user_function ();
133
134 if (maybe_cdef_ctor.is_defined ())
135 {
136 octave_function *fcn = maybe_cdef_ctor.function_value (true);
137
138 if (fcn && fcn->is_classdef_constructor ())
139 {
140 retval = maybe_cdef_ctor;
141
142 class_constructors[name] = retval;
143 class_methods[name] = retval;
144
145 function_on_path = old_function_on_path;
146 }
147 }
148 }
149
150 return retval;
151 }
152
154 fcn_info::fcn_info_rep::load_class_method (const std::string& dispatch_type)
155 {
156 octave_value retval;
157
158 if (full_name () == dispatch_type)
159 retval = load_class_constructor ();
160 else
161 {
162 cdef_manager& cdm
163 = __get_cdef_manager__ ("fcn_info::fcn_info_rep::load_class_method");
164
165 retval = cdm.find_method_symbol (name, dispatch_type);
166
167 if (! retval.is_defined ())
168 {
169 std::string dir_name;
170
171 load_path& lp = __get_load_path__ ("fcn_info::fcn_info_rep::load_class_method");
172
173 std::string file_name = lp.find_method (dispatch_type, name,
174 dir_name);
175
176 if (! file_name.empty ())
177 {
178 octave_value ov_fcn
179 = load_fcn_from_file (file_name, dir_name,
180 dispatch_type);
181
182 if (ov_fcn.is_defined ())
183 {
184 octave_function *tmpfcn = ov_fcn.function_value ();
185
186 if (tmpfcn && tmpfcn->is_class_method (dispatch_type))
187 {
188 retval = ov_fcn;
189
190 class_methods[dispatch_type] = retval;
191 }
192 }
193 }
194
195 if (retval.is_undefined ())
196 {
197 // Search parent classes
198
199 symbol_table& symtab
200 = __get_symbol_table__ ("fcn_info::fcn_info_rep::load_class_method");
201
202 const std::list<std::string>& plist
203 = symtab.parent_classes (dispatch_type);
204
205 auto it = plist.begin ();
206
207 while (it != plist.end ())
208 {
209 retval = find_method (*it);
210
211 if (retval.is_defined ())
212 {
213 class_methods[dispatch_type] = retval;
214 break;
215 }
216
217 it++;
218 }
219 }
220
221 if (retval.is_undefined ())
222 {
223 // Search for built-in functions that are declared to
224 // handle specific types.
225
226 if (built_in_function.is_defined ())
227 {
228 octave_function *fcn = built_in_function.function_value ();
229
230 if (fcn && fcn->handles_dispatch_class (dispatch_type))
231 {
232 retval = built_in_function;
233
234 class_methods[dispatch_type] = retval;
235 }
236 }
237 }
238 }
239 }
240
241 return retval;
242 }
243
244 // :-) JWE, can you parse this? Returns a 2D array with second dimension equal
245 // to btyp_num_types (static constant). Only the leftmost dimension can be
246 // variable in C/C++. Typedefs are boring.
247
249 {
251 for (int i = 0; i < btyp_num_types; i++)
252 for (int j = 0; j < btyp_num_types; j++)
253 {
254 builtin_type_t ityp = static_cast<builtin_type_t> (i);
255 builtin_type_t jtyp = static_cast<builtin_type_t> (j);
256 // FIXME: Is this really right?
257 bool use_j
258 = (jtyp == btyp_func_handle || ityp == btyp_bool
259 || (btyp_isarray (ityp)
260 && (! btyp_isarray (jtyp)
261 || (btyp_isinteger (jtyp) && ! btyp_isinteger (ityp))
262 || ((ityp == btyp_double || ityp == btyp_complex
263 || ityp == btyp_char)
264 && (jtyp == btyp_float
265 || jtyp == btyp_float_complex)))));
266
267 sup_table[i][j] = (use_j ? jtyp : ityp);
268 }
269
270 return sup_table;
271 }
272
273 std::string
275 builtin_type_t& builtin_type)
276 {
277 static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
278 std::string dispatch_type;
279
280 int n = args.length ();
281
282 if (n > 0)
283 {
284 int i = 0;
285 builtin_type = args(0).builtin_type ();
286 if (builtin_type != btyp_unknown)
287 {
288 for (i = 1; i < n; i++)
289 {
290 builtin_type_t bti = args(i).builtin_type ();
291 if (bti != btyp_unknown)
292 builtin_type = sup_table[builtin_type][bti];
293 else
294 {
295 builtin_type = btyp_unknown;
296 break;
297 }
298 }
299 }
300
301 if (builtin_type == btyp_unknown)
302 {
303 // There's a non-builtin class in the argument list.
304 dispatch_type = args(i).class_name ();
305
306 symbol_table& symtab = __get_symbol_table__ ("get_dispatch_type");
307
308 for (int j = i+1; j < n; j++)
309 {
310 octave_value arg = args(j);
311
312 if (arg.builtin_type () == btyp_unknown)
313 {
314 std::string cname = arg.class_name ();
315
316 // Only switch to type of ARG if it is marked superior
317 // to the current DISPATCH_TYPE.
318 if (! symtab.is_superiorto (dispatch_type, cname)
319 && symtab.is_superiorto (cname, dispatch_type))
320 dispatch_type = cname;
321 }
322 }
323 }
324 else
325 dispatch_type = btyp_class_name[builtin_type];
326 }
327 else
328 builtin_type = btyp_unknown;
329
330 return dispatch_type;
331 }
332
333 std::string
335 {
336 builtin_type_t builtin_type;
337 return get_dispatch_type (args, builtin_type);
338 }
339
340 // Find function definition according to the following precedence list:
341 //
342 // nested functions (and subfunctions)
343 // local functions in the current file
344 // private function
345 // class method
346 // class constructor
347 // command-line function
348 // autoload function
349 // functions on the load_path (current directory is always first)
350 // package (FIXME: does this belong here?)
351 // built-in function
352
354 fcn_info::fcn_info_rep::find (const symbol_scope& scope,
355 const octave_value_list& args)
356 {
357 symbol_scope search_scope
358 = (scope
359 ? scope : __get_current_scope__("fcn_info::fcn_info_rep::find"));
360
361 octave_value retval = xfind (search_scope, args);
362
363 if (retval.is_undefined ())
364 {
365 // It is possible that the user created a file on the fly since
366 // the last prompt or chdir, so try updating the load path and
367 // searching again.
368
369 load_path& lp = __get_load_path__ ("fcn_info::fcn_info_rep::find");
370
371 lp.update ();
372
373 retval = xfind (search_scope, args);
374 }
375
376 return retval;
377 }
378
379
380 static void
381 split_name_with_package (const std::string& name, std::string& fname,
382 std::string& pname)
383 {
384 std::size_t pos = name.rfind ('.');
385
386 fname.clear ();
387 pname.clear ();
388
389 if (pos != std::string::npos)
390 {
391 fname = name.substr (pos + 1);
392 pname = name.substr (0, pos);
393 }
394 else
395 fname = name;
396 }
397
398 // Check the load path to see if file that defined this is still
399 // visible. If the file is no longer visible, then erase the
400 // definition and move on. If the file is visible, then we also
401 // need to check to see whether the file has changed since the
402 // function was loaded/parsed. However, this check should only
403 // happen once per prompt (for files found from relative path
404 // elements, we also check if the working directory has changed
405 // since the last time the function was loaded/parsed).
406 //
407 // FIXME: perhaps this should be done for all loaded functions when
408 // the prompt is printed or the directory has changed, and then we
409 // would not check for it when finding symbol definitions.
410
411 static inline bool
412 load_out_of_date_fcn (const std::string& file_name,
413 const std::string& dir_name_arg,
414 octave_value& function,
415 const std::string& dispatch_type = "",
416 const std::string& package_name = "")
417 {
418 bool retval = false;
419
420 std::string dir_name = dir_name_arg;
421
422 if (dir_name.empty ())
423 {
424 std::size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
425
426 dir_name = file_name.substr (0, pos);
427 }
428
429 // FIXME: do the following job of determining private status and
430 // class membership in a separate function?
431
432 std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
433
434 bool is_private_fcn
435 = pos != std::string::npos && dir_name.substr (pos+1) == "private";
436
437 if (is_private_fcn)
438 dir_name = dir_name.substr (0, pos);
439
440 std::string class_name;
441
442 pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
443
444 if (pos != std::string::npos)
445 {
446 std::string tmp = dir_name.substr (pos+1);
447
448 if (tmp[0] == '@')
449 class_name = tmp.substr (1);
450 }
451
452 octave_value ov_fcn
453 = load_fcn_from_file (file_name, dir_name, dispatch_type,
454 package_name);
455
456 if (ov_fcn.is_defined ())
457 {
458 retval = true;
459
460 octave_function *fcn = ov_fcn.function_value ();
461
462 if (is_private_fcn)
463 fcn->mark_as_private_function (class_name);
464
465 function = ov_fcn;
466 }
467 else
468 function = octave_value ();
469
470 return retval;
471 }
472
473 static bool
475 const std::string& dispatch_type = "",
476 bool check_relative = true)
477 {
478 bool retval = false;
479
480 octave_function *fcn = function.function_value (true);
481
482 if (fcn)
483 {
484 // FIXME: we need to handle subfunctions properly here.
485
486 if (! (fcn->is_subfunction () || fcn->is_anonymous_function ()))
487 {
488 std::string ff = fcn->fcn_file_name ();
489
490 if (! ff.empty ())
491 {
492 sys::time tc = fcn->time_checked ();
493
494 bool relative = check_relative && fcn->is_relative ();
495
496 if (tc <= Vlast_prompt_time
497 || (relative && tc < Vlast_chdir_time))
498 {
499 bool clear_breakpoints = false;
500 std::string nm = fcn->name ();
501 std::string pack = fcn->package_name ();
502 std::string canonical_nm = fcn->canonical_name ();
503
504 bool is_same_file = false;
505
506 std::string file;
507 std::string dir_name;
508
509 if (check_relative)
510 {
511 int nm_len = nm.length ();
512
514 && ((nm_len > 4
515 && (nm.substr (nm_len-4) == ".oct"
516 || nm.substr (nm_len-4) == ".mex"))
517 || (nm_len > 2
518 && nm.substr (nm_len-2) == ".m")))
519 file = nm;
520 else
521 {
522 // We don't want to make this an absolute name,
523 // because load_fcn_file looks at the name to
524 // decide whether it came from a relative lookup.
525
526 if (! dispatch_type.empty ())
527 {
528 load_path& lp
529 = __get_load_path__ ("out_of_date_check");
530
531 file = lp.find_method (dispatch_type, nm,
532 dir_name, pack);
533
534 if (file.empty ())
535 {
536 std::string s_name;
537 std::string s_pack;
538
539 symbol_table& symtab
540 = __get_symbol_table__ ("out_of_date_check");
541
542 const std::list<std::string>& plist
543 = symtab.parent_classes (dispatch_type);
544
545 std::list<std::string>::const_iterator it
546 = plist.begin ();
547
548 while (it != plist.end ())
549 {
550 split_name_with_package (*it, s_name,
551 s_pack);
552
553 file = lp.find_method (*it, nm, dir_name,
554 s_pack);
555 if (! file.empty ())
556 {
557 pack = s_pack;
558 break;
559 }
560
561 it++;
562 }
563 }
564 }
565
566 // Maybe it's an autoload?
567 if (file.empty ())
568 {
570 = __get_evaluator__ ("out_of_data_check");
571
572 file = tw.lookup_autoload (nm);
573 }
574
575 if (file.empty ())
576 {
577 load_path& lp
578 = __get_load_path__ ("out_of_date_check");
579 file = lp.find_fcn (nm, dir_name, pack);
580 }
581 }
582
583 if (! file.empty ())
584 is_same_file = same_file (file, ff);
585 }
586 else
587 {
588 is_same_file = true;
589 file = ff;
590 }
591
592 if (file.empty ())
593 {
594 // Can't see this function from current
595 // directory, so we should clear it.
596
597 function = octave_value ();
598
599 clear_breakpoints = true;
600 }
601 else if (is_same_file)
602 {
603 // Same file. If it is out of date, then reload it.
604
605 sys::time ottp = fcn->time_parsed ();
606 OCTAVE_TIME_T tp = ottp.unix_time ();
607
608 fcn->mark_fcn_file_up_to_date (sys::time ());
609
612 && fcn->is_system_fcn_file ())))
613 {
614 sys::file_stat fs (ff);
615
616 if (fs)
617 {
618 if (fs.is_newer (tp))
619 {
620 retval = load_out_of_date_fcn (ff, dir_name,
621 function,
622 dispatch_type,
623 pack);
624
625 clear_breakpoints = true;
626 }
627 }
628 else
629 {
630 function = octave_value ();
631
632 clear_breakpoints = true;
633 }
634 }
635 }
636 else
637 {
638 // Not the same file, so load the new file in
639 // place of the old.
640
641 retval = load_out_of_date_fcn (file, dir_name, function,
642 dispatch_type, pack);
643
644 clear_breakpoints = true;
645 }
646
647 // If the function has been replaced then clear any
648 // breakpoints associated with it
649 if (clear_breakpoints)
650 {
651 bp_table& bptab
652 = __get_bp_table__ ("out_of_date_check");
653
654 bptab.remove_all_breakpoints_from_function (canonical_nm,
655 true);
656 }
657 }
658 }
659 }
660 }
661
662 return retval;
663 }
664
666 fcn_info::fcn_info_rep::find_scoped_function (const symbol_scope& search_scope)
667 {
668 if (search_scope)
669 {
670 // Subfunction.
671
672 octave_value fcn = search_scope.find_subfunction (name);
673
674 if (fcn.is_defined ())
675 return fcn;
676
677 // Local function.
678
679 std::string fcn_file = search_scope.fcn_file_name ();
680
681 // For anonymous functions we look at the parent scope so that if
682 // they were defined within class methods and use local functions
683 // (helper functions) we can still use those anonymous functions
684
685 if (! fcn_file.empty ())
686 {
687 auto r = local_functions.find (fcn_file);
688
689 if (r != local_functions.end ())
690 {
691 // We shouldn't need an out-of-date check here since
692 // local functions may ultimately be called only from
693 // a primary function or method defined in the same
694 // file.
695
696 return r->second;
697 }
698 }
699
700 // Private function.
701
702 return find_private_function (search_scope.dir_name ());
703 }
704
705 return octave_value ();
706 }
707
710 {
711 if (! dir_name.empty ())
712 {
713 auto q = private_functions.find (dir_name);
714
715 if (q == private_functions.end ())
716 {
717 octave_value val = load_private_function (dir_name);
718
719 if (val.is_defined ())
720 return val;
721 }
722 else
723 {
724 octave_value& fval = q->second;
725
726 if (fval.is_defined ())
727 out_of_date_check (fval, "", false);
728
729 if (fval.is_defined ())
730 return fval;
731 else
732 {
733 octave_value val = load_private_function (dir_name);
734
735 if (val.is_defined ())
736 return val;
737 }
738 }
739 }
740
741 return octave_value ();
742 }
743
746 {
747 if (! args.empty ())
748 {
749 std::string dispatch_type = get_dispatch_type (args);
750
751 return find_method (dispatch_type);
752 }
753
754 return octave_value ();
755 }
756
758 fcn_info::fcn_info_rep::xfind (const symbol_scope& search_scope,
759 const octave_value_list& args)
760 {
761 // Subfunction, local function, or private function.
762
763 octave_value fcn;
764
765 fcn = find_scoped_function (search_scope);
766
767 if (fcn.is_defined ())
768 return fcn;
769
770 // Class methods.
771
772 fcn = find_method (args);
773
774 if (fcn.is_defined ())
775 return fcn;
776
777 // Class constructors. The class name and function name are the same.
778
779 auto q = class_constructors.find (name);
780
781 if (q == class_constructors.end ())
782 {
783 octave_value val = load_class_constructor ();
784
785 if (val.is_defined ())
786 return val;
787 }
788 else
789 {
790 octave_value& fval = q->second;
791
792 if (fval.is_defined ())
793 out_of_date_check (fval, name);
794
795 if (fval.is_defined ())
796 return fval;
797 else
798 {
799 octave_value val = load_class_constructor ();
800
801 if (val.is_defined ())
802 return val;
803 }
804 }
805
806 // Command-line function.
807
808 if (cmdline_function.is_defined ())
809 return cmdline_function;
810
811 // Autoload?
812
813 fcn = find_autoload ();
814
815 if (fcn.is_defined ())
816 return fcn;
817
818 // Function on the path.
819
820 fcn = find_user_function ();
821
822 if (fcn.is_defined ())
823 return fcn;
824
825 // Package
826
827 fcn = find_package ();
828
829 if (fcn.is_defined ())
830 return fcn;
831
832 // Built-in function (might be undefined).
833
834 return built_in_function;
835 }
836
837 // Find the definition of NAME according to the following precedence
838 // list:
839 //
840 // built-in function
841 // function on the path
842 // autoload function
843 // command-line function
844 // private function
845 // subfunction
846
847 // This function is used to implement the "builtin" function, which
848 // searches for "built-in" functions. In Matlab, "builtin" only
849 // returns functions that are actually built-in to the interpreter.
850 // But since the list of built-in functions is different in Octave and
851 // Matlab, we also search up the precedence list until we find
852 // something that matches. Note that we are only searching by name,
853 // so class methods and constructors are skipped.
854
856 fcn_info::fcn_info_rep::builtin_find (const symbol_scope& scope)
857 {
858 symbol_scope search_scope
859 = (scope
860 ? scope : __get_current_scope__("fcn_info::fcn_info_rep::find"));
861
862 octave_value retval = x_builtin_find (search_scope);
863
864 if (! retval.is_defined ())
865 {
866 // It is possible that the user created a file on the fly since
867 // the last prompt or chdir, so try updating the load path and
868 // searching again.
869
870 load_path& lp = __get_load_path__ ("fcn_info::fcn_info_rep::builtin_find");
871
872 lp.update ();
873
874 retval = x_builtin_find (search_scope);
875 }
876
877 return retval;
878 }
879
881 fcn_info::fcn_info_rep::x_builtin_find (const symbol_scope& search_scope)
882 {
883 // Built-in function.
884 if (built_in_function.is_defined ())
885 return built_in_function;
886
887 // Function on the path.
888
890
891 if (fcn.is_defined ())
892 return fcn;
893
894 // Autoload?
895
896 fcn = find_autoload ();
897
898 if (fcn.is_defined ())
899 return fcn;
900
901 // Command-line function.
902
903 if (cmdline_function.is_defined ())
904 return cmdline_function;
905
906 // Private function, local function, or subfunction.
907
908 if (search_scope)
909 {
910 // Private function.
911
912 std::string dir_name = search_scope.dir_name ();
913
914 if (! dir_name.empty ())
915 {
916 auto q = private_functions.find (dir_name);
917
918 if (q == private_functions.end ())
919 {
920 octave_value val = load_private_function (dir_name);
921
922 if (val.is_defined ())
923 return val;
924 }
925 else
926 {
927 octave_value& fval = q->second;
928
929 if (fval.is_defined ())
930 out_of_date_check (fval);
931
932 if (fval.is_defined ())
933 return fval;
934 else
935 {
936 octave_value val = load_private_function (dir_name);
937
938 if (val.is_defined ())
939 return val;
940 }
941 }
942 }
943
944 // Local function.
945
946 std::string fcn_file = search_scope.fcn_file_name ();
947
948 if (! fcn_file.empty ())
949 {
950 auto r = local_functions.find (fcn_file);
951
952 if (r != local_functions.end ())
953 {
954 // We shouldn't need an out-of-date check here since local
955 // functions may ultimately be called only from a primary
956 // function or method defined in the same file.
957
958 return r->second;
959 }
960 }
961
962 // Subfunction. I think it only makes sense to check for
963 // subfunctions if we are currently executing a function defined
964 // from a .m file.
965
966 octave_value val = search_scope.find_subfunction (name);
967
968 if (val.is_defined ())
969 return val;
970 }
971
972 return octave_value ();
973 }
974
976 fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type)
977 {
978 octave_value retval;
979
980 auto q = class_methods.find (dispatch_type);
981
982 if (q == class_methods.end ())
983 {
984 octave_value val = load_class_method (dispatch_type);
985
986 if (val.is_defined ())
987 return val;
988 }
989 else
990 {
991 octave_value& fval = q->second;
992
993 if (fval.is_defined ())
994 out_of_date_check (fval, dispatch_type);
995
996 if (fval.is_defined ())
997 return fval;
998 else
999 {
1000 octave_value val = load_class_method (dispatch_type);
1001
1002 if (val.is_defined ())
1003 return val;
1004 }
1005 }
1006
1007 return retval;
1008 }
1009
1012 {
1013 // Autoloaded function.
1014
1015 if (autoload_function.is_defined ())
1016 out_of_date_check (autoload_function);
1017
1018 if (! autoload_function.is_defined ())
1019 {
1020 tree_evaluator& tw
1021 = __get_evaluator__ ("fcn_info::fcn_info_rep::x_builtin_find");
1022
1023 std::string file_name = tw.lookup_autoload (name);
1024
1025 if (! file_name.empty ())
1026 {
1027 std::size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
1028
1029 std::string dir_name = file_name.substr (0, pos);
1030
1031 octave_value ov_fcn
1032 = load_fcn_from_file (file_name, dir_name, "", "", name, true);
1033
1034 if (ov_fcn.is_defined ())
1035 autoload_function = octave_value (ov_fcn);
1036 }
1037 }
1038
1039 return autoload_function;
1040 }
1041
1044 {
1045 // Function on the path.
1046
1047 if (function_on_path.is_defined ())
1048 out_of_date_check (function_on_path);
1049
1050 if (function_on_path.is_undefined ())
1051 {
1052 std::string dir_name;
1053
1054 load_path& lp
1055 = __get_load_path__ ("fcn_info::fcn_info_rep::find_user_function");
1056
1057
1058 std::string file_name = lp.find_fcn (name, dir_name, package_name);
1059
1060 if (! file_name.empty ())
1061 {
1062 octave_value ov_fcn
1063 = load_fcn_from_file (file_name, dir_name, "", package_name);
1064
1065 if (ov_fcn.is_defined ())
1066 function_on_path = ov_fcn;
1067 }
1068 }
1069
1070 return function_on_path;
1071 }
1072
1075 {
1076 // FIXME: implement correct way to check out of date package
1077 //if (package.is_defined ())
1078 // out_of_date_check (package);
1079
1080 if (package.is_undefined ())
1081 {
1082 cdef_manager& cdm
1083 = __get_cdef_manager__ ("fcn_info::fcn_info_rep::find_package");
1084
1085 package = cdm.find_package_symbol (full_name ());
1086 }
1087
1088 return package;
1089 }
1090
1091 void
1093 {
1094 if (built_in_function.is_defined ())
1095 {
1096 octave_function *fcn = built_in_function.function_value ();
1097
1098 if (fcn)
1099 {
1100 if (fcn->handles_dispatch_class (klass))
1101 warning ("install_built_in_dispatch: '%s' already defined for class '%s'",
1102 name.c_str (), klass.c_str ());
1103 else
1104 fcn->push_dispatch_class (klass);
1105 }
1106 }
1107 else
1108 error ("install_built_in_dispatch: '%s' is not a built-in function",
1109 name.c_str ());
1110 }
1111
1114 {
1115 std::map<std::string, octave_value> m
1116 = {{ "name", full_name () },
1117 { "package", package.dump () },
1118 { "local_functions", dump_function_map (local_functions) },
1119 { "private_functions", dump_function_map (private_functions) },
1120 { "class_methods", dump_function_map (class_methods) },
1121 { "class_constructors", dump_function_map (class_constructors) },
1122 { "cmdline_function", cmdline_function.dump () },
1123 { "autoload_function", autoload_function.dump () },
1124 { "function_on_path", function_on_path.dump () },
1125 { "built_in_function", built_in_function.dump () }};
1126
1127 return octave_value (m);
1128 }
1129
1131 dump_function_map (const std::map<std::string, octave_value>& fcn_map)
1132 {
1133 if (fcn_map.empty ())
1134 return octave_value (Matrix ());
1135
1136 std::map<std::string, octave_value> info_map;
1137
1138 for (const auto& nm_fcn : fcn_map)
1139 {
1140 std::string nm = nm_fcn.first;
1141 const octave_value& fcn = nm_fcn.second;
1142 info_map[nm] = fcn.dump ();
1143 }
1144
1145 return octave_value (info_map);
1146 }
1147
1148DEFUN (ignore_function_time_stamp, args, nargout,
1149 doc: /* -*- texinfo -*-
1150@deftypefn {} {@var{val} =} ignore_function_time_stamp ()
1151@deftypefnx {} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})
1152Query or set the internal variable that controls whether Octave checks
1153the time stamp on files each time it looks up functions defined in
1154function files.
1155
1156If the internal variable is set to @qcode{"system"}, Octave will not
1157automatically recompile function files in subdirectories of
1158@file{@var{octave-home}/share/@var{version}/m} if they have changed since
1159they were last compiled, but will recompile other function files in the
1160search path if they change.
1161
1162If set to @qcode{"all"}, Octave will not recompile any function files
1163unless their definitions are removed with @code{clear}.
1164
1165If set to @qcode{"none"}, Octave will always check time stamps on files
1166to determine whether functions defined in function files need to
1167recompiled.
1168@end deftypefn */)
1169{
1170 int nargin = args.length ();
1171
1172 if (nargin > 1)
1173 print_usage ();
1174
1175 octave_value retval;
1176
1177 if (nargout > 0 || nargin == 0)
1178 {
1180 {
1181 case 1:
1182 retval = "system";
1183 break;
1184
1185 case 2:
1186 retval = "all";
1187 break;
1188
1189 default:
1190 retval = "none";
1191 break;
1192 }
1193 }
1194
1195 if (nargin == 1)
1196 {
1197 std::string sval = args(0).xstring_value ("ignore_function_time_stamp: first argument must be a string");
1198
1199 if (sval == "all")
1201 else if (sval == "system")
1203 else if (sval == "none")
1205 else
1206 error (R"(ignore_function_time_stamp: argument must be one of "all", "system", or "none")");
1207 }
1208
1209 return retval;
1210}
1211
1212/*
1213%!shared old_state
1214%! old_state = ignore_function_time_stamp ();
1215%!test
1216%! state = ignore_function_time_stamp ("all");
1217%! assert (state, old_state);
1218%! assert (ignore_function_time_stamp (), "all");
1219%! state = ignore_function_time_stamp ("system");
1220%! assert (state, "all");
1221%! assert (ignore_function_time_stamp (), "system");
1222%! ignore_function_time_stamp (old_state);
1223
1224## Test input validation
1225%!error ignore_function_time_stamp ("all", "all")
1226%!error ignore_function_time_stamp ("UNKNOWN_VALUE")
1227%!error ignore_function_time_stamp (42)
1228*/
1229
1230OCTAVE_NAMESPACE_END
Definition: dMatrix.h:42
octave_value find_private_function(const std::string &dir_name)
Definition: fcn-info.cc:709
octave_value builtin_find(const symbol_scope &search_scope)
Definition: fcn-info.cc:856
octave_value xfind(const symbol_scope &search_scope, const octave_value_list &args)
Definition: fcn-info.cc:758
octave_value find_method(const std::string &dispatch_type)
Definition: fcn-info.cc:976
octave_value dump(void) const
Definition: fcn-info.cc:1113
octave_value load_private_function(const std::string &dir_name)
Definition: fcn-info.cc:53
octave_value load_class_constructor(void)
Definition: fcn-info.cc:95
octave_value find_autoload(void)
Definition: fcn-info.cc:1011
octave_value find_user_function(void)
Definition: fcn-info.cc:1043
std::string name
Definition: fcn-info.h:207
std::map< std::string, octave_value > private_functions
Definition: fcn-info.h:215
void install_built_in_dispatch(const std::string &klass)
Definition: fcn-info.cc:1092
octave_value find_package(void)
Definition: fcn-info.cc:1074
octave_value x_builtin_find(const symbol_scope &search_scope)
Definition: fcn-info.cc:881
octave_value find_scoped_function(const symbol_scope &search_scope)
Definition: fcn-info.cc:666
octave_value find(const symbol_scope &search_scope, const octave_value_list &args)
Definition: fcn-info.cc:354
octave_value load_class_method(const std::string &dispatch_type)
Definition: fcn-info.cc:154
octave_value find_method(const std::string &dispatch_type) const
Definition: fcn-info.h:274
octave_value find_scoped_function(const symbol_scope &search_scope) const
Definition: fcn-info.h:264
octave_value find_autoload(void)
Definition: fcn-info.h:289
octave_value find_private_function(const std::string &dir_name) const
Definition: fcn-info.h:269
octave_value find_user_function(void)
Definition: fcn-info.h:295
std::string find_fcn(const std::string &fcn, std::string &dir_name, const std::string &pack_name="")
Definition: load-path.h:111
std::string find_private_fcn(const std::string &dir, const std::string &fcn, const std::string &pack_name="")
Definition: load-path.h:124
void update(void)
Definition: load-path.cc:457
std::string find_method(const std::string &class_name, const std::string &meth, std::string &dir_name, const std::string &pack_name="")
Definition: load-path.h:79
OCTAVE_TIME_T unix_time(void) const
Definition: oct-time.h:110
virtual bool is_anonymous_function(void) const
Definition: ov-base.h:499
virtual octave_function * function_value(bool silent=false)
Definition: ov-base.cc:935
virtual bool handles_dispatch_class(const std::string &) const
Definition: ov-fcn.h:144
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:78
virtual octave::sys::time time_parsed(void) const
Definition: ov-fcn.h:97
bool is_relative(void) const
Definition: ov-fcn.h:205
std::string package_name(void) const
Definition: ov-fcn.h:153
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:116
virtual void push_dispatch_class(const std::string &)
Definition: ov-fcn.h:142
virtual bool is_subfunction(void) const
Definition: ov-fcn.h:109
virtual bool is_classdef_constructor(const std::string &="") const
Definition: ov-fcn.h:126
std::string canonical_name(void) const
Definition: ov-fcn.h:209
virtual octave::sys::time time_checked(void) const
Definition: ov-fcn.h:100
virtual void mark_fcn_file_up_to_date(const octave::sys::time &)
Definition: ov-fcn.h:93
virtual void mark_as_private_function(const std::string &cname="")
Definition: ov-fcn.h:156
std::string name(void) const
Definition: ov-fcn.h:207
virtual bool is_system_fcn_file(void) const
Definition: ov-fcn.h:76
bool empty(void) const
Definition: ovl.h:115
octave_idx_type length(void) const
Definition: ovl.h:113
OCTINTERP_API std::string xstring_value(const char *fmt,...) const
OCTINTERP_API octave_function * function_value(bool silent=false) const
builtin_type_t builtin_type(void) const
Definition: ov.h:735
octave_value dump(void) const
Definition: ov.h:1560
bool is_defined(void) const
Definition: ov.h:637
std::string class_name(void) const
Definition: ov.h:1451
bool is_undefined(void) const
Definition: ov.h:640
bool is_superiorto(const std::string &a, const std::string &b)
Definition: symtab.cc:537
std::list< std::string > parent_classes(const std::string &dispatch_type)
Definition: symtab.cc:669
std::string lookup_autoload(const std::string &nm) const
Definition: pt-eval.cc:4444
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void warning(const char *fmt,...)
Definition: error.cc:1055
void error(const char *fmt,...)
Definition: error.cc:980
std::string get_dispatch_type(const octave_value_list &args, builtin_type_t &builtin_type)
Definition: fcn-info.cc:274
static bool out_of_date_check(octave_value &function, const std::string &dispatch_type="", bool check_relative=true)
Definition: fcn-info.cc:474
static builtin_type_t(* build_sup_table(void))[btyp_num_types]
Definition: fcn-info.cc:248
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
Definition: fcn-info.cc:1131
static bool load_out_of_date_fcn(const std::string &file_name, const std::string &dir_name_arg, octave_value &function, const std::string &dispatch_type="", const std::string &package_name="")
Definition: fcn-info.cc:412
static void split_name_with_package(const std::string &name, std::string &fname, std::string &pname)
Definition: fcn-info.cc:381
static int Vignore_function_time_stamp
Definition: fcn-info.cc:48
QString name
octave::sys::time Vlast_prompt_time
Definition: input.cc:83
sys::time Vlast_chdir_time
Definition: interpreter.cc:335
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:688
cdef_manager & __get_cdef_manager__(const std::string &who)
tree_evaluator & __get_evaluator__(const std::string &who)
symbol_scope __get_current_scope__(const std::string &who)
bp_table & __get_bp_table__(const std::string &who)
load_path & __get_load_path__(const std::string &who)
symbol_table & __get_symbol_table__(const std::string &who)
octave_value load_fcn_from_file(const std::string &file_name, const std::string &dir_name, const std::string &dispatch_type, const std::string &package_name, const std::string &fcn_name, bool autoload)
Definition: oct-parse.cc:10047
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
std::string btyp_class_name[btyp_num_types+1]
Definition: ov-base.cc:89
bool btyp_isinteger(builtin_type_t btyp)
Definition: ov-base.h:102
bool btyp_isarray(builtin_type_t btyp)
Definition: ov-base.h:108
builtin_type_t
Definition: ov-base.h:75
@ btyp_float_complex
Definition: ov-base.h:79
@ btyp_func_handle
Definition: ov-base.h:92
@ btyp_double
Definition: ov-base.h:76
@ btyp_float
Definition: ov-base.h:77
@ btyp_bool
Definition: ov-base.h:88
@ btyp_unknown
Definition: ov-base.h:93
@ btyp_num_types
Definition: ov-base.h:94
@ btyp_char
Definition: ov-base.h:89
@ btyp_complex
Definition: ov-base.h:78
static bool absolute_pathname(const std::string &s)
Definition: shared-fcns.h:148
static std::string dir_sep_chars
Definition: shared-fcns.h:96
bool same_file(const std::string &f, const std::string &g)
Definition: utils.cc:293