GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
load-path.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2006-2013 John W. Eaton
4 Copyright (C) 2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <algorithm>
29 
30 #include "dir-ops.h"
31 #include "file-ops.h"
32 #include "file-stat.h"
33 #include "oct-env.h"
34 #include "pathsearch.h"
35 #include "singleton-cleanup.h"
36 
37 #include "defaults.h"
38 #include "defun.h"
39 #include "input.h"
40 #include "load-path.h"
41 #include "pager.h"
42 #include "parse.h"
43 #include "toplev.h"
44 #include "unwind-prot.h"
45 #include "utils.h"
46 
51 std::string load_path::sys_path;
53 
54 void
56 {
57  file_stat fs (dir_name);
58 
59  if (fs)
60  {
61  if (is_relative)
62  {
63  try
64  {
65  std::string abs_name = octave_env::make_absolute (dir_name);
66 
67  abs_dir_cache_iterator p = abs_dir_cache.find (abs_name);
68 
69  if (p != abs_dir_cache.end ())
70  {
71  // The directory is in the cache of all directories
72  // we have visited (indexed by its absolute name).
73  // If it is out of date, initialize it. Otherwise,
74  // copy the info from the cache. By doing that, we
75  // avoid unnecessary calls to stat that can slow
76  // things down tremendously for large directories.
77 
78  const dir_info& di = p->second;
79 
80  if (fs.mtime () + fs.time_resolution ()
82  initialize ();
83  else
84  *this = di;
85  }
86  else
87  {
88  // We haven't seen this directory before.
89 
90  initialize ();
91  }
92  }
93  catch (octave_execution_exception)
94  {
95  // Skip updating if we don't know where we are, but
96  // don't treat it as an error.
97 
98  error_state = 0;
99  }
100  }
101  else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked)
102  initialize ();
103  }
104  else
105  {
106  std::string msg = fs.error ();
107  warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
108  }
109 }
110 
111 void
113 {
114  is_relative = ! octave_env::absolute_pathname (dir_name);
115 
116  dir_time_last_checked = octave_time (static_cast<time_t> (0));
117 
118  file_stat fs (dir_name);
119 
120  if (fs)
121  {
122  method_file_map.clear ();
123 
124  dir_mtime = fs.mtime ();
125  dir_time_last_checked = octave_time ();
126 
127  get_file_list (dir_name);
128 
129  try
130  {
131  std::string abs_name = octave_env::make_absolute (dir_name);
132 
133  // FIXME: nothing is ever removed from this cache of
134  // directory information, so there could be some resource
135  // problems. Perhaps it should be pruned from time to time.
136 
137  abs_dir_cache[abs_name] = *this;
138  }
139  catch (octave_execution_exception)
140  {
141  // Skip updating if we don't know where we are.
142  }
143  }
144  else
145  {
146  std::string msg = fs.error ();
147  warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
148  }
149 }
150 
151 void
153 {
154  dir_entry dir (d);
155 
156  if (dir)
157  {
158  string_vector flist = dir.read ();
159 
160  octave_idx_type len = flist.length ();
161 
162  all_files.resize (len);
163  fcn_files.resize (len);
164 
165  octave_idx_type all_files_count = 0;
166  octave_idx_type fcn_files_count = 0;
167 
168  for (octave_idx_type i = 0; i < len; i++)
169  {
170  std::string fname = flist[i];
171 
172  std::string full_name = file_ops::concat (d, fname);
173 
174  file_stat fs (full_name);
175 
176  if (fs)
177  {
178  if (fs.is_dir ())
179  {
180  if (fname == "private")
181  get_private_file_map (full_name);
182  else if (fname[0] == '@')
183  get_method_file_map (full_name, fname.substr (1));
184  }
185  else
186  {
187  all_files[all_files_count++] = fname;
188 
189  size_t pos = fname.rfind ('.');
190 
191  if (pos != std::string::npos)
192  {
193  std::string ext = fname.substr (pos);
194 
195  if (ext == ".m" || ext == ".oct" || ext == ".mex")
196  {
197  std::string base = fname.substr (0, pos);
198 
199  if (valid_identifier (base))
200  fcn_files[fcn_files_count++] = fname;
201  }
202  }
203  }
204  }
205  }
206 
207  all_files.resize (all_files_count);
208  fcn_files.resize (fcn_files_count);
209  }
210  else
211  {
212  std::string msg = dir.error ();
213  warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
214  }
215 }
216 
218 get_fcn_files (const std::string& d)
219 {
221 
222  dir_entry dir (d);
223 
224  if (dir)
225  {
226  string_vector flist = dir.read ();
227 
228  octave_idx_type len = flist.length ();
229 
230  for (octave_idx_type i = 0; i < len; i++)
231  {
232  std::string fname = flist[i];
233 
234  std::string ext;
235  std::string base = fname;
236 
237  size_t pos = fname.rfind ('.');
238 
239  if (pos != std::string::npos)
240  {
241  base = fname.substr (0, pos);
242  ext = fname.substr (pos);
243 
244  if (valid_identifier (base))
245  {
246  int t = 0;
247 
248  if (ext == ".m")
249  t = load_path::M_FILE;
250  else if (ext == ".oct")
252  else if (ext == ".mex")
254 
255  retval[base] |= t;
256  }
257  }
258  }
259  }
260  else
261  {
262  std::string msg = dir.error ();
263  warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
264  }
265 
266  return retval;
267 }
268 
269 void
271 {
272  private_file_map = get_fcn_files (d);
273 }
274 
275 void
277  const std::string& class_name)
278 {
279  method_file_map[class_name].method_file_map = get_fcn_files (d);
280 
281  std::string pd = file_ops::concat (d, "private");
282 
283  file_stat fs (pd);
284 
285  if (fs && fs.is_dir ())
286  method_file_map[class_name].private_file_map = get_fcn_files (pd);
287 }
288 
289 bool
291 {
292  bool retval = true;
293 
294  if (! instance)
295  {
296  instance = new load_path ();
297 
298  if (instance)
300  }
301 
302  if (! instance)
303  {
304  ::error ("unable to create load path object!");
305 
306  retval = false;
307  }
308 
309  return retval;
310 }
311 
312 // FIXME: maybe we should also maintain a map to speed up this method of access.
313 
315 load_path::find_dir_info (const std::string& dir_arg) const
316 {
317  std::string dir = file_ops::tilde_expand (dir_arg);
318 
320 
321  while (retval != dir_info_list.end ())
322  {
323  if (retval->dir_name == dir)
324  break;
325 
326  retval++;
327  }
328 
329  return retval;
330 }
331 
333 load_path::find_dir_info (const std::string& dir_arg)
334 {
335  std::string dir = file_ops::tilde_expand (dir_arg);
336 
337  dir_info_list_iterator retval = dir_info_list.begin ();
338 
339  while (retval != dir_info_list.end ())
340  {
341  if (retval->dir_name == dir)
342  break;
343 
344  retval++;
345  }
346 
347  return retval;
348 }
349 
350 bool
351 load_path::contains (const std::string& dir) const
352 {
353  return find_dir_info (dir) != dir_info_list.end ();
354 }
355 
356 bool
357 load_path::do_contains_canonical (const std::string& dir) const
358 {
359  bool retval = false;
360 
362  i != dir_info_list.end ();
363  i++)
364  {
365  if (same_file (dir, i->dir_name))
366  {
367  retval = true;
368  break;
369  }
370  }
371 
372  return retval;
373 }
374 
375 void
376 load_path::move_fcn_map (const std::string& dir_name,
377  const string_vector& fcn_files, bool at_end)
378 {
379  octave_idx_type len = fcn_files.length ();
380 
381  for (octave_idx_type k = 0; k < len; k++)
382  {
383  std::string fname = fcn_files[k];
384 
385  std::string ext;
386  std::string base = fname;
387 
388  size_t pos = fname.rfind ('.');
389 
390  if (pos != std::string::npos)
391  {
392  base = fname.substr (0, pos);
393  ext = fname.substr (pos);
394  }
395 
396  file_info_list_type& file_info_list = fcn_map[base];
397 
398  if (file_info_list.size () == 1)
399  continue;
400  else
401  {
402  for (file_info_list_iterator p = file_info_list.begin ();
403  p != file_info_list.end ();
404  p++)
405  {
406  if (p->dir_name == dir_name)
407  {
408  file_info fi = *p;
409 
410  file_info_list.erase (p);
411 
412  if (at_end)
413  file_info_list.push_back (fi);
414  else
415  file_info_list.push_front (fi);
416 
417  break;
418  }
419  }
420  }
421  }
422 }
423 
424 void
425 load_path::move_method_map (const std::string& dir_name, bool at_end)
426 {
427  for (method_map_iterator i = method_map.begin ();
428  i != method_map.end ();
429  i++)
430  {
431  std::string class_name = i->first;
432 
433  fcn_map_type& fm = i->second;
434 
435  std::string full_dir_name
436  = file_ops::concat (dir_name, "@" + class_name);
437 
438  for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
439  {
440  file_info_list_type& file_info_list = q->second;
441 
442  if (file_info_list.size () == 1)
443  continue;
444  else
445  {
446  for (file_info_list_iterator p = file_info_list.begin ();
447  p != file_info_list.end (); p++)
448  {
449  if (p->dir_name == full_dir_name)
450  {
451  file_info fi = *p;
452 
453  file_info_list.erase (p);
454 
455  if (at_end)
456  file_info_list.push_back (fi);
457  else
458  file_info_list.push_front (fi);
459 
460  break;
461  }
462  }
463  }
464  }
465  }
466 }
467 
468 void
470 {
471  if (dir_info_list.size () > 1)
472  {
473  dir_info di = *i;
474 
475  dir_info_list.erase (i);
476 
477  if (at_end)
478  dir_info_list.push_back (di);
479  else
480  dir_info_list.push_front (di);
481 
482  std::string dir_name = di.dir_name;
483 
484  move_fcn_map (dir_name, di.fcn_files, at_end);
485 
486  // No need to move elements of private function map.
487 
488  move_method_map (dir_name, at_end);
489  }
490 }
491 
492 static void
493 maybe_add_path_elts (std::string& path, const std::string& dir)
494 {
495  std::string tpath = genpath (dir);
496 
497  if (! tpath.empty ())
498  {
499  if (path.empty ())
500  path = tpath;
501  else
502  path += dir_path::path_sep_str () + tpath;
503  }
504 }
505 
506 void
508 {
509  sys_path = "";
510 
511  if (set_initial_path)
512  {
521  }
522 
523  std::string tpath = load_path::command_line_path;
524 
525  if (tpath.empty ())
526  tpath = octave_env::getenv ("OCTAVE_PATH");
527 
528  std::string xpath;
529 
530  if (! tpath.empty ())
531  {
532  xpath = tpath;
533 
534  if (! sys_path.empty ())
535  xpath += dir_path::path_sep_str () + sys_path;
536  }
537  else
538  xpath = sys_path;
539 
540  do_set (xpath, false, true);
541 }
542 
543 void
545 {
546  dir_info_list.clear ();
547  fcn_map.clear ();
548  private_fcn_map.clear ();
549  method_map.clear ();
550 }
551 
552 static std::list<std::string>
553 split_path (const std::string& p)
554 {
555  std::list<std::string> retval;
556 
557  size_t beg = 0;
558  size_t end = p.find (dir_path::path_sep_char ());
559 
560  size_t len = p.length ();
561 
562  while (end != std::string::npos)
563  {
564  std::string elt = p.substr (beg, end-beg);
565 
566  if (! elt.empty ())
567  retval.push_back (elt);
568 
569  beg = end + 1;
570 
571  if (beg == len)
572  break;
573 
574  end = p.find (dir_path::path_sep_char (), beg);
575  }
576 
577  std::string elt = p.substr (beg);
578 
579  if (! elt.empty ())
580  retval.push_back (elt);
581 
582  return retval;
583 }
584 
585 void
586 load_path::do_set (const std::string& p, bool warn, bool is_init)
587 {
588  // Use a list when we need to preserve order.
589  std::list<std::string> elts = split_path (p);
590 
591  // Use a set when we need to search and order is not important.
592  std::set<std::string> elts_set (elts.begin (), elts.end ());
593 
594  if (is_init)
595  init_dirs = elts_set;
596  else
597  {
598  for (std::set<std::string>::const_iterator it = init_dirs.begin ();
599  it != init_dirs.end (); it++)
600  {
601  if (elts_set.find (*it) == elts_set.end ())
602  {
603  warning_with_id ("Octave:remove-init-dir",
604  "default load path altered. Some built-in functions may not be found. Try restoredefaultpath() to recover it.");
605  break;
606  }
607  }
608  }
609 
610  // Temporarily disable add hook.
611 
612  unwind_protect frame;
613  frame.protect_var (add_hook);
614 
615  add_hook = 0;
616 
617  do_clear ();
618 
619  for (std::list<std::string>::const_iterator i = elts.begin ();
620  i != elts.end (); i++)
621  do_append (*i, warn);
622 
623  // Restore add hook and execute for all newly added directories.
624  frame.run_first ();
625 
626  for (dir_info_list_iterator i = dir_info_list.begin ();
627  i != dir_info_list.end ();
628  i++)
629  {
630  if (add_hook)
631  add_hook (i->dir_name);
632  }
633 
634  // Always prepend current directory.
635  do_prepend (".", warn);
636 }
637 
638 void
639 load_path::do_append (const std::string& dir, bool warn)
640 {
641  if (! dir.empty ())
642  do_add (dir, true, warn);
643 }
644 
645 void
646 load_path::do_prepend (const std::string& dir, bool warn)
647 {
648  if (! dir.empty ())
649  do_add (dir, false, warn);
650 }
651 
652 // Strip trailing directory separators.
653 
654 static std::string
655 strip_trailing_separators (const std::string& dir_arg)
656 {
657  std::string dir = dir_arg;
658 
659  size_t k = dir.length ();
660 
661  while (k > 1 && file_ops::is_dir_sep (dir[k-1]))
662  k--;
663 
664  if (k < dir.length ())
665  dir.resize (k);
666 
667  return dir;
668 }
669 
670 void
671 load_path::do_add (const std::string& dir_arg, bool at_end, bool warn)
672 {
673  size_t len = dir_arg.length ();
674 
675  if (len > 1 && dir_arg.substr (len-2) == "//")
676  warning_with_id ("Octave:recursive-path-search",
677  "trailing '//' is no longer special in search path elements");
678 
679  std::string dir = file_ops::tilde_expand (dir_arg);
680 
681  dir = strip_trailing_separators (dir);
682 
684 
685  if (i != dir_info_list.end ())
686  move (i, at_end);
687  else
688  {
689  file_stat fs (dir);
690 
691  if (fs)
692  {
693  if (fs.is_dir ())
694  {
695  dir_info di (dir);
696 
697  if (! error_state)
698  {
699  if (at_end)
700  dir_info_list.push_back (di);
701  else
702  dir_info_list.push_front (di);
703 
704  add_to_fcn_map (di, at_end);
705 
707 
708  add_to_method_map (di, at_end);
709 
710  if (add_hook)
711  add_hook (dir);
712  }
713  }
714  else if (warn)
715  warning ("addpath: %s: not a directory", dir_arg.c_str ());
716  }
717  else if (warn)
718  {
719  std::string msg = fs.error ();
720  warning ("addpath: %s: %s", dir_arg.c_str (), msg.c_str ());
721  }
722  }
723 
724  // FIXME: is there a better way to do this?
725 
726  i = find_dir_info (".");
727 
728  if (i != dir_info_list.end ())
729  move (i, false);
730 }
731 
732 void
733 load_path::remove_fcn_map (const std::string& dir,
734  const string_vector& fcn_files)
735 {
736  octave_idx_type len = fcn_files.length ();
737 
738  for (octave_idx_type k = 0; k < len; k++)
739  {
740  std::string fname = fcn_files[k];
741 
742  std::string ext;
743  std::string base = fname;
744 
745  size_t pos = fname.rfind ('.');
746 
747  if (pos != std::string::npos)
748  {
749  base = fname.substr (0, pos);
750  ext = fname.substr (pos);
751  }
752 
753  file_info_list_type& file_info_list = fcn_map[base];
754 
755  for (file_info_list_iterator p = file_info_list.begin ();
756  p != file_info_list.end ();
757  p++)
758  {
759  if (p->dir_name == dir)
760  {
761  file_info_list.erase (p);
762 
763  if (file_info_list.empty ())
764  fcn_map.erase (fname);
765 
766  break;
767  }
768  }
769  }
770 }
771 
772 void
773 load_path::remove_private_fcn_map (const std::string& dir)
774 {
776 
777  if (p != private_fcn_map.end ())
778  private_fcn_map.erase (p);
779 }
780 
781 void
782 load_path::remove_method_map (const std::string& dir)
783 {
784  for (method_map_iterator i = method_map.begin ();
785  i != method_map.end ();
786  i++)
787  {
788  std::string class_name = i->first;
789 
790  fcn_map_type& fm = i->second;
791 
792  std::string full_dir_name = file_ops::concat (dir, "@" + class_name);
793 
794  for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
795  {
796  file_info_list_type& file_info_list = q->second;
797 
798  if (file_info_list.size () == 1)
799  continue;
800  else
801  {
802  for (file_info_list_iterator p = file_info_list.begin ();
803  p != file_info_list.end (); p++)
804  {
805  if (p->dir_name == full_dir_name)
806  {
807  file_info_list.erase (p);
808 
809  // FIXME: if there are no other elements, we
810  // should remove this element of fm but calling
811  // erase here would invalidate the iterator q.
812 
813  break;
814  }
815  }
816  }
817  }
818  }
819 }
820 
821 bool
822 load_path::do_remove (const std::string& dir_arg)
823 {
824  bool retval = false;
825 
826  if (! dir_arg.empty ())
827  {
828  if (dir_arg == ".")
829  {
830  warning ("rmpath: can't remove \".\" from path");
831 
832  // Avoid additional warnings.
833  retval = true;
834  }
835  else
836  {
837  std::string dir = file_ops::tilde_expand (dir_arg);
838 
839  dir = strip_trailing_separators (dir);
840 
842 
843  if (i != dir_info_list.end ())
844  {
845  retval = true;
846 
847  if (remove_hook)
848  remove_hook (dir);
849 
850  string_vector fcn_files = i->fcn_files;
851 
852  dir_info_list.erase (i);
853 
854  remove_fcn_map (dir, fcn_files);
855 
857 
858  remove_method_map (dir);
859  }
860  }
861  }
862 
863  return retval;
864 }
865 
866 void
868 {
869  // I don't see a better way to do this because we need to
870  // preserve the correct directory ordering for new files that
871  // have appeared.
872 
873  fcn_map.clear ();
874 
875  private_fcn_map.clear ();
876 
877  method_map.clear ();
878 
879  for (dir_info_list_iterator p = dir_info_list.begin ();
880  p != dir_info_list.end ();
881  p++)
882  {
883  dir_info& di = *p;
884 
885  di.update ();
886 
887  add_to_fcn_map (di, true);
888 
890 
891  add_to_method_map (di, true);
892  }
893 }
894 
895 bool
896 load_path::check_file_type (std::string& fname, int type, int possible_types,
897  const std::string& fcn, const char *who)
898 {
899  bool retval = false;
900 
901  if (type == load_path::OCT_FILE)
902  {
903  if ((type & possible_types) == load_path::OCT_FILE)
904  {
905  fname += ".oct";
906  retval = true;
907  }
908  }
909  else if (type == load_path::M_FILE)
910  {
911  if ((type & possible_types) == load_path::M_FILE)
912  {
913  fname += ".m";
914  retval = true;
915  }
916  }
917  else if (type == load_path::MEX_FILE)
918  {
919  if ((type & possible_types) == load_path::MEX_FILE)
920  {
921  fname += ".mex";
922  retval = true;
923  }
924  }
925  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
926  {
927  if (possible_types & load_path::OCT_FILE)
928  {
929  fname += ".oct";
930  retval = true;
931  }
932  else if (possible_types & load_path::M_FILE)
933  {
934  fname += ".m";
935  retval = true;
936  }
937  }
938  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
939  {
940  if (possible_types & load_path::MEX_FILE)
941  {
942  fname += ".mex";
943  retval = true;
944  }
945  else if (possible_types & load_path::M_FILE)
946  {
947  fname += ".m";
948  retval = true;
949  }
950  }
951  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
952  {
953  if (possible_types & load_path::OCT_FILE)
954  {
955  fname += ".oct";
956  retval = true;
957  }
958  else if (possible_types & load_path::MEX_FILE)
959  {
960  fname += ".mex";
961  retval = true;
962  }
963  }
964  else if (type == (load_path::M_FILE | load_path::OCT_FILE
966  {
967  if (possible_types & load_path::OCT_FILE)
968  {
969  fname += ".oct";
970  retval = true;
971  }
972  else if (possible_types & load_path::MEX_FILE)
973  {
974  fname += ".mex";
975  retval = true;
976  }
977  else if (possible_types & load_path::M_FILE)
978  {
979  fname += ".m";
980  retval = true;
981  }
982  }
983  else
984  error ("%s: %s: invalid type code = %d", who, fcn.c_str (), type);
985 
986  return retval;
987 }
988 
989 std::string
990 load_path::do_find_fcn (const std::string& fcn, std::string& dir_name,
991  int type) const
992 {
993  std::string retval;
994 
995  // update ();
996 
997  if (fcn.length () > 0 && fcn[0] == '@')
998  {
999  size_t pos = fcn.find ('/');
1000 
1001  if (pos != std::string::npos)
1002  {
1003  std::string class_name = fcn.substr (1, pos-1);
1004  std::string meth = fcn.substr (pos+1);
1005 
1006  retval = do_find_method (class_name, meth, dir_name);
1007  }
1008  else
1009  retval = std::string ();
1010  }
1011  else
1012  {
1013  dir_name = std::string ();
1014 
1015  const_fcn_map_iterator p = fcn_map.find (fcn);
1016 
1017  if (p != fcn_map.end ())
1018  {
1019  const file_info_list_type& file_info_list = p->second;
1020 
1021  for (const_file_info_list_iterator i = file_info_list.begin ();
1022  i != file_info_list.end ();
1023  i++)
1024  {
1025  const file_info& fi = *i;
1026 
1027  retval = file_ops::concat (fi.dir_name, fcn);
1028 
1029  if (check_file_type (retval, type, fi.types,
1030  fcn, "load_path::do_find_fcn"))
1031  {
1032  dir_name = fi.dir_name;
1033  break;
1034  }
1035  else
1036  retval = std::string ();
1037  }
1038  }
1039  }
1040 
1041  return retval;
1042 }
1043 
1044 std::string
1045 load_path::do_find_private_fcn (const std::string& dir,
1046  const std::string& fcn, int type) const
1047 {
1048  std::string retval;
1049 
1050  // update ();
1051 
1053 
1054  if (q != private_fcn_map.end ())
1055  {
1056  const dir_info::fcn_file_map_type& m = q->second;
1057 
1058  dir_info::const_fcn_file_map_iterator p = m.find (fcn);
1059 
1060  if (p != m.end ())
1061  {
1062  std::string fname
1063  = file_ops::concat (file_ops::concat (dir, "private"), fcn);
1064 
1065  if (check_file_type (fname, type, p->second, fcn,
1066  "load_path::find_private_fcn"))
1067  retval = fname;
1068  }
1069  }
1070 
1071  return retval;
1072 }
1073 
1074 std::string
1075 load_path::do_find_method (const std::string& class_name,
1076  const std::string& meth,
1077  std::string& dir_name, int type) const
1078 {
1079  std::string retval;
1080 
1081  // update ();
1082 
1083  dir_name = std::string ();
1084 
1085  const_method_map_iterator q = method_map.find (class_name);
1086 
1087  if (q != method_map.end ())
1088  {
1089  const fcn_map_type& m = q->second;
1090 
1091  const_fcn_map_iterator p = m.find (meth);
1092 
1093  if (p != m.end ())
1094  {
1095  const file_info_list_type& file_info_list = p->second;
1096 
1097  for (const_file_info_list_iterator i = file_info_list.begin ();
1098  i != file_info_list.end ();
1099  i++)
1100  {
1101  const file_info& fi = *i;
1102 
1103  retval = file_ops::concat (fi.dir_name, meth);
1104 
1105  bool found = check_file_type (retval, type, fi.types,
1106  meth, "load_path::do_find_method");
1107 
1108  if (found)
1109  {
1110  dir_name = fi.dir_name;
1111  break;
1112  }
1113  else
1114  retval = std::string ();
1115  }
1116  }
1117  }
1118 
1119  return retval;
1120 }
1121 
1122 std::list<std::string>
1123 load_path::do_methods (const std::string& class_name) const
1124 {
1125  std::list<std::string> retval;
1126 
1127  // update ();
1128 
1129  const_method_map_iterator q = method_map.find (class_name);
1130 
1131  if (q != method_map.end ())
1132  {
1133  const fcn_map_type& m = q->second;
1134 
1135  for (const_fcn_map_iterator p = m.begin (); p != m.end (); p++)
1136  retval.push_back (p->first);
1137  }
1138 
1139  if (! retval.empty ())
1140  retval.sort ();
1141 
1142  return retval;
1143 }
1144 
1145 std::list<std::string>
1146 load_path::do_overloads (const std::string& meth) const
1147 {
1148  std::list<std::string> retval;
1149 
1150  // update ();
1151 
1152  for (const_method_map_iterator q = method_map.begin ();
1153  q != method_map.end (); q++)
1154  {
1155  const fcn_map_type& m = q->second;
1156 
1157  if (m.find (meth) != m.end ())
1158  retval.push_back (q->first);
1159  }
1160 
1161  return retval;
1162 }
1163 
1164 std::string
1165 load_path::do_find_file (const std::string& file) const
1166 {
1167  std::string retval;
1168 
1169  if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
1170  {
1173  {
1174  file_stat fs (file);
1175 
1176  if (fs.exists ())
1177  return file;
1178  }
1179  else
1180  {
1181  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1182  p != dir_info_list.end ();
1183  p++)
1184  {
1185  std::string tfile = file_ops::concat (p->dir_name, file);
1186 
1187  file_stat fs (tfile);
1188 
1189  if (fs.exists ())
1190  return tfile;
1191  }
1192  }
1193  }
1194  else
1195  {
1196  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1197  p != dir_info_list.end ();
1198  p++)
1199  {
1200  string_vector all_files = p->all_files;
1201 
1202  octave_idx_type len = all_files.length ();
1203 
1204  for (octave_idx_type i = 0; i < len; i++)
1205  {
1206  if (all_files[i] == file)
1207  return file_ops::concat (p->dir_name, file);
1208  }
1209  }
1210  }
1211 
1212  return retval;
1213 }
1214 
1215 std::string
1216 load_path::do_find_dir (const std::string& dir) const
1217 {
1218  std::string retval;
1219 
1220  if (dir.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos
1223  {
1224  file_stat fs (dir);
1225 
1226  if (fs.exists () && fs.is_dir ())
1227  return dir;
1228  }
1229  else
1230  {
1231  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1232  p != dir_info_list.end ();
1233  p++)
1234  {
1235  std::string dname = octave_env::make_absolute (p->dir_name);
1236 
1237  size_t dname_len = dname.length ();
1238 
1239  if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ())
1240  {
1241  dname = dname.substr (0, dname_len - 1);
1242  dname_len--;
1243  }
1244 
1245  size_t dir_len = dir.length ();
1246 
1247  if (dname_len >= dir_len
1248  && file_ops::is_dir_sep (dname[dname_len - dir_len - 1])
1249  && dir.compare (dname.substr (dname_len - dir_len)) == 0)
1250  {
1251  file_stat fs (p->dir_name);
1252 
1253  if (fs.exists () && fs.is_dir ())
1254  return p->dir_name;
1255  }
1256  }
1257  }
1258 
1259  return retval;
1260 }
1261 
1263 load_path::do_find_matching_dirs (const std::string& dir) const
1264 {
1265  std::list<std::string> retlist;
1266 
1267  if (dir.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos
1270  {
1271  file_stat fs (dir);
1272 
1273  if (fs.exists () && fs.is_dir ())
1274  retlist.push_back (dir);
1275  }
1276  else
1277  {
1278  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1279  p != dir_info_list.end ();
1280  p++)
1281  {
1282  std::string dname = octave_env::make_absolute (p->dir_name);
1283 
1284  size_t dname_len = dname.length ();
1285 
1286  if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ())
1287  {
1288  dname = dname.substr (0, dname_len - 1);
1289  dname_len--;
1290  }
1291 
1292  size_t dir_len = dir.length ();
1293 
1294  if (dname_len >= dir_len
1295  && file_ops::is_dir_sep (dname[dname_len - dir_len - 1])
1296  && dir.compare (dname.substr (dname_len - dir_len)) == 0)
1297  {
1298  file_stat fs (p->dir_name);
1299 
1300  if (fs.exists () && fs.is_dir ())
1301  retlist.push_back (p->dir_name);
1302  }
1303  }
1304  }
1305 
1306  return retlist;
1307 }
1308 
1309 std::string
1311 {
1312  std::string retval;
1313 
1314  std::string dir_name;
1315  std::string file_name;
1316 
1317  octave_idx_type flen = flist.length ();
1318  octave_idx_type rel_flen = 0;
1319 
1320  string_vector rel_flist (flen);
1321 
1322  for (octave_idx_type i = 0; i < flen; i++)
1323  {
1324  std::string file = flist[i];
1325 
1326  if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
1327  {
1330  {
1331  file_stat fs (file);
1332 
1333  if (fs.exists ())
1334  return file;
1335  }
1336  else
1337  {
1338  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1339  p != dir_info_list.end ();
1340  p++)
1341  {
1342  std::string tfile = file_ops::concat (p->dir_name, file);
1343 
1344  file_stat fs (tfile);
1345 
1346  if (fs.exists ())
1347  return tfile;
1348  }
1349  }
1350  }
1351  else
1352  rel_flist[rel_flen++] = file;
1353  }
1354 
1355  rel_flist.resize (rel_flen);
1356 
1357  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1358  p != dir_info_list.end ();
1359  p++)
1360  {
1361  string_vector all_files = p->all_files;
1362 
1363  octave_idx_type len = all_files.length ();
1364 
1365  for (octave_idx_type i = 0; i < len; i++)
1366  {
1367  for (octave_idx_type j = 0; j < rel_flen; j++)
1368  {
1369  if (all_files[i] == rel_flist[j])
1370  {
1371  dir_name = p->dir_name;
1372  file_name = rel_flist[j];
1373 
1374  goto done;
1375  }
1376  }
1377  }
1378  }
1379 
1380 done:
1381 
1382  if (! dir_name.empty ())
1383  retval = file_ops::concat (dir_name, file_name);
1384 
1385  return retval;
1386 }
1387 
1390 {
1391  std::list<std::string> retlist;
1392 
1393  std::string dir_name;
1394  std::string file_name;
1395 
1396  octave_idx_type flen = flist.length ();
1397  octave_idx_type rel_flen = 0;
1398 
1399  string_vector rel_flist (flen);
1400 
1401  for (octave_idx_type i = 0; i < flen; i++)
1402  {
1403  std::string file = flist[i];
1404 
1405  if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
1406  {
1409  {
1410  file_stat fs (file);
1411 
1412  if (fs.exists ())
1413  retlist.push_back (file);
1414  }
1415  else
1416  {
1417  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1418  p != dir_info_list.end ();
1419  p++)
1420  {
1421  std::string tfile = file_ops::concat (p->dir_name, file);
1422 
1423  file_stat fs (tfile);
1424 
1425  if (fs.exists ())
1426  retlist.push_back (tfile);
1427  }
1428  }
1429  }
1430  else
1431  rel_flist[rel_flen++] = file;
1432  }
1433 
1434  rel_flist.resize (rel_flen);
1435 
1436  for (const_dir_info_list_iterator p = dir_info_list.begin ();
1437  p != dir_info_list.end (); p++)
1438  {
1439  string_vector all_files = p->all_files;
1440 
1441  octave_idx_type len = all_files.length ();
1442 
1443  for (octave_idx_type i = 0; i < len; i++)
1444  {
1445  for (octave_idx_type j = 0; j < rel_flen; j++)
1446  {
1447  if (all_files[i] == rel_flist[j])
1448  retlist.push_back (file_ops::concat (p->dir_name,
1449  rel_flist[j]));
1450  }
1451  }
1452  }
1453 
1454  return retlist;
1455 }
1456 
1459 {
1460  size_t len = dir_info_list.size ();
1461 
1462  string_vector retval (len);
1463 
1464  octave_idx_type k = 0;
1465 
1466  for (const_dir_info_list_iterator i = dir_info_list.begin ();
1467  i != dir_info_list.end ();
1468  i++)
1469  retval[k++] = i->dir_name;
1470 
1471  return retval;
1472 }
1473 
1474 std::list<std::string>
1476 {
1477  std::list<std::string> retval;
1478 
1479  for (const_dir_info_list_iterator i = dir_info_list.begin ();
1480  i != dir_info_list.end ();
1481  i++)
1482  retval.push_back (i->dir_name);
1483 
1484  return retval;
1485 }
1486 
1488 load_path::do_files (const std::string& dir, bool omit_exts) const
1489 {
1490  string_vector retval;
1491 
1493 
1494  if (p != dir_info_list.end ())
1495  retval = p->fcn_files;
1496 
1497  if (omit_exts)
1498  {
1499  octave_idx_type len = retval.length ();
1500 
1501  for (octave_idx_type i = 0; i < len; i++)
1502  {
1503  std::string fname = retval[i];
1504 
1505  size_t pos = fname.rfind ('.');
1506 
1507  if (pos != std::string::npos)
1508  retval[i] = fname.substr (0, pos);
1509  }
1510  }
1511 
1512  return retval;
1513 }
1514 
1517 {
1518  size_t len = fcn_map.size ();
1519 
1520  string_vector retval (len);
1521 
1522  octave_idx_type count = 0;
1523 
1524  for (const_fcn_map_iterator p = fcn_map.begin ();
1525  p != fcn_map.end ();
1526  p++)
1527  retval[count++] = p->first;
1528 
1529  return retval;
1530 }
1531 
1532 std::string
1534 {
1535  std::string xpath;
1536 
1537  string_vector xdirs = load_path::dirs ();
1538 
1539  octave_idx_type len = xdirs.length ();
1540 
1541  if (len > 0)
1542  xpath = xdirs[0];
1543 
1544  for (octave_idx_type i = 1; i < len; i++)
1545  xpath += dir_path::path_sep_str () + xdirs[i];
1546 
1547  return xpath;
1548 }
1549 
1550 void
1551 print_types (std::ostream& os, int types)
1552 {
1553  bool printed_type = false;
1554 
1555  if (types & load_path::OCT_FILE)
1556  {
1557  os << "oct";
1558  printed_type = true;
1559  }
1560 
1561  if (types & load_path::MEX_FILE)
1562  {
1563  if (printed_type)
1564  os << "|";
1565  os << "mex";
1566  printed_type = true;
1567  }
1568 
1569  if (types & load_path::M_FILE)
1570  {
1571  if (printed_type)
1572  os << "|";
1573  os << "m";
1574  printed_type = true;
1575  }
1576 }
1577 
1578 void
1579 print_fcn_list (std::ostream& os,
1581 {
1583  p != lst.end ();
1584  p++)
1585  {
1586  os << " " << p->first << " (";
1587 
1588  print_types (os, p->second);
1589 
1590  os << ")\n";
1591  }
1592 }
1593 
1596 {
1597  octave_idx_type n = lst.size ();
1598 
1599  string_vector retval (n);
1600 
1601  octave_idx_type count = 0;
1602 
1604  p != lst.end ();
1605  p++)
1606  {
1607  std::string nm = p->first;
1608 
1609  int types = p->second;
1610 
1611  if (types & load_path::OCT_FILE)
1612  nm += ".oct";
1613  else if (types & load_path::MEX_FILE)
1614  nm += ".mex";
1615  else
1616  nm += ".m";
1617 
1618  retval[count++] = nm;
1619  }
1620 
1621  return retval;
1622 }
1623 
1624 void
1625 load_path::do_display (std::ostream& os) const
1626 {
1627  for (const_dir_info_list_iterator i = dir_info_list.begin ();
1628  i != dir_info_list.end ();
1629  i++)
1630  {
1631  string_vector fcn_files = i->fcn_files;
1632 
1633  if (! fcn_files.empty ())
1634  {
1635  os << "\n*** function files in " << i->dir_name << ":\n\n";
1636 
1637  fcn_files.list_in_columns (os);
1638  }
1639 
1640  const dir_info::method_file_map_type& method_file_map
1641  = i->method_file_map;
1642 
1643  if (! method_file_map.empty ())
1644  {
1646  p = method_file_map.begin (); p != method_file_map.end (); p++)
1647  {
1648  os << "\n*** methods in " << i->dir_name
1649  << "/@" << p->first << ":\n\n";
1650 
1651  const dir_info::class_info& ci = p->second;
1652 
1653  string_vector method_files = get_file_list (ci.method_file_map);
1654 
1655  method_files.list_in_columns (os);
1656  }
1657  }
1658  }
1659 
1661  i != private_fcn_map.end (); i++)
1662  {
1663  os << "\n*** private functions in "
1664  << file_ops::concat (i->first, "private") << ":\n\n";
1665 
1666  print_fcn_list (os, i->second);
1667  }
1668 
1669 #if defined (DEBUG_LOAD_PATH)
1670 
1671  for (const_fcn_map_iterator i = fcn_map.begin ();
1672  i != fcn_map.end ();
1673  i++)
1674  {
1675  os << i->first << ":\n";
1676 
1677  const file_info_list_type& file_info_list = i->second;
1678 
1679  for (const_file_info_list_iterator p = file_info_list.begin ();
1680  p != file_info_list.end ();
1681  p++)
1682  {
1683  os << " " << p->dir_name << " (";
1684 
1685  print_types (os, p->types);
1686 
1687  os << ")\n";
1688  }
1689  }
1690 
1691  for (const_method_map_iterator i = method_map.begin ();
1692  i != method_map.end ();
1693  i++)
1694  {
1695  os << "CLASS " << i->first << ":\n";
1696 
1697  const fcn_map_type& fm = i->second;
1698 
1699  for (const_fcn_map_iterator q = fm.begin ();
1700  q != fm.end ();
1701  q++)
1702  {
1703  os << " " << q->first << ":\n";
1704 
1705  const file_info_list_type& file_info_list = q->second;
1706 
1707  for (const_file_info_list_iterator p = file_info_list.begin ();
1708  p != file_info_list.end ();
1709  p++)
1710  {
1711  os << " " << p->dir_name << " (";
1712 
1713  print_types (os, p->types);
1714 
1715  os << ")\n";
1716  }
1717  }
1718  }
1719 
1720  os << "\n";
1721 
1722 #endif
1723 }
1724 
1725 // True if a path is contained in a path list separated by path_sep_char
1726 static bool
1727 in_path_list (const std::string& path_list, const std::string& path)
1728 {
1729  size_t ps = path.size ();
1730  size_t pls = path_list.size ();
1731  size_t pos = path_list.find (path);
1732  char psc = dir_path::path_sep_char ();
1733  while (pos != std::string::npos)
1734  {
1735  if ((pos == 0 || path_list[pos-1] == psc)
1736  && (pos + ps == pls || path_list[pos + ps] == psc))
1737  return true;
1738  else
1739  pos = path_list.find (path, pos + 1);
1740  }
1741 
1742  return false;
1743 }
1744 
1745 void
1746 load_path::add_to_fcn_map (const dir_info& di, bool at_end) const
1747 {
1748  std::string dir_name = di.dir_name;
1749 
1750  string_vector fcn_files = di.fcn_files;
1751 
1752  octave_idx_type len = fcn_files.length ();
1753 
1754  for (octave_idx_type i = 0; i < len; i++)
1755  {
1756  std::string fname = fcn_files[i];
1757 
1758  std::string ext;
1759  std::string base = fname;
1760 
1761  size_t pos = fname.rfind ('.');
1762 
1763  if (pos != std::string::npos)
1764  {
1765  base = fname.substr (0, pos);
1766  ext = fname.substr (pos);
1767  }
1768 
1769  file_info_list_type& file_info_list = fcn_map[base];
1770 
1771  file_info_list_iterator p = file_info_list.begin ();
1772 
1773  while (p != file_info_list.end ())
1774  {
1775  if (p->dir_name == dir_name)
1776  break;
1777 
1778  p++;
1779  }
1780 
1781  int t = 0;
1782  if (ext == ".m")
1783  t = load_path::M_FILE;
1784  else if (ext == ".oct")
1785  t = load_path::OCT_FILE;
1786  else if (ext == ".mex")
1787  t = load_path::MEX_FILE;
1788 
1789  if (p == file_info_list.end ())
1790  {
1791  file_info fi (dir_name, t);
1792 
1793  if (at_end)
1794  file_info_list.push_back (fi);
1795  else
1796  {
1797  // Warn if a built-in or library function is being shadowed.
1798 
1799  if (! file_info_list.empty ())
1800  {
1801  file_info& old = file_info_list.front ();
1802 
1803  // FIXME: do we need to be more careful about the
1804  // way we look for old.dir_name in sys_path to avoid
1805  // partial matches?
1806 
1807  // Don't warn about Contents.m files since we expect
1808  // more than one to exist in the load path.
1809 
1810  if (fname != "Contents.m"
1811  && sys_path.find (old.dir_name) != std::string::npos
1812  && in_path_list (sys_path, old.dir_name))
1813  {
1814  std::string fcn_path = file_ops::concat (dir_name, fname);
1815 
1816  warning_with_id ("Octave:shadowed-function",
1817  "function %s shadows a core library function",
1818  fcn_path.c_str ());
1819  }
1820  }
1822  {
1823  std::string fcn_path = file_ops::concat (dir_name, fname);
1824  warning_with_id ("Octave:shadowed-function",
1825  "function %s shadows a built-in function",
1826  fcn_path.c_str ());
1827  }
1828 
1829  file_info_list.push_front (fi);
1830  }
1831  }
1832  else
1833  {
1834  file_info& fi = *p;
1835 
1836  fi.types |= t;
1837  }
1838  }
1839 }
1840 
1841 void
1843 {
1844  dir_info::fcn_file_map_type private_file_map = di.private_file_map;
1845 
1846  if (! private_file_map.empty ())
1847  private_fcn_map[di.dir_name] = private_file_map;
1848 }
1849 
1850 void
1851 load_path::add_to_method_map (const dir_info& di, bool at_end) const
1852 {
1853  std::string dir_name = di.dir_name;
1854 
1855  // <CLASS_NAME, CLASS_INFO>
1856  dir_info::method_file_map_type method_file_map = di.method_file_map;
1857 
1858  for (dir_info::const_method_file_map_iterator q = method_file_map.begin ();
1859  q != method_file_map.end ();
1860  q++)
1861  {
1862  std::string class_name = q->first;
1863 
1864  fcn_map_type& fm = method_map[class_name];
1865 
1866  std::string full_dir_name
1867  = file_ops::concat (dir_name, "@" + class_name);
1868 
1869  const dir_info::class_info& ci = q->second;
1870 
1871  // <FCN_NAME, TYPES>
1873 
1874  for (dir_info::const_fcn_file_map_iterator p = m.begin ();
1875  p != m.end ();
1876  p++)
1877  {
1878  std::string base = p->first;
1879 
1880  int types = p->second;
1881 
1882  file_info_list_type& file_info_list = fm[base];
1883 
1884  file_info_list_iterator p2 = file_info_list.begin ();
1885 
1886  while (p2 != file_info_list.end ())
1887  {
1888  if (p2->dir_name == full_dir_name)
1889  break;
1890 
1891  p2++;
1892  }
1893 
1894  if (p2 == file_info_list.end ())
1895  {
1896  file_info fi (full_dir_name, types);
1897 
1898  if (at_end)
1899  file_info_list.push_back (fi);
1900  else
1901  file_info_list.push_front (fi);
1902  }
1903  else
1904  {
1905  // FIXME: is this possible?
1906 
1907  file_info& fi = *p2;
1908 
1909  fi.types = types;
1910  }
1911  }
1912 
1913  // <FCN_NAME, TYPES>
1914  dir_info::fcn_file_map_type private_file_map = ci.private_file_map;
1915 
1916  if (! private_file_map.empty ())
1917  private_fcn_map[full_dir_name] = private_file_map;
1918  }
1919 }
1920 
1921 std::string
1922 genpath (const std::string& dirname, const string_vector& skip)
1923 {
1924  std::string retval;
1925 
1926  dir_entry dir (dirname);
1927 
1928  if (dir)
1929  {
1930  retval = dirname;
1931 
1932  string_vector dirlist = dir.read ();
1933 
1934  octave_idx_type len = dirlist.length ();
1935 
1936  for (octave_idx_type i = 0; i < len; i++)
1937  {
1938  std::string elt = dirlist[i];
1939 
1940  bool skip_p = (elt == "." || elt == ".." || elt[0] == '@');
1941 
1942  if (! skip_p)
1943  {
1944  for (octave_idx_type j = 0; j < skip.length (); j++)
1945  {
1946  skip_p = (elt == skip[j]);
1947  if (skip_p)
1948  break;
1949  }
1950 
1951  if (! skip_p)
1952  {
1953  std::string nm = file_ops::concat (dirname, elt);
1954 
1955  file_stat fs (nm);
1956 
1957  if (fs && fs.is_dir ())
1958  retval += dir_path::path_sep_str () + genpath (nm, skip);
1959  }
1960  }
1961  }
1962  }
1963 
1964  return retval;
1965 }
1966 
1967 static void
1968 execute_pkg_add_or_del (const std::string& dir,
1969  const std::string& script_file)
1970 {
1972  return;
1973 
1974  unwind_protect frame;
1975 
1976  std::string file = file_ops::concat (dir, script_file);
1977 
1978  file_stat fs (file);
1979 
1980  if (fs.exists ())
1981  source_file (file, "base");
1982 }
1983 
1984 void
1985 execute_pkg_add (const std::string& dir)
1986 {
1987  execute_pkg_add_or_del (dir, "PKG_ADD");
1988 }
1989 
1990 void
1991 execute_pkg_del (const std::string& dir)
1992 {
1993  execute_pkg_add_or_del (dir, "PKG_DEL");
1994 }
1995 
1996 DEFUN (genpath, args, ,
1997  "-*- texinfo -*-\n\
1998 @deftypefn {Built-in Function} {} genpath (@var{dir})\n\
1999 @deftypefnx {Built-in Function} {} genpath (@var{dir}, @var{skip}, @dots{})\n\
2000 Return a path constructed from @var{dir} and all its subdirectories.\n\
2001 If additional string parameters are given, the resulting path will\n\
2002 exclude directories with those names.\n\
2003 @end deftypefn")
2004 {
2005  octave_value retval;
2006 
2007  octave_idx_type nargin = args.length ();
2008 
2009  if (nargin == 1)
2010  {
2011  std::string dirname = args(0).string_value ();
2012 
2013  if (! error_state)
2014  retval = genpath (dirname);
2015  else
2016  error ("genpath: DIR must be a character string");
2017  }
2018  else if (nargin > 1)
2019  {
2020  std::string dirname = args(0).string_value ();
2021 
2022  string_vector skip (nargin - 1);
2023 
2024  for (octave_idx_type i = 1; i < nargin; i++)
2025  {
2026  skip[i-1] = args(i).string_value ();
2027 
2028  if (error_state)
2029  break;
2030  }
2031 
2032  if (! error_state)
2033  retval = genpath (dirname, skip);
2034  else
2035  error ("genpath: all arguments must be character strings");
2036  }
2037  else
2038  print_usage ();
2039 
2040  return retval;
2041 }
2042 
2043 static void
2045 {
2046  load_path::update ();
2047 
2048  // FIXME: maybe we should rename this variable since it is being
2049  // used for more than keeping track of the prompt time.
2050 
2051  // This will force updated functions to be found.
2053 }
2054 
2055 DEFUN (rehash, , ,
2056  "-*- texinfo -*-\n\
2057 @deftypefn {Built-in Function} {} rehash ()\n\
2058 Reinitialize Octave's load path directory cache.\n\
2059 @end deftypefn")
2060 {
2061  octave_value_list retval;
2062 
2063  rehash_internal ();
2064 
2065  return retval;
2066 }
2067 
2069  "-*- texinfo -*-\n\
2070 @deftypefn {Built-in Function} {} command_line_path (@dots{})\n\
2071 Return the command line path variable.\n\
2072 \n\
2073 @seealso{path, addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
2074 @end deftypefn")
2075 {
2077 }
2078 
2079 DEFUN (restoredefaultpath, , ,
2080  "-*- texinfo -*-\n\
2081 @deftypefn {Built-in Function} {} restoredefaultpath (@dots{})\n\
2082 Restore Octave's path to its initial state at startup.\n\
2083 \n\
2084 @seealso{path, addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
2085 @end deftypefn")
2086 {
2087  load_path::initialize (true);
2088 
2090 }
2091 
2092 // Return Octave's original default list of directories in which to
2093 // search for function files. This corresponds to the path that
2094 // exists prior to running the system's octaverc file or the user's
2095 // ~/.octaverc file
2096 
2097 DEFUN (__pathorig__, , ,
2098  "-*- texinfo -*-\n\
2099 @deftypefn {Built-in Function} {@var{val} =} __pathorig__ ()\n\
2100 Undocumented internal function.\n\
2101 @end deftypefn")
2102 {
2104 }
2105 
2106 DEFUN (path, args, nargout,
2107  "-*- texinfo -*-\n\
2108 @deftypefn {Built-in Function} {} path (@dots{})\n\
2109 Modify or display Octave's load path.\n\
2110 \n\
2111 If @var{nargin} and @var{nargout} are zero, display the elements of\n\
2112 Octave's load path in an easy to read format.\n\
2113 \n\
2114 If @var{nargin} is zero and nargout is greater than zero, return the\n\
2115 current load path.\n\
2116 \n\
2117 If @var{nargin} is greater than zero, concatenate the arguments,\n\
2118 separating them with @code{pathsep}. Set the internal search path\n\
2119 to the result and return it.\n\
2120 \n\
2121 No checks are made for duplicate elements.\n\
2122 @seealso{addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
2123 @end deftypefn")
2124 {
2125  octave_value retval;
2126 
2127  int argc = args.length () + 1;
2128 
2129  string_vector argv = args.make_argv ("path");
2130 
2131  if (! error_state)
2132  {
2133  if (argc > 1)
2134  {
2135  std::string path = argv[1];
2136 
2137  for (int i = 2; i < argc; i++)
2138  path += dir_path::path_sep_str () + argv[i];
2139 
2140  load_path::set (path, true);
2141 
2142  rehash_internal ();
2143  }
2144 
2145  if (nargout > 0)
2146  retval = load_path::path ();
2147  else if (argc == 1 && nargout == 0)
2148  {
2149  octave_stdout <<
2150  "\nOctave's search path contains the following directories:\n\n";
2151 
2153 
2155 
2156  octave_stdout << "\n";
2157  }
2158  }
2159 
2160  return retval;
2161 }
2162 
2163 DEFUN (addpath, args, nargout,
2164  "-*- texinfo -*-\n\
2165 @deftypefn {Built-in Function} {} addpath (@var{dir1}, @dots{})\n\
2166 @deftypefnx {Built-in Function} {} addpath (@var{dir1}, @dots{}, @var{option})\n\
2167 Add named directories to the function search path. If\n\
2168 @var{option} is @qcode{\"-begin\"} or 0 (the default), prepend the\n\
2169 directory name to the current path. If @var{option} is @qcode{\"-end\"}\n\
2170 or 1, append the directory name to the current path.\n\
2171 Directories added to the path must exist.\n\
2172 \n\
2173 In addition to accepting individual directory arguments, lists of\n\
2174 directory names separated by @code{pathsep} are also accepted. For example:\n\
2175 \n\
2176 @example\n\
2177 addpath (\"dir1:/dir2:~/dir3\")\n\
2178 @end example\n\
2179 @seealso{path, rmpath, genpath, pathdef, savepath, pathsep}\n\
2180 @end deftypefn")
2181 {
2182  octave_value retval;
2183 
2184  // Originally written by Bill Denney and Etienne Grossman. Heavily
2185  // modified and translated to C++ by jwe.
2186 
2187  if (nargout > 0)
2188  retval = load_path::path ();
2189 
2190  int nargin = args.length ();
2191 
2192  if (nargin > 0)
2193  {
2194  bool append = false;
2195 
2196  octave_value option_arg = args(nargin-1);
2197 
2198  if (option_arg.is_string ())
2199  {
2200  std::string option = option_arg.string_value ();
2201 
2202  if (option == "-end")
2203  {
2204  append = true;
2205  nargin--;
2206  }
2207  else if (option == "-begin")
2208  nargin--;
2209  }
2210  else if (option_arg.is_numeric_type ())
2211  {
2212  int val = option_arg.int_value ();
2213 
2214  if (! error_state)
2215  {
2216  if (val == 0)
2217  nargin--;
2218  else if (val == 1)
2219  {
2220  append = true;
2221  nargin--;
2222  }
2223  else
2224  {
2225  error ("addpath: expecting final argument to be 1 or 0");
2226  return retval;
2227  }
2228  }
2229  else
2230  {
2231  error ("addpath: expecting final argument to be 1 or 0");
2232  return retval;
2233  }
2234  }
2235 
2236  bool need_to_update = false;
2237 
2238  for (int i = 0; i < nargin; i++)
2239  {
2240  std::string arg = args(i).string_value ();
2241 
2242  if (! error_state)
2243  {
2244  std::list<std::string> dir_elts = split_path (arg);
2245 
2246  if (! append)
2247  std::reverse (dir_elts.begin (), dir_elts.end ());
2248 
2249  for (std::list<std::string>::const_iterator p = dir_elts.begin ();
2250  p != dir_elts.end ();
2251  p++)
2252  {
2253  std::string dir = *p;
2254 
2255  //dir = regexprep (dir_elts{j}, '//+', "/");
2256  //dir = regexprep (dir, '/$', "");
2257 
2258  if (append)
2259  load_path::append (dir, true);
2260  else
2261  load_path::prepend (dir, true);
2262 
2263  need_to_update = true;
2264  }
2265  }
2266  else
2267  error ("addpath: all arguments must be character strings");
2268  }
2269 
2270  if (need_to_update)
2271  rehash_internal ();
2272  }
2273  else
2274  print_usage ();
2275 
2276  return retval;
2277 }
2278 
2279 DEFUN (rmpath, args, nargout,
2280  "-*- texinfo -*-\n\
2281 @deftypefn {Built-in Function} {} rmpath (@var{dir1}, @dots{})\n\
2282 Remove @var{dir1}, @dots{} from the current function search path.\n\
2283 \n\
2284 In addition to accepting individual directory arguments, lists of\n\
2285 directory names separated by @code{pathsep} are also accepted. For example:\n\
2286 \n\
2287 @example\n\
2288 rmpath (\"dir1:/dir2:~/dir3\")\n\
2289 @end example\n\
2290 @seealso{path, addpath, genpath, pathdef, savepath, pathsep}\n\
2291 @end deftypefn")
2292 {
2293  // Originally by Etienne Grossmann. Heavily modified and translated
2294  // to C++ by jwe.
2295 
2296  octave_value retval;
2297 
2298  if (nargout > 0)
2299  retval = load_path::path ();
2300 
2301  int nargin = args.length ();
2302 
2303  if (nargin > 0)
2304  {
2305  bool need_to_update = false;
2306 
2307  for (int i = 0; i < nargin; i++)
2308  {
2309  std::string arg = args(i).string_value ();
2310 
2311  if (! error_state)
2312  {
2313  std::list<std::string> dir_elts = split_path (arg);
2314 
2315  for (std::list<std::string>::const_iterator p = dir_elts.begin ();
2316  p != dir_elts.end ();
2317  p++)
2318  {
2319  std::string dir = *p;
2320 
2321  //dir = regexprep (dir_elts{j}, '//+', "/");
2322  //dir = regexprep (dir, '/$', "");
2323 
2324  if (! load_path::remove (dir))
2325  warning ("rmpath: %s: not found", dir.c_str ());
2326  else
2327  need_to_update = true;
2328  }
2329  }
2330  else
2331  error ("addpath: all arguments must be character strings");
2332  }
2333 
2334  if (need_to_update)
2335  rehash_internal ();
2336  }
2337  else
2338  print_usage ();
2339 
2340  return retval;
2341 }