diff -Nur viewcvs.orig/cgi/viewcvs.conf.dist viewcvs/cgi/viewcvs.conf.dist
--- viewcvs.orig/cgi/viewcvs.conf.dist	2002-12-12 01:02:51.000000000 -0100
+++ viewcvs/cgi/viewcvs.conf.dist	2003-05-21 23:56:38.000000000 -0100
@@ -28,6 +28,7 @@
 #
 #    use_enscript
 #    use_cvsgraph
+#    use_metacvs
 #
 # For Python source colorization:
 #
@@ -443,6 +444,11 @@
 cvsgraph_conf = <VIEWCVS_INSTALL_DIRECTORY>/cvsgraph.conf
 
 #
+# Use Meta-CVS. More info on http://users.footprints.net/~kaz/mcvs.html
+#
+use_metacvs = 1
+
+#
 # Set to enable regular expression search of all files in a directory
 #
 # WARNING:
diff -Nur viewcvs.orig/lib/config.py viewcvs/lib/config.py
--- viewcvs.orig/lib/config.py	2003-03-11 19:43:06.000000000 -0100
+++ viewcvs/lib/config.py	2003-05-21 23:56:38.000000000 -0100
@@ -203,6 +203,7 @@
     self.options.use_re_search = 0
     self.options.use_pagesize = 0
     self.options.use_localtime = 0
+    self.options.use_metacvs = 0
 
   def is_forbidden(self, module):
     if not module:
diff -Nur viewcvs.orig/lib/viewcvs.py viewcvs/lib/viewcvs.py
--- viewcvs.orig/lib/viewcvs.py	2003-05-12 19:39:19.000000000 -0100
+++ viewcvs/lib/viewcvs.py	2003-05-22 00:02:43.000000000 -0100
@@ -442,6 +442,11 @@
   for i in range(len(parts)):
     where = where + '/' + parts[i]
     is_leaf = i == len(parts) - 1
+    if cfg.options.use_metacvs:
+      pathname = os.path.dirname(request.full_name)
+      realname = get_metacvs_name(pathname, parts[i])
+    else:
+      realname = parts[i]
     if not is_leaf or leaf_is_link:
       if is_leaf and leaf_is_file:
         slash = ''
@@ -449,9 +454,9 @@
         slash = '/'
       s = s + ' / <a href="%s%s%s%s#dirlist">%s</a>' % \
           (script_name, urllib.quote(where), slash,
-           request.qmark_query, parts[i])
+           request.qmark_query, realname)
     else:
-      s = s + ' / ' + parts[i]
+      s = s + ' / ' + realname
 
   return s
 
@@ -786,7 +791,11 @@
   file_url = urllib.quote(filename)
 
   data = nav_header_data(request, pathname, filename, revision)
+
+  realname = get_realname(request, pathname, filename)
+
   data.update({
+    'realname' : get_realname,
     'request' : request,
     'cfg' : cfg,
     'vsn' : __version__,
@@ -809,6 +818,7 @@
     entry.date_str = make_time_string(entry.date)
 
     data.update({
+      'realname' : realname,
       'date_str' : entry.date_str,
       'ago' : html_time(request, entry.date, 1),
       'author' : entry.author,
@@ -895,6 +905,7 @@
   data[0] = (relative) filename
   data[1] = full pathname
   data[2] = is_directory (0/1)
+  data[3] = real filename (iff using Meta-CVS repositories)
 
   Only RCS files (*,v) and subdirs are returned.
   """
@@ -920,6 +931,12 @@
     except os.error:
       data.append((file, _UNREADABLE_MARKER, None))
       continue
+    if cfg.options.use_metacvs:
+      realname = get_metacvs_name(full_name, file)
+    else:
+      realname = file
+      if realname[-2:] == ',v':
+        realname = realname[:-2]
     mode = info[stat.ST_MODE]
     isdir = stat.S_ISDIR(mode)
     isreg = stat.S_ISREG(mode)
@@ -959,9 +976,9 @@
         valid = 0
       
       if valid:
-        data.append((file, pathname, isdir))
+        data.append((file, pathname, isdir, realname))
       else:
-        data.append((file, _UNREADABLE_MARKER, isdir))
+        data.append((file, _UNREADABLE_MARKER, isdir, realname))
 
   return data
 
@@ -974,7 +991,7 @@
   """
 
   lastmod = { }
-  for file, pathname, isdir in file_data:
+  for file, pathname, isdir, realname in file_data:
     if not isdir or pathname == _UNREADABLE_MARKER:
       continue
     if file == 'Attic':
@@ -1075,8 +1092,9 @@
       return 1
 
     # the two files should be RCS files. drop the ",v" from the end.
-    file1 = data1[0]
-    file2 = data2[0]
+    # sort on the real filename
+    file1 = data1[3]
+    file2 = data2[3]
 
     # we should have data on these. if not, then it is because we requested
     # a specific tag and that tag is not present on the file.
@@ -1144,7 +1162,7 @@
 
   # get all the required info
   rcs_files = subfiles + attic_files
-  for file, pathname, isdir in file_data:
+  for file, pathname, isdir, realname in file_data:
     if not isdir and pathname != _UNREADABLE_MARKER:
       rcs_files.append(file)
   fileinfo, alltags = bincvs.get_logs(cfg.general.rcs_path, full_name,
@@ -1153,7 +1171,11 @@
   # append the Attic files into the file_data now
   # NOTE: we only insert the filename and isdir==0
   for file in attic_files:
-    file_data.append((file, None, 0))
+    if cfg.options.use_metacvs:
+      realname = get_metacvs_name(full_name, file[6:])
+    else:
+      realname = file
+    file_data.append((file, None, 0, realname))
 
   # prepare the data that will be passed to the template
   data = {
@@ -1232,7 +1254,7 @@
 
   rows = data['rows'] = [ ]
 
-  for file, pathname, isdir in file_data:
+  for file, pathname, isdir, realname in file_data:
 
     row = _item(href=None, graph_href=None,
                 author=None, log=None, log_file=None, log_rev=None,
@@ -1323,11 +1345,8 @@
       file_url = urllib.quote(file)
       url = file_url + request.qmark_query
 
-      if file[:6] == 'Attic/':
-        file = file[6:]
-
       row.cvs = 'data'
-      row.name = file	# ensure this occurs after we strip Attic/
+      row.name = realname	# ensure this occurs after we strip Attic/
       row.href = url
       row.rev = info.rev
       row.author = info.author
@@ -1472,7 +1491,7 @@
   unreadable = 0
   rows = data['rows'] = [ ]
 
-  for file, pathname, isdir in file_data:
+  for file, pathname, isdir, realname in file_data:
     row = _item(href=None, graph_href=None,
                 author=None, log=None, log_file=None, log_rev=None,
                 show_log=None, state=None)
@@ -1498,7 +1517,7 @@
         row.href = url
     else:
       row.type = 'file'
-      row.name = file
+      row.name = realname
       row.cvs = 'data' # What the heck is this?
       file_url = urllib.quote(file)
       url = file_url + request.qmark_query
@@ -1857,6 +1876,7 @@
   entries.reverse()
   
   data = {
+    'realname' : get_realname(request, pathname, filename),
     'roottype' : 'svn',
     'where' : where,
     'request' : request,
@@ -1933,7 +1953,7 @@
   ### whoops. this sometimes/always? does not have the ",v"
   assert full_name[-2:] != ',v', 'please report this error to viewcvs@lyra.org'
   #filename = os.path.basename(full_name[:-2])  # drop the ",v"
-  filename = os.path.basename(full_name)
+  pathname, filename = os.path.split(full_name)
 
   ### can we use filename rather than where? need to clarify the two vars
   file_url = urllib.quote(os.path.basename(where))
@@ -1943,6 +1963,7 @@
              request.qmark_query + '#' + filename
 
   data = {
+    'realname' : get_realname(request, pathname, filename),
     'roottype' : 'cvs',
     'where' : where,
     'request' : request,
@@ -2185,7 +2206,9 @@
     pathname = pathname[:-6]
 
   data = nav_header_data(request, pathname, filename, rev)
+
   data.update({
+    'realname' : get_realname(request, pathname, filename),
     'cfg' : cfg,
     'vsn' : __version__,
     'kv' : request.kv,
@@ -2239,6 +2262,7 @@
                     request.where + ',v'), 'rb', 0)
 
   data.update({
+    'realname' : get_realname(request, pathname, filename),
     'request' : request,
     'imagemap' : fp,
     'cfg' : cfg,
@@ -2249,6 +2273,20 @@
   request.server.header()
   generate_page(request, cfg.templates.graph, data)
 
+
+def get_realname(request, pathname, filename):
+  """ Retrieve the real name of a file.
+
+  This might parse the Meta-CVS MAP file if Meta-CVS support is enabled.
+  """
+  if cfg.options.use_metacvs:
+    dirname = os.path.dirname(request.full_name)
+    realname = pathname + '/' + get_metacvs_name(dirname, filename)
+  else:
+    realname = request.where
+  return realname
+
+
 def search_files(request, search_re):
   """ Search files in a directory for a regular expression.
 
@@ -2440,6 +2478,7 @@
     date2 = date2 + ' UTC'
 
   data.update({
+    'realname' : get_realname(request, pathname, filename),
     'cfg' : cfg,
     'vsn' : __version__,
     'kv' : request.kv,
@@ -2800,7 +2839,7 @@
 
   subdirs = [ ]
   rcs_files = [ ]
-  for file, pathname, isdir in get_file_data(rep_dir):
+  for file, pathname, isdir, realname in get_file_data(rep_dir):
     if pathname == _UNREADABLE_MARKER:
       continue
     if isdir:
@@ -2808,7 +2847,7 @@
     else:
       rcs_files.append(file)
   if tag and 'Attic' in subdirs:
-    for file, pathname, isdir in get_file_data(rep_dir + '/Attic'):
+    for file, pathname, isdir, realname in get_file_data(rep_dir + '/Attic'):
       if not isdir and pathname != _UNREADABLE_MARKER:
         rcs_files.append('Attic/' + file)
 
@@ -3053,6 +3092,62 @@
     debug.DumpChildren(server)
 
 
+_map_cache = []
+_pathname = ''
+def get_metacvs_name(pathname, filename):
+  global _map_cache
+  global _pathname
+
+  if pathname[-5:] == 'Attic':
+    pathname = pathname[:-5]
+  if filename[-2:] == ',v':
+    name = filename[:-2] # strip ,v from the filename
+  else:
+    name = filename
+
+  if _pathname != pathname:
+    p0 = re.compile( '^  "MCVS/.-[A-Z0-9]+.*"' )
+    p1 = re.compile( '^  "MCVS/' )
+    p2 = re.compile( '^  "' )
+    p3 = re.compile( '".*$|\r|\n' )
+    try:
+      map = open(pathname + '/MAP,v', 'r')
+      line = map.readline()
+      while line:
+        if p0.match(line):
+          line = p1.sub('', line)
+          line = p3.sub('', line)
+          _map_cache.append(line)
+
+          line = map.readline()
+          line = p2.sub('', line)
+          line = p3.sub('', line)
+          _map_cache.append(line)
+
+        line = map.readline()
+      _pathname = pathname
+      map.close()
+    except:
+      _pathname = 'error' # need to have at least some statement here
+
+  try:
+    try:
+      i = _map_cache.index( name )
+    except:
+      i = len(_map_cache) - 1
+      while i >= 0:
+        if name == _map_cache[i]:
+          break
+        i = i-1
+    if i == -1:
+      return name
+    else:
+      return _map_cache[i+1]
+  except:
+    return name
+
+
 class _item:
   def __init__(self, **kw):
     vars(self).update(kw)
+
diff -Nur viewcvs.orig/templates/diff.ezt viewcvs/templates/diff.ezt
--- viewcvs.orig/templates/diff.ezt	2002-10-09 03:04:01.000000000 -0100
+++ viewcvs/templates/diff.ezt	2003-05-21 23:56:38.000000000 -0100
@@ -1,6 +1,6 @@
 [include "header.ezt" "diff"]
 
-<h3 align=center>Diff for /[where] between version [rev1] and [rev2]</h3>
+<h3 align=center>Diff for /[realname] between version [rev1] and [rev2]</h3>
 <table border=0 cellspacing=0 cellpadding=0 width="100%">
   <tr bgcolor=white>
     <th width="50%" valign=top>
diff -Nur viewcvs.orig/templates/graph.ezt viewcvs/templates/graph.ezt
--- viewcvs.orig/templates/graph.ezt	2002-10-10 22:08:52.000000000 -0100
+++ viewcvs/templates/graph.ezt	2003-05-21 23:56:38.000000000 -0100
@@ -1,12 +1,12 @@
 [include "header.ezt" "graph"]
 
 <center>
-<h1>Revision graph of [request.where]</h1>
+<h1>Revision graph of [realname]</h1>
 
 [imagemap]
 <img border="0" usemap="#MyMapName"
   src="[request.url]?graph=[rev]&amp;makeimage=1[request.amp_query]" 
-  alt="Revisions of [request.where]">
+  alt="Revisions of [realname]">
 </center>
 
 [include "footer.ezt"]
diff -Nur viewcvs.orig/templates/header.ezt viewcvs/templates/header.ezt
--- viewcvs.orig/templates/header.ezt	2001-12-23 08:57:06.000000000 -0100
+++ viewcvs/templates/header.ezt	2003-05-21 23:56:38.000000000 -0100
@@ -13,7 +13,7 @@
         <img src="/icons/small/back.gif" alt="(file)" border=0 width=16 height=16>
       </a>
       <b>Return to
-        <a href="[file_url][qquery]#rev[rev]">[filename]</a>
+        <a href="[file_url][qquery]#rev[rev]">[realname]</a>
         CVS log</b>
       <img src="/icons/small/text.gif" alt="(file)" border=0 width=16 height=16>
     </td>
diff -Nur viewcvs.orig/templates/log.ezt viewcvs/templates/log.ezt
--- viewcvs.orig/templates/log.ezt	2003-05-12 19:39:20.000000000 -0100
+++ viewcvs/templates/log.ezt	2003-05-21 23:56:38.000000000 -0100
@@ -4,12 +4,12 @@
 <!-- ViewCVS       -- http://viewcvs.sourceforge.net/
      by Greg Stein -- mailto:gstein@lyra.org
   -->
-<title>[is roottype "svn"]Subversion[else]CVS[end] log for [where]</title>
+<title>[is roottype "svn"]Subversion[else]CVS[end] log for [realname]</title>
 </head>
 <body text="#000000" bgcolor="#ffffff">
 <table width="100%" border=0 cellspacing=0 cellpadding=0>
   <tr>
-    <td rowspan=2><h1>[is roottype "svn"]Subversion[else]CVS[end] log for [where]</h1></td>
+    <td rowspan=2><h1>[is roottype "svn"]Subversion[else]CVS[end] log for [realname]</h1></td>
     <td align=right><img src="/icons/apache_pb.gif" alt="(logo)" border=0
 			width=259 height=32></td>
   </tr>
diff -Nur viewcvs.orig/templates/log_table.ezt viewcvs/templates/log_table.ezt
--- viewcvs.orig/templates/log_table.ezt	2002-12-12 01:02:52.000000000 -0100
+++ viewcvs/templates/log_table.ezt	2003-05-21 23:56:38.000000000 -0100
@@ -4,12 +4,12 @@
 <!-- ViewCVS       -- http://viewcvs.sourceforge.net/
      by Greg Stein -- mailto:gstein@lyra.org
   -->
-<title>CVS log for [where]</title>
+<title>CVS log for [realname]</title>
 </head>
 <body text="#000000" bgcolor="#ffffff">
 <table width="100%" border=0 cellspacing=0 cellpadding=0>
   <tr>
-    <td rowspan=2><h1>CVS log for [where]</h1></td>
+    <td rowspan=2><h1>CVS log for [realname]</h1></td>
     <td align=right><img src="/icons/apache_pb.gif" alt="(logo)" border=0
 			width=259 height=32></td>
   </tr>
