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