load-path.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2012 John W. Eaton
00004 Copyright (C) 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <algorithm>
00029 
00030 #include "dir-ops.h"
00031 #include "file-ops.h"
00032 #include "file-stat.h"
00033 #include "oct-env.h"
00034 #include "pathsearch.h"
00035 #include "singleton-cleanup.h"
00036 
00037 #include "defaults.h"
00038 #include "defun.h"
00039 #include "input.h"
00040 #include "load-path.h"
00041 #include "pager.h"
00042 #include "parse.h"
00043 #include "toplev.h"
00044 #include "unwind-prot.h"
00045 #include "utils.h"
00046 
00047 load_path *load_path::instance = 0;
00048 load_path::hook_fcn_ptr load_path::add_hook = execute_pkg_add;
00049 load_path::hook_fcn_ptr load_path::remove_hook = execute_pkg_del;
00050 std::string load_path::command_line_path;
00051 std::string load_path::sys_path;
00052 load_path::abs_dir_cache_type load_path::abs_dir_cache;
00053 
00054 void
00055 load_path::dir_info::update (void)
00056 {
00057   file_stat fs (dir_name);
00058 
00059   if (fs)
00060     {
00061       if (is_relative)
00062         {
00063           try
00064             {
00065               std::string abs_name = octave_env::make_absolute (dir_name);
00066 
00067               abs_dir_cache_iterator p = abs_dir_cache.find (abs_name);
00068 
00069               if (p != abs_dir_cache.end ())
00070                 {
00071                   // The directory is in the cache of all directories
00072                   // we have visited (indexed by its absolute name).
00073                   // If it is out of date, initialize it.  Otherwise,
00074                   // copy the info from the cache.  By doing that, we
00075                   // avoid unnecessary calls to stat that can slow
00076                   // things down tremendously for large directories.
00077 
00078                   const dir_info& di = p->second;
00079 
00080                   if (fs.mtime () + fs.time_resolution () > di.dir_time_last_checked)
00081                     initialize ();
00082                   else
00083                     *this = di;
00084                 }
00085               else
00086                 {
00087                   // We haven't seen this directory before.
00088 
00089                   initialize ();
00090                 }
00091             }
00092           catch (octave_execution_exception)
00093             {
00094               // Skip updating if we don't know where we are, but
00095               // don't treat it as an error.
00096 
00097               error_state = 0;
00098             }
00099         }
00100       else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked)
00101         initialize ();
00102     }
00103   else
00104     {
00105       std::string msg = fs.error ();
00106       warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
00107     }
00108 }
00109 
00110 void
00111 load_path::dir_info::initialize (void)
00112 {
00113   is_relative = ! octave_env::absolute_pathname (dir_name);
00114 
00115   dir_time_last_checked = octave_time (static_cast<time_t> (0));
00116 
00117   file_stat fs (dir_name);
00118 
00119   if (fs)
00120     {
00121       method_file_map.clear ();
00122 
00123       dir_mtime = fs.mtime ();
00124       dir_time_last_checked = octave_time ();
00125 
00126       get_file_list (dir_name);
00127 
00128       try
00129         {
00130           std::string abs_name = octave_env::make_absolute (dir_name);
00131 
00132           // FIXME -- nothing is ever removed from this cache of
00133           // directory information, so there could be some resource
00134           // problems.  Perhaps it should be pruned from time to time.
00135 
00136           abs_dir_cache[abs_name] = *this;
00137         }
00138       catch (octave_execution_exception)
00139         {
00140           // Skip updating if we don't know where we are.
00141         }
00142     }
00143   else
00144     {
00145       std::string msg = fs.error ();
00146       warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
00147     }
00148 }
00149 
00150 void
00151 load_path::dir_info::get_file_list (const std::string& d)
00152 {
00153   dir_entry dir (d);
00154 
00155   if (dir)
00156     {
00157       string_vector flist = dir.read ();
00158 
00159       octave_idx_type len = flist.length ();
00160 
00161       all_files.resize (len);
00162       fcn_files.resize (len);
00163 
00164       octave_idx_type all_files_count = 0;
00165       octave_idx_type fcn_files_count = 0;
00166 
00167       for (octave_idx_type i = 0; i < len; i++)
00168         {
00169           std::string fname = flist[i];
00170 
00171           std::string full_name = file_ops::concat (d, fname);
00172 
00173           file_stat fs (full_name);
00174 
00175           if (fs)
00176             {
00177               if (fs.is_dir ())
00178                 {
00179                   if (fname == "private")
00180                     get_private_file_map (full_name);
00181                   else if (fname[0] == '@')
00182                     get_method_file_map (full_name, fname.substr (1));
00183                 }
00184               else
00185                 {
00186                   all_files[all_files_count++] = fname;
00187 
00188                   size_t pos = fname.rfind ('.');
00189 
00190                   if (pos != std::string::npos)
00191                     {
00192                       std::string ext = fname.substr (pos);
00193 
00194                       if (ext == ".m" || ext == ".oct" || ext == ".mex")
00195                         {
00196                           std::string base = fname.substr (0, pos);
00197 
00198                           if (valid_identifier (base))
00199                             fcn_files[fcn_files_count++] = fname;
00200                         }
00201                     }
00202                 }
00203             }
00204         }
00205 
00206       all_files.resize (all_files_count);
00207       fcn_files.resize (fcn_files_count);
00208     }
00209   else
00210     {
00211       std::string msg = dir.error ();
00212       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
00213     }
00214 }
00215 
00216 load_path::dir_info::fcn_file_map_type
00217 get_fcn_files (const std::string& d)
00218 {
00219   load_path::dir_info::fcn_file_map_type retval;
00220 
00221   dir_entry dir (d);
00222 
00223   if (dir)
00224     {
00225       string_vector flist = dir.read ();
00226 
00227       octave_idx_type len = flist.length ();
00228 
00229       for (octave_idx_type i = 0; i < len; i++)
00230         {
00231           std::string fname = flist[i];
00232 
00233           std::string ext;
00234           std::string base = fname;
00235 
00236           size_t pos = fname.rfind ('.');
00237 
00238           if (pos != std::string::npos)
00239             {
00240               base = fname.substr (0, pos);
00241               ext = fname.substr (pos);
00242 
00243               if (valid_identifier (base))
00244                 {
00245                   int t = 0;
00246 
00247                   if (ext == ".m")
00248                     t = load_path::M_FILE;
00249                   else if (ext == ".oct")
00250                     t = load_path::OCT_FILE;
00251                   else if (ext == ".mex")
00252                     t = load_path::MEX_FILE;
00253 
00254                   retval[base] |= t;
00255                 }
00256             }
00257         }
00258     }
00259   else
00260     {
00261       std::string msg = dir.error ();
00262       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
00263     }
00264 
00265   return retval;
00266 }
00267 
00268 void
00269 load_path::dir_info::get_private_file_map (const std::string& d)
00270 {
00271   private_file_map = get_fcn_files (d);
00272 }
00273 
00274 void
00275 load_path::dir_info::get_method_file_map (const std::string& d,
00276                                           const std::string& class_name)
00277 {
00278   method_file_map[class_name].method_file_map = get_fcn_files (d);
00279 
00280   std::string pd = file_ops::concat (d, "private");
00281 
00282   file_stat fs (pd);
00283 
00284   if (fs && fs.is_dir ())
00285     method_file_map[class_name].private_file_map = get_fcn_files (pd);
00286 }
00287 
00288 bool
00289 load_path::instance_ok (void)
00290 {
00291   bool retval = true;
00292 
00293   if (! instance)
00294     {
00295       instance = new load_path ();
00296 
00297       if (instance)
00298         singleton_cleanup_list::add (cleanup_instance);
00299     }
00300 
00301   if (! instance)
00302     {
00303       ::error ("unable to create load path object!");
00304 
00305       retval = false;
00306     }
00307 
00308   return retval;
00309 }
00310 
00311 // FIXME -- maybe we should also maintain a map to speed up this
00312 // method of access.
00313 
00314 load_path::const_dir_info_list_iterator
00315 load_path::find_dir_info (const std::string& dir_arg) const
00316 {
00317   std::string dir = file_ops::tilde_expand (dir_arg);
00318 
00319   const_dir_info_list_iterator retval = dir_info_list.begin ();
00320 
00321   while (retval != dir_info_list.end ())
00322     {
00323       if (retval->dir_name == dir)
00324         break;
00325 
00326       retval++;
00327     }
00328 
00329   return retval;
00330 }
00331 
00332 load_path::dir_info_list_iterator
00333 load_path::find_dir_info (const std::string& dir_arg)
00334 {
00335   std::string dir = file_ops::tilde_expand (dir_arg);
00336 
00337   dir_info_list_iterator retval = dir_info_list.begin ();
00338 
00339   while (retval != dir_info_list.end ())
00340     {
00341       if (retval->dir_name == dir)
00342         break;
00343 
00344       retval++;
00345     }
00346 
00347   return retval;
00348 }
00349 
00350 bool
00351 load_path::contains (const std::string& dir) const
00352 {
00353   return find_dir_info (dir) != dir_info_list.end ();
00354 }
00355 
00356 void
00357 load_path::move_fcn_map (const std::string& dir_name,
00358                          const string_vector& fcn_files, bool at_end)
00359 {
00360   octave_idx_type len = fcn_files.length ();
00361 
00362   for (octave_idx_type k = 0; k < len; k++)
00363     {
00364       std::string fname = fcn_files[k];
00365 
00366       std::string ext;
00367       std::string base = fname;
00368 
00369       size_t pos = fname.rfind ('.');
00370 
00371       if (pos != std::string::npos)
00372         {
00373           base = fname.substr (0, pos);
00374           ext = fname.substr (pos);
00375         }
00376 
00377       file_info_list_type& file_info_list = fcn_map[base];
00378 
00379       if (file_info_list.size () == 1)
00380         continue;
00381       else
00382         {
00383           for (file_info_list_iterator p = file_info_list.begin ();
00384                p != file_info_list.end ();
00385                p++)
00386             {
00387               if (p->dir_name == dir_name)
00388                 {
00389                   file_info fi = *p;
00390 
00391                   file_info_list.erase (p);
00392 
00393                   if (at_end)
00394                     file_info_list.push_back (fi);
00395                   else
00396                     file_info_list.push_front (fi);
00397 
00398                   break;
00399                 }
00400             }
00401         }
00402     }
00403 }
00404 
00405 void
00406 load_path::move_method_map (const std::string& dir_name, bool at_end)
00407 {
00408   for (method_map_iterator i = method_map.begin ();
00409        i != method_map.end ();
00410        i++)
00411     {
00412       std::string class_name = i->first;
00413 
00414       fcn_map_type& fm = i->second;
00415 
00416       std::string full_dir_name
00417         = file_ops::concat (dir_name, "@" + class_name);
00418 
00419       for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
00420         {
00421           file_info_list_type& file_info_list = q->second;
00422 
00423           if (file_info_list.size () == 1)
00424             continue;
00425           else
00426             {
00427               for (file_info_list_iterator p = file_info_list.begin ();
00428                p != file_info_list.end ();
00429                p++)
00430                 {
00431                   if (p->dir_name == full_dir_name)
00432                     {
00433                       file_info fi = *p;
00434 
00435                       file_info_list.erase (p);
00436 
00437                       if (at_end)
00438                         file_info_list.push_back (fi);
00439                       else
00440                         file_info_list.push_front (fi);
00441 
00442                       break;
00443                     }
00444                 }
00445             }
00446         }
00447     }
00448 }
00449 
00450 void
00451 load_path::move (dir_info_list_iterator i, bool at_end)
00452 {
00453   if (dir_info_list.size () > 1)
00454     {
00455       dir_info di = *i;
00456 
00457       dir_info_list.erase (i);
00458 
00459       if (at_end)
00460         dir_info_list.push_back (di);
00461       else
00462         dir_info_list.push_front (di);
00463 
00464       std::string dir_name = di.dir_name;
00465 
00466       move_fcn_map (dir_name, di.fcn_files, at_end);
00467 
00468       // No need to move elements of private function map.
00469 
00470       move_method_map (dir_name, at_end);
00471     }
00472 }
00473 
00474 static void
00475 maybe_add_path_elts (std::string& path, const std::string& dir)
00476 {
00477   std::string tpath = genpath (dir);
00478 
00479   if (! tpath.empty ())
00480     {
00481       if (path.empty ())
00482         path = tpath;
00483       else
00484         path += dir_path::path_sep_str () + tpath;
00485     }
00486 }
00487 
00488 void
00489 load_path::do_initialize (bool set_initial_path)
00490 {
00491   sys_path = "";
00492 
00493   if (set_initial_path)
00494     {
00495       maybe_add_path_elts (sys_path, Vlocal_ver_oct_file_dir);
00496       maybe_add_path_elts (sys_path, Vlocal_api_oct_file_dir);
00497       maybe_add_path_elts (sys_path, Vlocal_oct_file_dir);
00498       maybe_add_path_elts (sys_path, Vlocal_ver_fcn_file_dir);
00499       maybe_add_path_elts (sys_path, Vlocal_api_fcn_file_dir);
00500       maybe_add_path_elts (sys_path, Vlocal_fcn_file_dir);
00501       maybe_add_path_elts (sys_path, Voct_file_dir);
00502       maybe_add_path_elts (sys_path, Vfcn_file_dir);
00503     }
00504 
00505   std::string tpath = load_path::command_line_path;
00506 
00507   if (tpath.empty ())
00508     tpath = octave_env::getenv ("OCTAVE_PATH");
00509 
00510   std::string xpath;
00511 
00512   if (! tpath.empty ())
00513     {
00514       xpath = tpath;
00515 
00516       if (! sys_path.empty ())
00517         xpath += dir_path::path_sep_str () + sys_path;
00518     }
00519   else
00520     xpath = sys_path;
00521 
00522   do_set (xpath, false);
00523 }
00524 
00525 void
00526 load_path::do_clear (void)
00527 {
00528   dir_info_list.clear ();
00529   fcn_map.clear ();
00530   private_fcn_map.clear ();
00531   method_map.clear ();
00532 }
00533 
00534 static std::list<std::string>
00535 split_path (const std::string& p)
00536 {
00537   std::list<std::string> retval;
00538 
00539   size_t beg = 0;
00540   size_t end = p.find (dir_path::path_sep_char ());
00541 
00542   size_t len = p.length ();
00543 
00544   while (end != std::string::npos)
00545     {
00546       std::string elt = p.substr (beg, end-beg);
00547 
00548       if (! elt.empty ())
00549         retval.push_back (elt);
00550 
00551       beg = end + 1;
00552 
00553       if (beg == len)
00554         break;
00555 
00556       end = p.find (dir_path::path_sep_char (), beg);
00557     }
00558 
00559   std::string elt = p.substr (beg);
00560 
00561   if (! elt.empty ())
00562     retval.push_back (elt);
00563 
00564   return retval;
00565 }
00566 
00567 void
00568 load_path::do_set (const std::string& p, bool warn)
00569 {
00570   std::list<std::string> elts = split_path (p);
00571 
00572   // Temporarily disable add hook.
00573 
00574   unwind_protect frame;
00575   frame.protect_var (add_hook);
00576 
00577   add_hook = 0;
00578 
00579   do_clear ();
00580 
00581   for (std::list<std::string>::const_iterator i = elts.begin ();
00582        i != elts.end ();
00583        i++)
00584     do_append (*i, warn);
00585 
00586   // Restore add hook and execute for all newly added directories.
00587   frame.run_top ();
00588 
00589   for (dir_info_list_iterator i = dir_info_list.begin ();
00590        i != dir_info_list.end ();
00591        i++)
00592     {
00593       if (add_hook)
00594         add_hook (i->dir_name);
00595     }
00596 
00597   // Always prepend current directory.
00598   do_prepend (".", warn);
00599 }
00600 
00601 void
00602 load_path::do_append (const std::string& dir, bool warn)
00603 {
00604   if (! dir.empty ())
00605     do_add (dir, true, warn);
00606 }
00607 
00608 void
00609 load_path::do_prepend (const std::string& dir, bool warn)
00610 {
00611   if (! dir.empty ())
00612     do_add (dir, false, warn);
00613 }
00614 
00615 // Strip trailing directory separators.
00616 
00617 static std::string
00618 strip_trailing_separators (const std::string& dir_arg)
00619 {
00620   std::string dir = dir_arg;
00621 
00622   size_t k = dir.length ();
00623 
00624   while (k > 1 && file_ops::is_dir_sep (dir[k-1]))
00625     k--;
00626 
00627   if (k < dir.length ())
00628     dir.resize (k);
00629 
00630   return dir;
00631 }
00632 
00633 void
00634 load_path::do_add (const std::string& dir_arg, bool at_end, bool warn)
00635 {
00636   size_t len = dir_arg.length ();
00637 
00638   if (len > 1 && dir_arg.substr (len-2) == "//")
00639     warning_with_id ("Octave:recursive-path-search",
00640                      "trailing '//' is no longer special in search path elements");
00641 
00642   std::string dir = file_ops::tilde_expand (dir_arg);
00643 
00644   dir = strip_trailing_separators (dir);
00645 
00646   dir_info_list_iterator i = find_dir_info (dir);
00647 
00648   if (i != dir_info_list.end ())
00649     move (i, at_end);
00650   else
00651     {
00652       file_stat fs (dir);
00653 
00654       if (fs)
00655         {
00656           if (fs.is_dir ())
00657             {
00658               dir_info di (dir);
00659 
00660               if (! error_state)
00661                 {
00662                   if (at_end)
00663                     dir_info_list.push_back (di);
00664                   else
00665                     dir_info_list.push_front (di);
00666 
00667                   add_to_fcn_map (di, at_end);
00668 
00669                   add_to_private_fcn_map (di);
00670 
00671                   add_to_method_map (di, at_end);
00672 
00673                   if (add_hook)
00674                     add_hook (dir);
00675                 }
00676             }
00677           else if (warn)
00678             warning ("addpath: %s: not a directory", dir_arg.c_str ());
00679         }
00680       else if (warn)
00681         {
00682           std::string msg = fs.error ();
00683           warning ("addpath: %s: %s", dir_arg.c_str (), msg.c_str ());
00684         }
00685     }
00686 
00687   // FIXME -- is there a better way to do this?
00688 
00689   i = find_dir_info (".");
00690 
00691   if (i != dir_info_list.end ())
00692     move (i, false);
00693 }
00694 
00695 void
00696 load_path::remove_fcn_map (const std::string& dir,
00697                            const string_vector& fcn_files)
00698 {
00699   octave_idx_type len = fcn_files.length ();
00700 
00701   for (octave_idx_type k = 0; k < len; k++)
00702     {
00703       std::string fname = fcn_files[k];
00704 
00705       std::string ext;
00706       std::string base = fname;
00707 
00708       size_t pos = fname.rfind ('.');
00709 
00710       if (pos != std::string::npos)
00711         {
00712           base = fname.substr (0, pos);
00713           ext = fname.substr (pos);
00714         }
00715 
00716       file_info_list_type& file_info_list = fcn_map[base];
00717 
00718       for (file_info_list_iterator p = file_info_list.begin ();
00719            p != file_info_list.end ();
00720            p++)
00721         {
00722           if (p->dir_name == dir)
00723             {
00724               file_info_list.erase (p);
00725 
00726               if (file_info_list.empty ())
00727                 fcn_map.erase (fname);
00728 
00729               break;
00730             }
00731         }
00732     }
00733 }
00734 
00735 void
00736 load_path::remove_private_fcn_map (const std::string& dir)
00737 {
00738   private_fcn_map_iterator p = private_fcn_map.find (dir);
00739 
00740   if (p != private_fcn_map.end ())
00741     private_fcn_map.erase (p);
00742 }
00743 
00744 void
00745 load_path::remove_method_map (const std::string& dir)
00746 {
00747   for (method_map_iterator i = method_map.begin ();
00748        i != method_map.end ();
00749        i++)
00750     {
00751       std::string class_name = i->first;
00752 
00753       fcn_map_type& fm = i->second;
00754 
00755       std::string full_dir_name = file_ops::concat (dir, "@" + class_name);
00756 
00757       for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
00758         {
00759           file_info_list_type& file_info_list = q->second;
00760 
00761           if (file_info_list.size () == 1)
00762             continue;
00763           else
00764             {
00765               for (file_info_list_iterator p = file_info_list.begin ();
00766                p != file_info_list.end ();
00767                p++)
00768                 {
00769                   if (p->dir_name == full_dir_name)
00770                     {
00771                       file_info_list.erase (p);
00772 
00773                       // FIXME -- if there are no other elements, we
00774                       // should remove this element of fm but calling
00775                       // erase here would invalidate the iterator q.
00776 
00777                       break;
00778                     }
00779                 }
00780             }
00781         }
00782     }
00783 }
00784 
00785 bool
00786 load_path::do_remove (const std::string& dir_arg)
00787 {
00788   bool retval = false;
00789 
00790   if (! dir_arg.empty ())
00791     {
00792       if (dir_arg == ".")
00793         {
00794           warning ("rmpath: can't remove \".\" from path");
00795 
00796           // Avoid additional warnings.
00797           retval = true;
00798         }
00799       else
00800         {
00801           std::string dir = file_ops::tilde_expand (dir_arg);
00802 
00803           dir = strip_trailing_separators (dir);
00804 
00805           dir_info_list_iterator i = find_dir_info (dir);
00806 
00807           if (i != dir_info_list.end ())
00808             {
00809               retval = true;
00810 
00811               if (remove_hook)
00812                 remove_hook (dir);
00813 
00814               string_vector fcn_files = i->fcn_files;
00815 
00816               dir_info_list.erase (i);
00817 
00818               remove_fcn_map (dir, fcn_files);
00819 
00820               remove_private_fcn_map (dir);
00821 
00822               remove_method_map (dir);
00823             }
00824         }
00825     }
00826 
00827   return retval;
00828 }
00829 
00830 void
00831 load_path::do_update (void) const
00832 {
00833   // I don't see a better way to do this because we need to
00834   // preserve the correct directory ordering for new files that
00835   // have appeared.
00836 
00837   fcn_map.clear ();
00838 
00839   private_fcn_map.clear ();
00840 
00841   method_map.clear ();
00842 
00843   for (dir_info_list_iterator p = dir_info_list.begin ();
00844        p != dir_info_list.end ();
00845        p++)
00846     {
00847       dir_info& di = *p;
00848 
00849       di.update ();
00850 
00851       add_to_fcn_map (di, true);
00852 
00853       add_to_private_fcn_map (di);
00854 
00855       add_to_method_map (di, true);
00856     }
00857 }
00858 
00859 bool
00860 load_path::check_file_type (std::string& fname, int type, int possible_types,
00861                             const std::string& fcn, const char *who)
00862 {
00863   bool retval = false;
00864 
00865   if (type == load_path::OCT_FILE)
00866     {
00867       if ((type & possible_types) == load_path::OCT_FILE)
00868         {
00869           fname += ".oct";
00870           retval = true;
00871         }
00872     }
00873   else if (type == load_path::M_FILE)
00874     {
00875       if ((type & possible_types) == load_path::M_FILE)
00876         {
00877           fname += ".m";
00878           retval = true;
00879         }
00880     }
00881   else if (type == load_path::MEX_FILE)
00882     {
00883       if ((type & possible_types) == load_path::MEX_FILE)
00884         {
00885           fname += ".mex";
00886           retval = true;
00887         }
00888     }
00889   else if (type == (load_path::M_FILE | load_path::OCT_FILE))
00890     {
00891       if (possible_types & load_path::OCT_FILE)
00892         {
00893           fname += ".oct";
00894           retval = true;
00895         }
00896       else if (possible_types & load_path::M_FILE)
00897         {
00898           fname += ".m";
00899           retval = true;
00900         }
00901     }
00902   else if (type == (load_path::M_FILE | load_path::MEX_FILE))
00903     {
00904       if (possible_types & load_path::MEX_FILE)
00905         {
00906           fname += ".mex";
00907           retval = true;
00908         }
00909       else if (possible_types & load_path::M_FILE)
00910         {
00911           fname += ".m";
00912           retval = true;
00913         }
00914     }
00915   else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
00916     {
00917       if (possible_types & load_path::OCT_FILE)
00918         {
00919           fname += ".oct";
00920           retval = true;
00921         }
00922       else if (possible_types & load_path::MEX_FILE)
00923         {
00924           fname += ".mex";
00925           retval = true;
00926         }
00927     }
00928   else if (type == (load_path::M_FILE | load_path::OCT_FILE
00929                     | load_path::MEX_FILE))
00930     {
00931       if (possible_types & load_path::OCT_FILE)
00932         {
00933           fname += ".oct";
00934           retval = true;
00935         }
00936       else if (possible_types & load_path::MEX_FILE)
00937         {
00938           fname += ".mex";
00939           retval = true;
00940         }
00941       else if (possible_types & load_path::M_FILE)
00942         {
00943           fname += ".m";
00944           retval = true;
00945         }
00946     }
00947   else
00948     error ("%s: %s: invalid type code = %d", who, fcn.c_str (), type);
00949 
00950   return retval;
00951 }
00952 
00953 std::string
00954 load_path::do_find_fcn (const std::string& fcn, std::string& dir_name,
00955                         int type) const
00956 {
00957   std::string retval;
00958 
00959   //  update ();
00960 
00961   if (fcn.length () > 0 && fcn[0] == '@')
00962     {
00963       size_t pos = fcn.find ('/');
00964 
00965       if (pos != std::string::npos)
00966         {
00967           std::string class_name = fcn.substr (1, pos-1);
00968           std::string meth = fcn.substr (pos+1);
00969 
00970           retval = do_find_method (class_name, meth, dir_name);
00971         }
00972       else
00973         retval = std::string ();
00974     }
00975   else
00976     {
00977       dir_name = std::string ();
00978 
00979       const_fcn_map_iterator p = fcn_map.find (fcn);
00980 
00981       if (p != fcn_map.end ())
00982         {
00983           const file_info_list_type& file_info_list = p->second;
00984 
00985           for (const_file_info_list_iterator i = file_info_list.begin ();
00986                i != file_info_list.end ();
00987                i++)
00988             {
00989               const file_info& fi = *i;
00990 
00991               retval = file_ops::concat (fi.dir_name, fcn);
00992 
00993               if (check_file_type (retval, type, fi.types,
00994                                    fcn, "load_path::do_find_fcn"))
00995                 {
00996                   dir_name = fi.dir_name;
00997                   break;
00998                 }
00999               else
01000                 retval = std::string ();
01001             }
01002         }
01003     }
01004 
01005   return retval;
01006 }
01007 
01008 std::string
01009 load_path::do_find_private_fcn (const std::string& dir,
01010                                 const std::string& fcn, int type) const
01011 {
01012   std::string retval;
01013 
01014   //  update ();
01015 
01016   const_private_fcn_map_iterator q = private_fcn_map.find (dir);
01017 
01018   if (q != private_fcn_map.end ())
01019     {
01020       const dir_info::fcn_file_map_type& m = q->second;
01021 
01022       dir_info::const_fcn_file_map_iterator p = m.find (fcn);
01023 
01024       if (p != m.end ())
01025         {
01026           std::string fname
01027             = file_ops::concat (file_ops::concat (dir, "private"), fcn);
01028 
01029           if (check_file_type (fname, type, p->second, fcn,
01030                                "load_path::find_private_fcn"))
01031             retval = fname;
01032         }
01033     }
01034 
01035   return retval;
01036 }
01037 
01038 std::string
01039 load_path::do_find_method (const std::string& class_name,
01040                            const std::string& meth,
01041                            std::string& dir_name, int type) const
01042 {
01043   std::string retval;
01044 
01045   //  update ();
01046 
01047   dir_name = std::string ();
01048 
01049   const_method_map_iterator q = method_map.find (class_name);
01050 
01051   if (q != method_map.end ())
01052     {
01053       const fcn_map_type& m = q->second;
01054 
01055       const_fcn_map_iterator p = m.find (meth);
01056 
01057       if (p != m.end ())
01058         {
01059           const file_info_list_type& file_info_list = p->second;
01060 
01061           for (const_file_info_list_iterator i = file_info_list.begin ();
01062                i != file_info_list.end ();
01063                i++)
01064             {
01065               const file_info& fi = *i;
01066 
01067               retval = file_ops::concat (fi.dir_name, meth);
01068 
01069               bool found = check_file_type (retval, type, fi.types,
01070                                             meth, "load_path::do_find_method");
01071 
01072               if (found)
01073                 {
01074                   dir_name = fi.dir_name;
01075                   break;
01076                 }
01077               else
01078                 retval = std::string ();
01079             }
01080         }
01081     }
01082 
01083   return retval;
01084 }
01085 
01086 std::list<std::string>
01087 load_path::do_methods (const std::string& class_name) const
01088 {
01089   std::list<std::string> retval;
01090 
01091   //  update ();
01092 
01093   const_method_map_iterator q = method_map.find (class_name);
01094 
01095   if (q != method_map.end ())
01096     {
01097       const fcn_map_type& m = q->second;
01098 
01099       for (const_fcn_map_iterator p = m.begin (); p != m.end (); p++)
01100         retval.push_back (p->first);
01101     }
01102 
01103   if (! retval.empty ())
01104     retval.sort ();
01105 
01106   return retval;
01107 }
01108 
01109 std::list<std::string>
01110 load_path::do_overloads (const std::string& meth) const
01111 {
01112   std::list<std::string> retval;
01113 
01114   //  update ();
01115 
01116   for (const_method_map_iterator q = method_map.begin ();
01117        q != method_map.end (); q++)
01118     {
01119       const fcn_map_type& m = q->second;
01120 
01121       if (m.find (meth) != m.end ())
01122         retval.push_back (q->first);
01123     }
01124 
01125   return retval;
01126 }
01127 
01128 std::string
01129 load_path::do_find_file (const std::string& file) const
01130 {
01131   std::string retval;
01132 
01133   if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
01134     {
01135       if (octave_env::absolute_pathname (file)
01136           || octave_env::rooted_relative_pathname (file))
01137         {
01138           file_stat fs (file);
01139 
01140           if (fs.exists ())
01141             return file;
01142         }
01143       else
01144         {
01145           for (const_dir_info_list_iterator p = dir_info_list.begin ();
01146                p != dir_info_list.end ();
01147                p++)
01148             {
01149               std::string tfile = file_ops::concat (p->dir_name, file);
01150 
01151               file_stat fs (tfile);
01152 
01153               if (fs.exists ())
01154                 return tfile;
01155             }
01156         }
01157     }
01158   else
01159     {
01160       for (const_dir_info_list_iterator p = dir_info_list.begin ();
01161            p != dir_info_list.end ();
01162            p++)
01163         {
01164           string_vector all_files = p->all_files;
01165 
01166           octave_idx_type len = all_files.length ();
01167 
01168           for (octave_idx_type i = 0; i < len; i++)
01169             {
01170               if (all_files[i] == file)
01171                 return file_ops::concat (p->dir_name, file);
01172             }
01173         }
01174     }
01175 
01176   return retval;
01177 }
01178 
01179 std::string
01180 load_path::do_find_dir (const std::string& dir) const
01181 {
01182   std::string retval;
01183 
01184   if (dir.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos
01185       && (octave_env::absolute_pathname (dir)
01186           || octave_env::rooted_relative_pathname (dir)))
01187     {
01188       file_stat fs (dir);
01189 
01190       if (fs.exists () && fs.is_dir ())
01191         return dir;
01192     }
01193   else
01194     {
01195       for (const_dir_info_list_iterator p = dir_info_list.begin ();
01196            p != dir_info_list.end ();
01197            p++)
01198         {
01199           std::string dname = octave_env::make_absolute (p->dir_name);
01200 
01201           size_t dname_len = dname.length ();
01202 
01203           if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ())
01204             {
01205               dname = dname.substr (0, dname_len - 1);
01206               dname_len--;
01207             }
01208 
01209           size_t dir_len = dir.length ();
01210 
01211           if (dname_len >= dir_len
01212               && file_ops::is_dir_sep (dname[dname_len - dir_len - 1])
01213               && dir.compare (dname.substr (dname_len - dir_len)) == 0)
01214             {
01215               file_stat fs (p->dir_name);
01216 
01217               if (fs.exists () && fs.is_dir ())
01218                 return p->dir_name;
01219             }
01220         }
01221     }
01222 
01223   return retval;
01224 }
01225 
01226 string_vector
01227 load_path::do_find_matching_dirs (const std::string& dir) const
01228 {
01229   std::list<std::string> retlist;
01230 
01231   if (dir.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos
01232       && (octave_env::absolute_pathname (dir)
01233           || octave_env::rooted_relative_pathname (dir)))
01234     {
01235       file_stat fs (dir);
01236 
01237       if (fs.exists () && fs.is_dir ())
01238         retlist.push_back (dir);
01239     }
01240   else
01241     {
01242       for (const_dir_info_list_iterator p = dir_info_list.begin ();
01243            p != dir_info_list.end ();
01244            p++)
01245         {
01246           std::string dname = octave_env::make_absolute (p->dir_name);
01247 
01248           size_t dname_len = dname.length ();
01249 
01250           if (dname.substr (dname_len - 1) == file_ops::dir_sep_str ())
01251             {
01252               dname = dname.substr (0, dname_len - 1);
01253               dname_len--;
01254             }
01255 
01256           size_t dir_len = dir.length ();
01257 
01258           if (dname_len >= dir_len
01259               && file_ops::is_dir_sep (dname[dname_len - dir_len - 1])
01260               && dir.compare (dname.substr (dname_len - dir_len)) == 0)
01261             {
01262               file_stat fs (p->dir_name);
01263 
01264               if (fs.exists () && fs.is_dir ())
01265                 retlist.push_back (p->dir_name);
01266             }
01267         }
01268     }
01269 
01270   return retlist;
01271 }
01272 
01273 std::string
01274 load_path::do_find_first_of (const string_vector& flist) const
01275 {
01276   std::string retval;
01277 
01278   std::string dir_name;
01279   std::string file_name;
01280 
01281   octave_idx_type flen = flist.length ();
01282   octave_idx_type rel_flen = 0;
01283 
01284   string_vector rel_flist (flen);
01285 
01286   for (octave_idx_type i = 0; i < flen; i++)
01287     {
01288       std::string file = flist[i];
01289 
01290       if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
01291         {
01292           if (octave_env::absolute_pathname (file)
01293               || octave_env::rooted_relative_pathname (file))
01294             {
01295               file_stat fs (file);
01296 
01297               if (fs.exists ())
01298                 return file;
01299             }
01300           else
01301             {
01302               for (const_dir_info_list_iterator p = dir_info_list.begin ();
01303                    p != dir_info_list.end ();
01304                    p++)
01305                 {
01306                   std::string tfile = file_ops::concat (p->dir_name, file);
01307 
01308                   file_stat fs (tfile);
01309 
01310                   if (fs.exists ())
01311                     return tfile;
01312                 }
01313             }
01314         }
01315       else
01316         rel_flist[rel_flen++] = file;
01317     }
01318 
01319   rel_flist.resize (rel_flen);
01320 
01321   for (const_dir_info_list_iterator p = dir_info_list.begin ();
01322        p != dir_info_list.end ();
01323        p++)
01324     {
01325       string_vector all_files = p->all_files;
01326 
01327       octave_idx_type len = all_files.length ();
01328 
01329       for (octave_idx_type i = 0; i < len; i++)
01330         {
01331           for (octave_idx_type j = 0; j < rel_flen; j++)
01332             {
01333               if (all_files[i] == rel_flist[j])
01334                 {
01335                   dir_name = p->dir_name;
01336                   file_name = rel_flist[j];
01337 
01338                   goto done;
01339                 }
01340             }
01341         }
01342     }
01343 
01344  done:
01345 
01346   if (! dir_name.empty ())
01347     retval = file_ops::concat (dir_name, file_name);
01348 
01349   return retval;
01350 }
01351 
01352 string_vector
01353 load_path::do_find_all_first_of (const string_vector& flist) const
01354 {
01355   std::list<std::string> retlist;
01356 
01357   std::string dir_name;
01358   std::string file_name;
01359 
01360   octave_idx_type flen = flist.length ();
01361   octave_idx_type rel_flen = 0;
01362 
01363   string_vector rel_flist (flen);
01364 
01365   for (octave_idx_type i = 0; i < flen; i++)
01366     {
01367       std::string file = flist[i];
01368 
01369       if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos)
01370         {
01371           if (octave_env::absolute_pathname (file)
01372               || octave_env::rooted_relative_pathname (file))
01373             {
01374               file_stat fs (file);
01375 
01376               if (fs.exists ())
01377                 retlist.push_back (file);
01378             }
01379           else
01380             {
01381               for (const_dir_info_list_iterator p = dir_info_list.begin ();
01382                    p != dir_info_list.end ();
01383                    p++)
01384                 {
01385                   std::string tfile = file_ops::concat (p->dir_name, file);
01386 
01387                   file_stat fs (tfile);
01388 
01389                   if (fs.exists ())
01390                     retlist.push_back (tfile);
01391                 }
01392             }
01393         }
01394       else
01395         rel_flist[rel_flen++] = file;
01396     }
01397 
01398   rel_flist.resize (rel_flen);
01399 
01400   for (const_dir_info_list_iterator p = dir_info_list.begin ();
01401        p != dir_info_list.end ();
01402        p++)
01403     {
01404       string_vector all_files = p->all_files;
01405 
01406       octave_idx_type len = all_files.length ();
01407 
01408       for (octave_idx_type i = 0; i < len; i++)
01409         {
01410           for (octave_idx_type j = 0; j < rel_flen; j++)
01411             {
01412               if (all_files[i] == rel_flist[j])
01413                 retlist.push_back
01414                   (file_ops::concat (p->dir_name, rel_flist[j]));
01415             }
01416         }
01417     }
01418 
01419   return retlist;
01420 }
01421 
01422 string_vector
01423 load_path::do_dirs (void) const
01424 {
01425   size_t len = dir_info_list.size ();
01426 
01427   string_vector retval (len);
01428 
01429   octave_idx_type k = 0;
01430 
01431   for (const_dir_info_list_iterator i = dir_info_list.begin ();
01432        i != dir_info_list.end ();
01433        i++)
01434     retval[k++] = i->dir_name;
01435 
01436   return retval;
01437 }
01438 
01439 std::list<std::string>
01440 load_path::do_dir_list (void) const
01441 {
01442   std::list<std::string> retval;
01443 
01444   for (const_dir_info_list_iterator i = dir_info_list.begin ();
01445        i != dir_info_list.end ();
01446        i++)
01447     retval.push_back (i->dir_name);
01448 
01449   return retval;
01450 }
01451 
01452 string_vector
01453 load_path::do_files (const std::string& dir, bool omit_exts) const
01454 {
01455   string_vector retval;
01456 
01457   const_dir_info_list_iterator p = find_dir_info (dir);
01458 
01459   if (p != dir_info_list.end ())
01460     retval = p->fcn_files;
01461 
01462   if (omit_exts)
01463     {
01464       octave_idx_type len = retval.length ();
01465 
01466       for (octave_idx_type i = 0; i < len; i++)
01467         {
01468           std::string fname = retval[i];
01469 
01470           size_t pos = fname.rfind ('.');
01471 
01472           if (pos != std::string::npos)
01473             retval[i] = fname.substr (0, pos);
01474         }
01475     }
01476 
01477   return retval;
01478 }
01479 
01480 string_vector
01481 load_path::do_fcn_names (void) const
01482 {
01483   size_t len = fcn_map.size ();
01484 
01485   string_vector retval (len);
01486 
01487   octave_idx_type count = 0;
01488 
01489   for (const_fcn_map_iterator p = fcn_map.begin ();
01490        p != fcn_map.end ();
01491        p++)
01492     retval[count++] = p->first;
01493 
01494   return retval;
01495 }
01496 
01497 std::string
01498 load_path::do_path (void) const
01499 {
01500   std::string xpath;
01501 
01502   string_vector xdirs = load_path::dirs ();
01503 
01504   octave_idx_type len = xdirs.length ();
01505 
01506   if (len > 0)
01507     xpath = xdirs[0];
01508 
01509   for (octave_idx_type i = 1; i < len; i++)
01510     xpath += dir_path::path_sep_str () + xdirs[i];
01511 
01512   return xpath;
01513 }
01514 
01515 void
01516 print_types (std::ostream& os, int types)
01517 {
01518   bool printed_type = false;
01519 
01520   if (types & load_path::OCT_FILE)
01521     {
01522       os << "oct";
01523       printed_type = true;
01524     }
01525 
01526   if (types & load_path::MEX_FILE)
01527     {
01528       if (printed_type)
01529         os << "|";
01530       os << "mex";
01531       printed_type = true;
01532     }
01533 
01534   if (types & load_path::M_FILE)
01535     {
01536       if (printed_type)
01537         os << "|";
01538       os << "m";
01539       printed_type = true;
01540     }
01541 }
01542 
01543 void
01544 print_fcn_list (std::ostream& os,
01545                 const load_path::dir_info::fcn_file_map_type& lst)
01546 {
01547   for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
01548        p != lst.end ();
01549        p++)
01550     {
01551       os << "  " << p->first << " (";
01552 
01553       print_types (os, p->second);
01554 
01555       os << ")\n";
01556     }
01557 }
01558 
01559 string_vector
01560 get_file_list (const load_path::dir_info::fcn_file_map_type& lst)
01561 {
01562   octave_idx_type n = lst.size ();
01563 
01564   string_vector retval (n);
01565 
01566   octave_idx_type count = 0;
01567 
01568   for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
01569        p != lst.end ();
01570        p++)
01571     {
01572       std::string nm = p->first;
01573 
01574       int types = p->second;
01575 
01576       if (types & load_path::OCT_FILE)
01577         nm += ".oct";
01578       else if (types & load_path::MEX_FILE)
01579         nm += ".mex";
01580       else
01581         nm += ".m";
01582 
01583       retval[count++] = nm;
01584     }
01585 
01586   return retval;
01587 }
01588 
01589 void
01590 load_path::do_display (std::ostream& os) const
01591 {
01592   for (const_dir_info_list_iterator i = dir_info_list.begin ();
01593        i != dir_info_list.end ();
01594        i++)
01595     {
01596       string_vector fcn_files = i->fcn_files;
01597 
01598       if (! fcn_files.empty ())
01599         {
01600           os << "\n*** function files in " << i->dir_name << ":\n\n";
01601 
01602           fcn_files.list_in_columns (os);
01603         }
01604 
01605       const dir_info::method_file_map_type& method_file_map
01606         = i->method_file_map;
01607 
01608       if (! method_file_map.empty ())
01609         {
01610           for (dir_info::const_method_file_map_iterator p = method_file_map.begin ();
01611                p != method_file_map.end ();
01612                p++)
01613             {
01614               os << "\n*** methods in " << i->dir_name
01615                  << "/@" << p->first << ":\n\n";
01616 
01617               const dir_info::class_info& ci = p->second;
01618 
01619               string_vector method_files = get_file_list (ci.method_file_map);
01620 
01621               method_files.list_in_columns (os);
01622             }
01623         }
01624     }
01625 
01626   for (const_private_fcn_map_iterator i = private_fcn_map.begin ();
01627        i != private_fcn_map.end (); i++)
01628     {
01629       os << "\n*** private functions in "
01630          << file_ops::concat (i->first, "private") << ":\n\n";
01631 
01632       print_fcn_list (os, i->second);
01633     }
01634 
01635 #if defined (DEBUG_LOAD_PATH)
01636 
01637   for (const_fcn_map_iterator i = fcn_map.begin ();
01638        i != fcn_map.end ();
01639        i++)
01640     {
01641       os << i->first << ":\n";
01642 
01643       const file_info_list_type& file_info_list = i->second;
01644 
01645       for (const_file_info_list_iterator p = file_info_list.begin ();
01646            p != file_info_list.end ();
01647            p++)
01648         {
01649           os << "  " << p->dir_name << " (";
01650 
01651           print_types (os, p->types);
01652 
01653           os << ")\n";
01654         }
01655     }
01656 
01657   for (const_method_map_iterator i = method_map.begin ();
01658        i != method_map.end ();
01659        i++)
01660     {
01661       os << "CLASS " << i->first << ":\n";
01662 
01663       const fcn_map_type& fm = i->second;
01664 
01665       for (const_fcn_map_iterator q = fm.begin ();
01666            q != fm.end ();
01667            q++)
01668         {
01669           os << "  " << q->first << ":\n";
01670 
01671           const file_info_list_type& file_info_list = q->second;
01672 
01673           for (const_file_info_list_iterator p = file_info_list.begin ();
01674                p != file_info_list.end ();
01675                p++)
01676             {
01677               os << "  " << p->dir_name << " (";
01678 
01679               print_types (os, p->types);
01680 
01681               os << ")\n";
01682             }
01683         }
01684     }
01685 
01686   os << "\n";
01687 
01688 #endif
01689 }
01690 
01691 // True if a path is contained in a path list separated by path_sep_char
01692 static bool
01693 in_path_list (const std::string& path_list, const std::string& path)
01694 {
01695   size_t ps = path.size (), pls = path_list.size (), pos = path_list.find (path);
01696   char psc = dir_path::path_sep_char ();
01697   while (pos != std::string::npos)
01698     {
01699       if ((pos == 0 || path_list[pos-1] == psc)
01700           && (pos + ps == pls || path_list[pos + ps] == psc))
01701         return true;
01702       else
01703         pos = path_list.find (path, pos + 1);
01704     }
01705 
01706   return false;
01707 }
01708 
01709 void
01710 load_path::add_to_fcn_map (const dir_info& di, bool at_end) const
01711 {
01712   std::string dir_name = di.dir_name;
01713 
01714   string_vector fcn_files = di.fcn_files;
01715 
01716   octave_idx_type len = fcn_files.length ();
01717 
01718   for (octave_idx_type i = 0; i < len; i++)
01719     {
01720       std::string fname = fcn_files[i];
01721 
01722       std::string ext;
01723       std::string base = fname;
01724 
01725       size_t pos = fname.rfind ('.');
01726 
01727       if (pos != std::string::npos)
01728         {
01729           base = fname.substr (0, pos);
01730           ext = fname.substr (pos);
01731         }
01732 
01733       file_info_list_type& file_info_list = fcn_map[base];
01734 
01735       file_info_list_iterator p = file_info_list.begin ();
01736 
01737       while (p != file_info_list.end ())
01738         {
01739           if (p->dir_name == dir_name)
01740             break;
01741 
01742           p++;
01743         }
01744 
01745       int t = 0;
01746       if (ext == ".m")
01747         t = load_path::M_FILE;
01748       else if (ext == ".oct")
01749         t = load_path::OCT_FILE;
01750       else if (ext == ".mex")
01751         t = load_path::MEX_FILE;
01752 
01753       if (p == file_info_list.end ())
01754         {
01755           file_info fi (dir_name, t);
01756 
01757           if (at_end)
01758             file_info_list.push_back (fi);
01759           else
01760             {
01761               // Warn if a built-in or library function is being shadowed.
01762 
01763               if (! file_info_list.empty ())
01764                 {
01765                   file_info& old = file_info_list.front ();
01766 
01767                   // FIXME -- do we need to be more careful about the
01768                   // way we look for old.dir_name in sys_path to avoid
01769                   // partial matches?
01770 
01771                   if (sys_path.find (old.dir_name) != std::string::npos
01772                       && in_path_list (sys_path, old.dir_name))
01773                     {
01774                       std::string fcn_path = file_ops::concat (dir_name, fname);
01775 
01776                       warning_with_id ("Octave:shadowed-function",
01777                                        "function %s shadows a core library function",
01778                                        fcn_path.c_str ());
01779                     }
01780                 }
01781               else if (symbol_table::is_built_in_function_name (base))
01782                 {
01783                   std::string fcn_path = file_ops::concat (dir_name, fname);
01784                   warning_with_id ("Octave:shadowed-function",
01785                                    "function %s shadows a built-in function",
01786                                    fcn_path.c_str ());
01787                 }
01788 
01789               file_info_list.push_front (fi);
01790             }
01791         }
01792       else
01793         {
01794           file_info& fi = *p;
01795 
01796           fi.types |= t;
01797         }
01798     }
01799 }
01800 
01801 void
01802 load_path::add_to_private_fcn_map (const dir_info& di) const
01803 {
01804   dir_info::fcn_file_map_type private_file_map = di.private_file_map;
01805 
01806   if (! private_file_map.empty ())
01807     private_fcn_map[di.dir_name] = private_file_map;
01808 }
01809 
01810 void
01811 load_path::add_to_method_map (const dir_info& di, bool at_end) const
01812 {
01813   std::string dir_name = di.dir_name;
01814 
01815   // <CLASS_NAME, CLASS_INFO>
01816   dir_info::method_file_map_type method_file_map = di.method_file_map;
01817 
01818   for (dir_info::const_method_file_map_iterator q = method_file_map.begin ();
01819        q != method_file_map.end ();
01820        q++)
01821     {
01822       std::string class_name = q->first;
01823 
01824       fcn_map_type& fm = method_map[class_name];
01825 
01826       std::string full_dir_name
01827         = file_ops::concat (dir_name, "@" + class_name);
01828 
01829       const dir_info::class_info& ci = q->second;
01830 
01831       // <FCN_NAME, TYPES>
01832       const dir_info::fcn_file_map_type& m = ci.method_file_map;
01833 
01834       for (dir_info::const_fcn_file_map_iterator p = m.begin ();
01835            p != m.end ();
01836            p++)
01837         {
01838           std::string base = p->first;
01839 
01840           int types = p->second;
01841 
01842           file_info_list_type& file_info_list = fm[base];
01843 
01844           file_info_list_iterator p2 = file_info_list.begin ();
01845 
01846           while (p2 != file_info_list.end ())
01847             {
01848               if (p2->dir_name == full_dir_name)
01849                 break;
01850 
01851               p2++;
01852             }
01853 
01854           if (p2 == file_info_list.end ())
01855             {
01856               file_info fi (full_dir_name, types);
01857 
01858               if (at_end)
01859                 file_info_list.push_back (fi);
01860               else
01861                 file_info_list.push_front (fi);
01862             }
01863           else
01864             {
01865               // FIXME -- is this possible?
01866 
01867               file_info& fi = *p2;
01868 
01869               fi.types = types;
01870             }
01871         }
01872 
01873       // <FCN_NAME, TYPES>
01874       dir_info::fcn_file_map_type private_file_map = ci.private_file_map;
01875 
01876       if (! private_file_map.empty ())
01877         private_fcn_map[full_dir_name] = private_file_map;
01878     }
01879 }
01880 
01881 std::string
01882 genpath (const std::string& dirname, const string_vector& skip)
01883 {
01884   std::string retval;
01885 
01886   dir_entry dir (dirname);
01887 
01888   if (dir)
01889     {
01890       retval = dirname;
01891 
01892       string_vector dirlist = dir.read ();
01893 
01894       octave_idx_type len = dirlist.length ();
01895 
01896       for (octave_idx_type i = 0; i < len; i++)
01897         {
01898           std::string elt = dirlist[i];
01899 
01900           bool skip_p = (elt == "." || elt == ".." || elt[0] == '@');
01901 
01902           if (! skip_p)
01903             {
01904               for (octave_idx_type j = 0; j < skip.length (); j++)
01905                 {
01906                   skip_p = (elt == skip[j]);
01907                   if (skip_p)
01908                     break;
01909                 }
01910 
01911               if (! skip_p)
01912                 {
01913                   std::string nm = file_ops::concat (dirname, elt);
01914 
01915                   file_stat fs (nm);
01916 
01917                   if (fs && fs.is_dir ())
01918                     retval += dir_path::path_sep_str () + genpath (nm, skip);
01919                 }
01920             }
01921         }
01922     }
01923 
01924   return retval;
01925 }
01926 
01927 static void
01928 execute_pkg_add_or_del (const std::string& dir,
01929                         const std::string& script_file)
01930 {
01931   if (! octave_interpreter_ready)
01932     return;
01933 
01934   unwind_protect frame;
01935 
01936   frame.protect_var (input_from_startup_file);
01937 
01938   input_from_startup_file = true;
01939 
01940   std::string file = file_ops::concat (dir, script_file);
01941 
01942   file_stat fs (file);
01943 
01944   if (fs.exists ())
01945     source_file (file, "base");
01946 }
01947 
01948 void
01949 execute_pkg_add (const std::string& dir)
01950 {
01951   execute_pkg_add_or_del (dir, "PKG_ADD");
01952 }
01953 
01954 void
01955 execute_pkg_del (const std::string& dir)
01956 {
01957   execute_pkg_add_or_del (dir, "PKG_DEL");
01958 }
01959 
01960 DEFUN (genpath, args, ,
01961   "-*- texinfo -*-\n\
01962 @deftypefn  {Built-in Function} {} genpath (@var{dir})\n\
01963 @deftypefnx {Built-in Function} {} genpath (@var{dir}, @var{skip}, @dots{})\n\
01964 Return a path constructed from @var{dir} and all its subdirectories.\n\
01965 If additional string parameters are given, the resulting path will\n\
01966 exclude directories with those names.\n\
01967 @end deftypefn")
01968 {
01969   octave_value retval;
01970 
01971   octave_idx_type nargin = args.length ();
01972 
01973   if (nargin == 1)
01974     {
01975       std::string dirname = args(0).string_value ();
01976 
01977       if (! error_state)
01978         retval = genpath (dirname);
01979       else
01980         error ("genpath: DIR must be a character string");
01981     }
01982   else if (nargin > 1)
01983     {
01984       std::string dirname = args(0).string_value ();
01985 
01986       string_vector skip (nargin - 1);
01987 
01988       for (octave_idx_type i = 1; i < nargin; i++)
01989         {
01990           skip[i-1] = args(i).string_value ();
01991 
01992           if (error_state)
01993             break;
01994         }
01995 
01996       if (! error_state)
01997         retval = genpath (dirname, skip);
01998       else
01999         error ("genpath: all arguments must be character strings");
02000     }
02001   else
02002     print_usage ();
02003 
02004   return retval;
02005 }
02006 
02007 static void
02008 rehash_internal (void)
02009 {
02010   load_path::update ();
02011 
02012   // FIXME -- maybe we should rename this variable since it is being
02013   // used for more than keeping track of the prompt time.
02014 
02015   // This will force updated functions to be found.
02016   Vlast_prompt_time.stamp ();
02017 }
02018 
02019 DEFUN (rehash, , ,
02020   "-*- texinfo -*-\n\
02021 @deftypefn {Built-in Function} {} rehash ()\n\
02022 Reinitialize Octave's load path directory cache.\n\
02023 @end deftypefn")
02024 {
02025   octave_value_list retval;
02026 
02027   rehash_internal ();
02028 
02029   return retval;
02030 }
02031 
02032 DEFUN (command_line_path, , ,
02033     "-*- texinfo -*-\n\
02034 @deftypefn {Built-in Function} {} command_line_path (@dots{})\n\
02035 Return the command line path variable.\n\
02036 \n\
02037 @seealso{path, addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
02038 @end deftypefn")
02039 {
02040   return octave_value (load_path::get_command_line_path ());
02041 }
02042 
02043 DEFUN (restoredefaultpath, , ,
02044     "-*- texinfo -*-\n\
02045 @deftypefn {Built-in Function} {} restoredefaultpath (@dots{})\n\
02046 Restore Octave's path to its initial state at startup.\n\
02047 \n\
02048 @seealso{path, addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
02049 @end deftypefn")
02050 {
02051   load_path::initialize (true);
02052 
02053   return octave_value (load_path::system_path ());
02054 }
02055 
02056 // Return Octave's original default list of directories in which to
02057 // search for function files.  This corresponds to the path that
02058 // exists prior to running the system's octaverc file or the user's
02059 // ~/.octaverc file
02060 
02061 DEFUN (__pathorig__, , ,
02062   "-*- texinfo -*-\n\
02063 @deftypefn {Built-in Function} {@var{val} =} __pathorig__ ()\n\
02064 Undocumented internal function.\n\
02065 @end deftypefn")
02066 {
02067   return octave_value (load_path::system_path ());
02068 }
02069 
02070 DEFUN (path, args, nargout,
02071     "-*- texinfo -*-\n\
02072 @deftypefn {Built-in Function} {} path (@dots{})\n\
02073 Modify or display Octave's load path.\n\
02074 \n\
02075 If @var{nargin} and @var{nargout} are zero, display the elements of\n\
02076 Octave's load path in an easy to read format.\n\
02077 \n\
02078 If @var{nargin} is zero and nargout is greater than zero, return the\n\
02079 current load path.\n\
02080 \n\
02081 If @var{nargin} is greater than zero, concatenate the arguments,\n\
02082 separating them with @code{pathsep}.  Set the internal search path\n\
02083 to the result and return it.\n\
02084 \n\
02085 No checks are made for duplicate elements.\n\
02086 @seealso{addpath, rmpath, genpath, pathdef, savepath, pathsep}\n\
02087 @end deftypefn")
02088 {
02089   octave_value retval;
02090 
02091   int argc = args.length () + 1;
02092 
02093   string_vector argv = args.make_argv ("path");
02094 
02095   if (! error_state)
02096     {
02097       if (argc > 1)
02098         {
02099           std::string path = argv[1];
02100 
02101           for (int i = 2; i < argc; i++)
02102             path += dir_path::path_sep_str () + argv[i];
02103 
02104           load_path::set (path, true);
02105 
02106           rehash_internal ();
02107         }
02108 
02109       if (nargout > 0)
02110         retval = load_path::path ();
02111       else if (argc == 1 && nargout == 0)
02112         {
02113           octave_stdout << "\nOctave's search path contains the following directories:\n\n";
02114 
02115           string_vector dirs = load_path::dirs ();
02116 
02117           dirs.list_in_columns (octave_stdout);
02118 
02119           octave_stdout << "\n";
02120         }
02121     }
02122 
02123   return retval;
02124 }
02125 
02126 DEFUN (addpath, args, nargout,
02127   "-*- texinfo -*-\n\
02128 @deftypefn  {Built-in Function} {} addpath (@var{dir1}, @dots{})\n\
02129 @deftypefnx {Built-in Function} {} addpath (@var{dir1}, @dots{}, @var{option})\n\
02130 Add @var{dir1}, @dots{} to the current function search path.  If\n\
02131 @var{option} is \"-begin\" or 0 (the default), prepend the\n\
02132 directory name to the current path.  If @var{option} is \"-end\"\n\
02133 or 1, append the directory name to the current path.\n\
02134 Directories added to the path must exist.\n\
02135 \n\
02136 In addition to accepting individual directory arguments, lists of\n\
02137 directory names separated by @code{pathsep} are also accepted.  For example:\n\
02138 \n\
02139 @example\n\
02140 addpath (\"dir1:/dir2:~/dir3\");\n\
02141 @end example\n\
02142 @seealso{path, rmpath, genpath, pathdef, savepath, pathsep}\n\
02143 @end deftypefn")
02144 {
02145   octave_value retval;
02146 
02147   // Originally written by Bill Denney and Etienne Grossman.  Heavily
02148   // modified and translated to C++ by jwe.
02149 
02150   if (nargout > 0)
02151     retval = load_path::path ();
02152 
02153   int nargin = args.length ();
02154 
02155   if (nargin > 0)
02156     {
02157       bool append = false;
02158 
02159       octave_value option_arg = args(nargin-1);
02160 
02161       if (option_arg.is_string ())
02162         {
02163           std::string option = option_arg.string_value ();
02164 
02165           if (option == "-end")
02166             {
02167               append = true;
02168               nargin--;
02169             }
02170           else if (option == "-begin")
02171             nargin--;
02172         }
02173       else if (option_arg.is_numeric_type ())
02174         {
02175           int val = option_arg.int_value ();
02176 
02177           if (! error_state)
02178             {
02179               if (val == 0)
02180                 nargin--;
02181               else if (val == 1)
02182                 {
02183                   append = true;
02184                   nargin--;
02185                 }
02186               else
02187                 {
02188                   error ("addpath: expecting final argument to be 1 or 0");
02189                   return retval;
02190                 }
02191             }
02192           else
02193             {
02194               error ("addpath: expecting final argument to be 1 or 0");
02195               return retval;
02196             }
02197         }
02198 
02199       bool need_to_update = false;
02200 
02201       for (int i = 0; i < nargin; i++)
02202         {
02203           std::string arg = args(i).string_value ();
02204 
02205           if (! error_state)
02206             {
02207               std::list<std::string> dir_elts = split_path (arg);
02208 
02209               if (! append)
02210                 std::reverse (dir_elts.begin (), dir_elts.end ());
02211 
02212               for (std::list<std::string>::const_iterator p = dir_elts.begin ();
02213                    p != dir_elts.end ();
02214                    p++)
02215                 {
02216                   std::string dir = *p;
02217 
02218                   //dir = regexprep (dir_elts{j}, '//+', "/");
02219                   //dir = regexprep (dir, '/$', "");
02220 
02221                   if (append)
02222                     load_path::append (dir, true);
02223                   else
02224                     load_path::prepend (dir, true);
02225 
02226                   need_to_update = true;
02227                 }
02228             }
02229           else
02230             error ("addpath: all arguments must be character strings");
02231         }
02232 
02233       if (need_to_update)
02234         rehash_internal ();
02235     }
02236   else
02237     print_usage ();
02238 
02239   return retval;
02240 }
02241 
02242 DEFUN (rmpath, args, nargout,
02243   "-*- texinfo -*-\n\
02244 @deftypefn {Built-in Function} {} rmpath (@var{dir1}, @dots{})\n\
02245 Remove @var{dir1}, @dots{} from the current function search path.\n\
02246 \n\
02247 In addition to accepting individual directory arguments, lists of\n\
02248 directory names separated by @code{pathsep} are also accepted.  For example:\n\
02249 \n\
02250 @example\n\
02251 rmpath (\"dir1:/dir2:~/dir3\");\n\
02252 @end example\n\
02253 @seealso{path, addpath, genpath, pathdef, savepath, pathsep}\n\
02254 @end deftypefn")
02255 {
02256   // Originally by Etienne Grossmann. Heavily modified and translated
02257   // to C++ by jwe.
02258 
02259   octave_value retval;
02260 
02261   if (nargout > 0)
02262     retval = load_path::path ();
02263 
02264   int nargin = args.length ();
02265 
02266   if (nargin > 0)
02267     {
02268       bool need_to_update = false;
02269 
02270       for (int i = 0; i < nargin; i++)
02271         {
02272           std::string arg = args(i).string_value ();
02273 
02274           if (! error_state)
02275             {
02276               std::list<std::string> dir_elts = split_path (arg);
02277 
02278               for (std::list<std::string>::const_iterator p = dir_elts.begin ();
02279                    p != dir_elts.end ();
02280                    p++)
02281                 {
02282                   std::string dir = *p;
02283 
02284                   //dir = regexprep (dir_elts{j}, '//+', "/");
02285                   //dir = regexprep (dir, '/$', "");
02286 
02287                   if (! load_path::remove (dir))
02288                     warning ("rmpath: %s: not found", dir.c_str ());
02289                   else
02290                     need_to_update = true;
02291                 }
02292             }
02293           else
02294             error ("addpath: all arguments must be character strings");
02295         }
02296 
02297       if (need_to_update)
02298         rehash_internal ();
02299     }
02300   else
02301     print_usage ();
02302 
02303   return retval;
02304 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines