diff src/load-path.cc @ 7336:745a8299c2b5

[project @ 2007-12-28 20:56:55 by jwe]
author jwe
date Fri, 28 Dec 2007 20:56:58 +0000
parents 05ee52d7fad6
children 4ff9611147ba
line wrap: on
line diff
--- a/src/load-path.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/load-path.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -43,8 +43,8 @@
 #include "utils.h"
 
 load_path *load_path::instance = 0;
-load_path::hook_function_ptr load_path::add_hook = execute_pkg_add;
-load_path::hook_function_ptr load_path::remove_hook = execute_pkg_del;
+load_path::hook_fcn_ptr load_path::add_hook = execute_pkg_add;
+load_path::hook_fcn_ptr load_path::remove_hook = execute_pkg_del;
 std::string load_path::command_line_path;
 std::string load_path::sys_path;
 
@@ -81,17 +81,7 @@
     {
       dir_mtime = fs.mtime ();
 
-      bool has_private_subdir = get_file_list (dir_name);
-
-      if (! error_state)
-	{
-	  if (has_private_subdir)
-	    {
-	      std::string pdn = file_ops::concat (dir_name, "private");
-
-	      get_private_function_map (pdn);
-	    }
-	}
+      get_file_list (dir_name);
     }
   else
     {
@@ -100,11 +90,9 @@
     }
 }
 
-bool
+void
 load_path::dir_info::get_file_list (const std::string& d)
 {
-  bool has_private_subdir = false;
-
   dir_entry dir (d);
 
   if (dir)
@@ -131,8 +119,10 @@
 	    {
 	      if (fs.is_dir ())
 		{
-		  if (! has_private_subdir && fname == "private")
-		    has_private_subdir = true;
+		  if (fname == "private")
+		    get_private_file_map (full_name);
+		  else if (fname[0] == '@')
+		    get_method_file_map (full_name, fname.substr (1));
 		}
 	      else
 		{
@@ -164,13 +154,13 @@
       std::string msg = dir.error ();
       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
     }
-
-  return has_private_subdir;
 }
 
-void
-load_path::dir_info::get_private_function_map (const std::string& d)
+load_path::dir_info::fcn_file_map_type
+get_fcn_files (const std::string& d)
 {
+  load_path::dir_info::fcn_file_map_type retval;
+
   dir_entry dir (d);
 
   if (dir)
@@ -204,7 +194,7 @@
 		  else if (ext == ".mex")
 		    t = load_path::MEX_FILE;
 
-		  private_function_map[base] |= t;
+		  retval[base] |= t;
 		}
 	    }
 	}
@@ -214,6 +204,21 @@
       std::string msg = dir.error ();
       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
     }
+
+  return retval;
+}
+
+void
+load_path::dir_info::get_private_file_map (const std::string& d)
+{
+  private_file_map = get_fcn_files (d);
+}
+
+void
+load_path::dir_info::get_method_file_map (const std::string& d,
+					  const std::string& class_name)
+{
+  method_file_map[class_name] = get_fcn_files (d);
 }
 
 bool
@@ -234,6 +239,9 @@
   return retval;
 }
 
+// FIXME -- maybe we should also maintain a map to speed up this
+// method of access.
+
 load_path::const_dir_info_list_iterator
 load_path::find_dir_info (const std::string& dir_arg) const
 {
@@ -277,51 +285,81 @@
 }
 
 void
-load_path::move (dir_info_list_iterator i, bool at_end)
+load_path::move_fcn_map (const std::string& dir_name,
+			 const string_vector& fcn_files, bool at_end)
 {
-  if (dir_info_list.size () > 1)
+  octave_idx_type len = fcn_files.length ();
+
+  for (octave_idx_type k = 0; k < len; k++)
     {
-      dir_info di = *i;
-
-      dir_info_list.erase (i);
+      std::string fname = fcn_files[k];
 
-      if (at_end)
-	dir_info_list.push_back (di);
-      else
-	dir_info_list.push_front (di);
+      std::string ext;
+      std::string base = fname;
+
+      size_t pos = fname.rfind ('.');
 
-      std::string dir = di.dir_name;
+      if (pos != NPOS)
+	{
+	  base = fname.substr (0, pos);
+	  ext = fname.substr (pos);
+	}
 
-      string_vector fcn_files = di.fcn_files;
+      file_info_list_type& file_info_list = fcn_map[base];
 
-      octave_idx_type len = fcn_files.length ();
-
-      for (octave_idx_type k = 0; k < len; k++)
+      if (file_info_list.size () == 1)
+	continue;
+      else
 	{
-	  std::string fname = fcn_files[k];
+	  for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+	    {
+	      if (p->dir_name == dir_name)
+		{
+		  file_info fi = *p;
 
-	  std::string ext;
-	  std::string base = fname;
+		  file_info_list.erase (p);
+
+		  if (at_end)
+		    file_info_list.push_back (fi);
+		  else
+		    file_info_list.push_front (fi);
 
-	  size_t pos = fname.rfind ('.');
+		  break;
+		}
+	    }
+	}
+    }
+}
 
-	  if (pos != NPOS)
-	    {
-	      base = fname.substr (0, pos);
-	      ext = fname.substr (pos);
-	    }
+void
+load_path::move_method_map (const std::string& dir_name, bool at_end)
+{
+  for (method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      std::string class_name = i->first;
 
-	  std::list<file_info>& file_info_list = fcn_map[base];
+      fcn_map_type& fm = i->second;
+
+      std::string full_dir_name
+	= file_ops::concat (dir_name, "@" + class_name);
+
+      for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
+	{
+	  file_info_list_type& file_info_list = q->second;
 
 	  if (file_info_list.size () == 1)
 	    continue;
 	  else
 	    {
-	      for (std::list<file_info>::iterator p = file_info_list.begin ();
-		   p != file_info_list.end ();
-		   p++)
+	      for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
 		{
-		  if (p->dir_name == dir)
+		  if (p->dir_name == full_dir_name)
 		    {
 		      file_info fi = *p;
 
@@ -340,6 +378,30 @@
     }
 }
 
+void
+load_path::move (dir_info_list_iterator i, bool at_end)
+{
+  if (dir_info_list.size () > 1)
+    {
+      dir_info di = *i;
+
+      dir_info_list.erase (i);
+
+      if (at_end)
+	dir_info_list.push_back (di);
+      else
+	dir_info_list.push_front (di);
+
+      std::string dir_name = di.dir_name;
+
+      move_fcn_map (dir_name, di.fcn_files, at_end);
+
+      // No need to move elements of private function map.
+
+      move_method_map (dir_name, at_end);
+    }
+}
+
 static void
 maybe_add_path_elts (std::string& path, const std::string& dir)
 {
@@ -387,6 +449,8 @@
 {
   dir_info_list.clear ();
   fcn_map.clear ();
+  private_fcn_map.clear ();
+  method_map.clear ();
 
   do_append (".", false);
 }
@@ -503,6 +567,10 @@
 
 		  add_to_fcn_map (di, true);
 
+		  add_to_private_fcn_map (di);
+
+		  add_to_method_map (di, true);
+
 		  if (add_hook)
 		    add_hook (dir);
 		}
@@ -527,6 +595,96 @@
     panic_impossible ();
 }
 
+void
+load_path::remove_fcn_map (const std::string& dir,
+			   const string_vector& fcn_files)
+{
+  octave_idx_type len = fcn_files.length ();
+
+  for (octave_idx_type k = 0; k < len; k++)
+    {
+      std::string fname = fcn_files[k];
+
+      std::string ext;
+      std::string base = fname;
+
+      size_t pos = fname.rfind ('.');
+
+      if (pos != NPOS)
+	{
+	  base = fname.substr (0, pos);
+	  ext = fname.substr (pos);
+	}
+
+      file_info_list_type& file_info_list = fcn_map[base];
+
+      for (file_info_list_iterator p = file_info_list.begin ();
+	   p != file_info_list.end ();
+	   p++)
+	{
+	  if (p->dir_name == dir)
+	    {
+	      file_info_list.erase (p);
+
+	      if (file_info_list.empty ())
+		fcn_map.erase (fname);
+
+	      break;
+	    }
+	}
+    }
+}
+
+void
+load_path::remove_private_fcn_map (const std::string& dir)
+{
+  private_fcn_map_iterator p = private_fcn_map.find (dir);
+
+  if (p != private_fcn_map.end ())
+    private_fcn_map.erase (p);
+}
+
+void
+load_path::remove_method_map (const std::string& dir)
+{
+  for (method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      std::string class_name = i->first;
+
+      fcn_map_type& fm = i->second;
+
+      std::string full_dir_name = file_ops::concat (dir, "@" + class_name);
+
+      for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
+	{
+	  file_info_list_type& file_info_list = q->second;
+
+	  if (file_info_list.size () == 1)
+	    continue;
+	  else
+	    {
+	      for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+		{
+		  if (p->dir_name == full_dir_name)
+		    {
+		      file_info_list.erase (p);
+
+		      // FIXME -- if there are no other elements, we
+		      // should remove this element of fm but calling
+		      // erase here would invalidate the iterator q.
+
+		      break;
+		    }
+		}
+	    }
+	}
+    }
+}
+
 bool
 load_path::do_remove (const std::string& dir_arg)
 {
@@ -558,40 +716,11 @@
 
 	      dir_info_list.erase (i);
 
-	      octave_idx_type len = fcn_files.length ();
-
-	      for (octave_idx_type k = 0; k < len; k++)
-		{
-		  std::string fname = fcn_files[k];
-
-		  std::string ext;
-		  std::string base = fname;
-
-		  size_t pos = fname.rfind ('.');
-
-		  if (pos != NPOS)
-		    {
-		      base = fname.substr (0, pos);
-		      ext = fname.substr (pos);
-		    }
+	      remove_fcn_map (dir, fcn_files);
 
-		  std::list<file_info>& file_info_list = fcn_map[base];
+	      remove_private_fcn_map (dir);
 
-		  for (std::list<file_info>::iterator p = file_info_list.begin ();
-		       p != file_info_list.end ();
-		       p++)
-		    {
-		      if (p->dir_name == dir)
-			{
-			  file_info_list.erase (p);
-
-			  if (file_info_list.empty ())
-			    fcn_map.erase (fname);
-
-			  break;
-			}
-		    }
-		}
+	      remove_method_map (dir);
 	    }
 	}
     }
@@ -608,6 +737,10 @@
 
   fcn_map.clear ();
 
+  private_fcn_map.clear ();
+
+  method_map.clear ();
+
   for (dir_info_list_iterator p = dir_info_list.begin ();
        p != dir_info_list.end ();
        p++)
@@ -617,21 +750,122 @@
       di.update ();
 
       add_to_fcn_map (di, true);
+
+      add_to_private_fcn_map (di);
+
+      add_to_method_map (di, true);
     }
 }
 
+bool
+load_path::check_file_type (std::string& fname, int type, int possible_types,
+			    const std::string& fcn, const char *who)
+{
+  bool retval = false;
+
+  if (type == load_path::OCT_FILE)
+    {
+      if ((type & possible_types) == load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+    }
+  else if (type == load_path::M_FILE)
+    {
+      if ((type & possible_types) == load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == load_path::MEX_FILE)
+    {
+      if ((type & possible_types) == load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::OCT_FILE
+		    | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else
+    error ("%s: %s: invalid type code = %d", who, fcn.c_str (), type);
+
+  return retval;
+} 
+
 std::string
-load_path::do_find_fcn (const std::string& fcn, int type) const
+load_path::do_find_fcn (const std::string& fcn, std::string& dir_name,
+			int type) const
 {
   std::string retval;
+  
+  //  update ();
 
-  update ();
+  dir_name = std::string ();
 
   const_fcn_map_iterator p = fcn_map.find (fcn);
 
   if (p != fcn_map.end ())
     {
-      const std::list<file_info>& file_info_list = p->second;
+      const file_info_list_type& file_info_list = p->second;
 
       for (const_file_info_list_iterator i = file_info_list.begin ();
 	   i != file_info_list.end ();
@@ -639,104 +873,123 @@
 	{
 	  const file_info& fi = *i;
 
-	  int t = fi.types;
-
 	  retval = file_ops::concat (fi.dir_name, fcn);
 
-	  if (type == load_path::OCT_FILE)
+	  if (check_file_type (retval, type, fi.types,
+			       fcn, "load_path::do_find_fcn"))
 	    {
-	      if ((type & t) == load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	    }
-	  else if (type == load_path::M_FILE)
-	    {
-	      if ((type & t) == load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
+	      dir_name = fi.dir_name;
+	      break;
 	    }
-	  else if (type == load_path::MEX_FILE)
+	  else
+	    retval = std::string ();
+	}
+    }
+
+  return retval;
+}
+
+std::string
+load_path::do_find_private_fcn (const std::string& dir,
+				const std::string& fcn, int type) const
+{
+  std::string retval;
+
+  //  update ();
+
+  const_private_fcn_map_iterator q = private_fcn_map.find (dir);
+
+  if (q != private_fcn_map.end ())
+    {
+      const dir_info::fcn_file_map_type& m = q->second;
+
+      dir_info::const_fcn_file_map_iterator p = m.find (fcn);
+
+      if (p != m.end ())
+	{
+	  std::string fname
+	    = file_ops::concat (file_ops::concat (dir, "private"), fcn);
+
+	  if (check_file_type (fname, type, p->second, fcn,
+			       "load_path::find_private_fcn"))
+	    retval = fname;
+	}
+    }
+
+  return retval;
+}
+
+std::string
+load_path::do_find_method (const std::string& class_name,
+			   const std::string& meth,
+			   std::string& dir_name, int type) const
+{
+  std::string retval;
+
+  //  update ();
+
+  dir_name = std::string ();
+
+  const_method_map_iterator q = method_map.find (class_name);
+
+  if (q != method_map.end ())
+    {
+      const fcn_map_type& m = q->second;
+
+      const_fcn_map_iterator p = m.find (meth);
+
+      if (p != m.end ())
+	{
+	  const file_info_list_type& file_info_list = p->second;
+
+	  for (const_file_info_list_iterator i = file_info_list.begin ();
+	       i != file_info_list.end ();
+	       i++)
 	    {
-	      if ((type & t) == load_path::MEX_FILE)
+	      const file_info& fi = *i;
+
+	      retval = file_ops::concat (fi.dir_name, meth);
+
+	      bool found = check_file_type (retval, type, fi.types,
+					    meth, "load_path::do_find_method");
+
+	      if (found)
 		{
-		  retval += ".mex";
-		  break;
-		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
+		  dir_name = fi.dir_name;
 		  break;
 		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
+	      else
+		retval = std::string ();
 	    }
-	  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::OCT_FILE
-			    | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
-	    }
-	  else
-	    error ("load_path::do_find_fcn: %s: invalid type code = %d",
-		   fcn.c_str (), type);
- 
- 	  // Reset the return string, in case the above tesst fail.
- 	  retval = std::string ();
 	}
     }
 
   return retval;
 }
 
+std::list<std::string>
+load_path::do_methods (const std::string& class_name) const
+{
+  std::list<std::string> retval;
+
+  //  update ();
+
+  const_method_map_iterator q = method_map.find (class_name);
+
+  if (q != method_map.end ())
+    {
+      const fcn_map_type& m = q->second;
+
+      for (const_fcn_map_iterator p = m.begin (); p != m.end (); p++)
+	retval.push_back (p->first);
+    }
+
+  if (! retval.empty ())
+    retval.sort ();
+
+  return retval;
+}
+
 std::string
 load_path::do_find_file (const std::string& file) const
 {
@@ -987,6 +1240,80 @@
 }
 
 void
+print_types (std::ostream& os, int types)
+{
+  bool printed_type = false;
+
+  if (types & load_path::OCT_FILE)
+    {
+      os << "oct";
+      printed_type = true;
+    }
+
+  if (types & load_path::MEX_FILE)
+    {
+      if (printed_type)
+	os << "|";
+      os << "mex";
+      printed_type = true;
+    }
+
+  if (types & load_path::M_FILE)
+    {
+      if (printed_type)
+	os << "|";
+      os << "m";
+      printed_type = true;
+    }
+}
+
+void
+print_fcn_list (std::ostream& os,
+		const load_path::dir_info::fcn_file_map_type& lst)
+{
+  for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
+       p != lst.end ();
+       p++)
+    {
+      os << "  " << p->first << " (";
+
+      print_types (os, p->second);
+
+      os << ")\n";
+    }
+}
+
+string_vector
+get_file_list (const load_path::dir_info::fcn_file_map_type& lst)
+{
+  octave_idx_type n = lst.size ();
+
+  string_vector retval (n);
+
+  octave_idx_type count = 0;
+
+  for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
+       p != lst.end ();
+       p++)
+    {
+      std::string nm = p->first;
+
+      int types = p->second;
+
+      if (types & load_path::OCT_FILE)
+	nm += ".oct";
+      else if (types & load_path::MEX_FILE)
+	nm += ".mex";
+      else
+	nm += ".m";
+
+      retval[count++] = nm;
+    }
+
+  return retval;
+}
+
+void
 load_path::do_display (std::ostream& os) const
 {
   for (const_dir_info_list_iterator i = dir_info_list.begin ();
@@ -1002,53 +1329,32 @@
 	  fcn_files.list_in_columns (os);
 	}
 
-#if defined (DEBUG_LOAD_PATH)
-
-      const std::map<std::string, int>& private_function_map
-	= i->private_function_map;
+      const dir_info::method_file_map_type& method_file_map
+	= i->method_file_map;
 
-      if (private_function_map.size () > 0)
+      if (! method_file_map.empty ())
 	{
-	  os << "private:\n";
-
-	  for (std::map<std::string, int>::const_iterator p = private_function_map.begin ();
-	       p != private_function_map.end ();
+	  for (dir_info::const_method_file_map_iterator p = method_file_map.begin ();
+	       p != method_file_map.end ();
 	       p++)
 	    {
-	      os << "  " << p->first << " (";
-
-	      bool printed_type = false;
-
-	      int types = p->second;
+	      os << "\n*** methods in " << i->dir_name
+		 << "/@" << p->first << ":\n\n";
 
-	      if (types & load_path::OCT_FILE)
-		{
-		  os << "oct";
-		  printed_type = true;
-		}
+	      string_vector method_files = get_file_list (p->second);
 
-	      if (types & load_path::MEX_FILE)
-		{
-		  if (printed_type)
-		    os << "|";
-		  os << "mex";
-		  printed_type = true;
-		}
+	      method_files.list_in_columns (os);
+	    }
+	}
+    }
 
-	      if (types & load_path::M_FILE)
-		{
-		  if (printed_type)
-		    os << "|";
-		  os << "m";
-		  printed_type = true;
-		}
+  for (const_private_fcn_map_iterator i = private_fcn_map.begin ();
+       i != private_fcn_map.end (); i++)
+    {
+      os << "\n*** private functions in "
+	 << file_ops::concat (i->first, "private") << ":\n\n";
 
-	      os << ")\n";
-	    }
-
-	  os << "\n";
-	}
-#endif
+      print_fcn_list (os, i->second);
     }
 
 #if defined (DEBUG_LOAD_PATH)
@@ -1059,7 +1365,7 @@
     {
       os << i->first << ":\n";
 
-      const std::list<file_info>& file_info_list = i->second;
+      const file_info_list_type& file_info_list = i->second;
 
       for (const_file_info_list_iterator p = file_info_list.begin ();
 	   p != file_info_list.end ();
@@ -1067,34 +1373,41 @@
 	{
 	  os << "  " << p->dir_name << " (";
 
-	  bool printed_type = false;
-
-	  if (p->types & load_path::OCT_FILE)
-	    {
-	      os << "oct";
-	      printed_type = true;
-	    }
-
-	  if (p->types & load_path::MEX_FILE)
-	    {
-	      if (printed_type)
-		os << "|";
-	      os << "mex";
-	      printed_type = true;
-	    }
-
-	  if (p->types & load_path::M_FILE)
-	    {
-	      if (printed_type)
-		os << "|";
-	      os << "m";
-	      printed_type = true;
-	    }
+	  print_types (os, p->types);
 
 	  os << ")\n";
 	}
     }
 
+  for (const_method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      os << "CLASS " << i->first << ":\n";
+
+      const fcn_map_type& fm = i->second;
+
+      for (const_fcn_map_iterator q = fm.begin ();
+	   q != fm.end ();
+	   q++)
+	{
+	  os << "  " << q->first << ":\n";
+
+	  const file_info_list_type& file_info_list = q->second;
+
+	  for (const_file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+	    {
+	      os << "  " << p->dir_name << " (";
+
+	      print_types (os, p->types);
+
+	      os << ")\n";
+	    }
+	}
+    }
+
   os << "\n";
 
 #endif
@@ -1124,7 +1437,7 @@
 	  ext = fname.substr (pos);
 	}
 
-      std::list<file_info>& file_info_list = fcn_map[base];
+      file_info_list_type& file_info_list = fcn_map[base];
 
       file_info_list_iterator p = file_info_list.begin ();
 
@@ -1162,6 +1475,78 @@
     }
 }
 
+void
+load_path::add_to_private_fcn_map (const dir_info& di) const
+{
+  dir_info::fcn_file_map_type private_file_map = di.private_file_map;
+
+  if (! private_file_map.empty ())
+    private_fcn_map[di.dir_name] = private_file_map;
+}
+
+void
+load_path::add_to_method_map (const dir_info& di, bool at_end) const
+{
+  std::string dir_name = di.dir_name;
+
+  // <CLASS_NAME, <FCN_NAME, TYPES>>
+  dir_info::method_file_map_type method_file_map = di.method_file_map;
+
+  for (dir_info::const_method_file_map_iterator q = method_file_map.begin ();
+       q != method_file_map.end ();
+       q++)
+    {
+      std::string class_name = q->first;
+
+      fcn_map_type& fm = method_map[class_name];
+
+      std::string full_dir_name
+	= file_ops::concat (dir_name, "@" + class_name);
+
+      // <FCN_NAME, TYPES>
+      const dir_info::fcn_file_map_type& m = q->second;
+
+      for (dir_info::const_fcn_file_map_iterator p = m.begin ();
+	   p != m.end ();
+	   p++)
+	{
+	  std::string base = p->first;
+
+	  int types = p->second;
+
+	  file_info_list_type& file_info_list = fm[base];
+
+	  file_info_list_iterator p2 = file_info_list.begin ();
+
+	  while (p2 != file_info_list.end ())
+	    {
+	      if (p2->dir_name == full_dir_name)
+		break;
+
+	      p2++;
+	    }
+
+	  if (p2 == file_info_list.end ())
+	    {
+	      file_info fi (full_dir_name, types);
+
+	      if (at_end)
+		file_info_list.push_back (fi);
+	      else
+		file_info_list.push_front (fi);
+	    }
+	  else
+	    {
+	      // FIXME -- is this possible?
+
+	      file_info& fi = *p2;
+
+	      fi.types = types;
+	    }
+	}
+    }
+}
+
 std::string
 genpath (const std::string& dirname, const string_vector& skip)
 {
@@ -1182,9 +1567,10 @@
 	  std::string elt = dirlist[i];
 
 	  // FIXME -- the caller should be able to specify the list of
-	  // directories to skip in addition to "." and "..".
+	  // directories to skip in addition to ".", "..", and
+	  // directories beginning with "@".
 
-	  bool skip_p = (elt == "." || elt == "..");
+	  bool skip_p = (elt == "." || elt == ".." || elt[0] == '@');
 
 	  if (! skip_p)
 	    {