00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00072
00073
00074
00075
00076
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
00088
00089 initialize ();
00090 }
00091 }
00092 catch (octave_execution_exception)
00093 {
00094
00095
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
00133
00134
00135
00136 abs_dir_cache[abs_name] = *this;
00137 }
00138 catch (octave_execution_exception)
00139 {
00140
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
00312
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
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
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
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
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
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
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
00774
00775
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
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
00834
00835
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
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
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
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
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
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
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
01762
01763 if (! file_info_list.empty ())
01764 {
01765 file_info& old = file_info_list.front ();
01766
01767
01768
01769
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
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
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
01866
01867 file_info& fi = *p2;
01868
01869 fi.types = types;
01870 }
01871 }
01872
01873
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
02013
02014
02015
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
02057
02058
02059
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
02148
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
02219
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
02257
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
02285
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 }