Add GDB pretty-printing support for svn mergeinfo data types:
svn_merge_range_t, svn_mergeinfo_t.

### Relies on adding a typedef 'svn_rangelist_t' to the C code.

### The recursive printing of mergeinfo_catalog_t doesn't work properly: its
values are printed as plain apr_hash_t (that is, having unknown value type)
rather than as svn_mergeinfo_t.

* tools/dev/gdb-py/svndbg/printers.py
  (children_of_apr_array): New function.
  (SvnMergeRangePrinter, SvnRangelistPrinter, SvnMergeinfoPrinter): New
    pretty-printers.
  (SvnMergeinfoCatalogPrinter): Minor tweaks.
  (build_libsvn_printers): Add the new pretty-printers.
--This line, and those below, will be ignored--

Index: tools/dev/gdb-py/svndbg/printers.py
===================================================================
--- tools/dev/gdb-py/svndbg/printers.py	(revision 1364750)
+++ tools/dev/gdb-py/svndbg/printers.py	(working copy)
@@ -156,6 +156,14 @@ class AprArrayPrinter:
     def display_hint(self):
         return 'array'
 
+def children_of_apr_array(array, value_type):
+    """Iterate over an 'apr_array_header_t' GDB value, in the way required for
+       a pretty-printer 'children' method when the display-hint is 'array'.
+       Cast the value pointers to VALUE_TYPE."""
+    nelts = int(array['nelts'])
+    elts = array['elts'].reinterpret_cast(value_type.pointer())
+    for i in range(nelts):
+        yield str(i), elts[i]
 
 ########################################################################
 
@@ -179,23 +187,100 @@ class SvnStringPrinter:
     def display_hint(self):
         return 'string'
 
+class SvnMergeRangePrinter:
+    def __init__(self, val):
+        if val.type.code == gdb.TYPE_CODE_PTR and val:
+            self.val = val.dereference()
+        else:
+            self.val = val
+
+    def to_string(self):
+        if not self.val:
+            return 'NULL'
+
+        r = self.val
+        rs = str(r['start']) + '-' + str(r['end'])
+        if not r['inheritable']:
+          rs += '*'
+        return rs
+
+    def display_hint(self):
+        return 'string'
+
+class SvnRangelistPrinter:
+    def __init__(self, val):
+        if val.type.code == gdb.TYPE_CODE_PTR and val:
+            self.array = val.dereference()
+        else:
+            self.array = val
+        self.svn_merge_range_t = gdb.lookup_type('svn_merge_range_t')
+
+    def to_string(self):
+        if not self.array:
+            return 'NULL'
+
+        nelts = int(self.array['nelts'])
+        s = ''
+
+        # We can probably iterate more simply by something like
+        # "for i, rs in children_of_apr_array(self.array,
+        #                 self.svn_merge_range_t.pointer())"
+        # but I haven't tested that yet.
+        elts = self.array['elts'].reinterpret_cast(
+                                    self.svn_merge_range_t.pointer().pointer())
+        for i in range(nelts):
+            rs = SvnMergeRangePrinter(elts[i].dereference()).to_string()
+            if i:
+              s += ','
+            s += rs
+        return s
+
+    def display_hint(self):
+        return 'string'
+
+class SvnMergeinfoPrinter:
+    """for svn_mergeinfo_t"""
+    def __init__(self, val):
+        self.hash_p = val
+        self.svn_rangelist_t = gdb.lookup_type('svn_rangelist_t')
+
+    def to_string(self):
+        if self.hash_p == 0:
+            return 'NULL'
+        return None
+        #return 'mergeinfo[' + str(apr_hash_count(self.hash_p)) + ' paths]'
+
+    def children(self):
+        if self.hash_p == 0:
+            # Return [] here so GDB prints just the 'NULL' of to_string();
+            # returning 'None' here would give a 'not iterable' error.
+            return []
+        return children_as_map(
+                 children_of_apr_hash(self.hash_p,
+                                      self.svn_rangelist_t.pointer()))
+
+    def display_hint(self):
+        return 'map'
+
 class SvnMergeinfoCatalogPrinter:
     """for svn_mergeinfo_catalog_t"""
     def __init__(self, val):
         self.hash_p = val
+        self.svn_mergeinfo_t = gdb.lookup_type('svn_mergeinfo_t')
 
     def to_string(self):
         if self.hash_p == 0:
             return 'NULL'
-        return 'mergeinfo catalog of ' + str(apr_hash_count(self.hash_p)) + ' items'
+        return 'mergeinfo_catalog[' + str(apr_hash_count(self.hash_p)) + ' paths]'
 
     def children(self):
         if self.hash_p == 0:
             # Return [] here so GDB prints just the 'NULL' of to_string();
             # returning 'None' here would give a 'not iterable' error.
             return []
-        mergeinfoType = gdb.lookup_type('svn_mergeinfo_t')
-        return children_as_map(children_of_apr_hash(self.hash_p, mergeinfoType))
+
+        return children_as_map(
+                 children_of_apr_hash(self.hash_p, self.svn_mergeinfo_t))
 
     def display_hint(self):
         return 'map'
@@ -271,6 +356,16 @@ def build_libsvn_printers():
                                SvnStringPrinter)
     libsvn_printer2.add_printer('svn_client__pathrev_t', r'^svn_client__pathrev_t$',
                                 SvnPathrevPrinter)
+    libsvn_printer2.add_printer('svn_merge_range_t', r'^svn_merge_range_t$',
+                                SvnMergeRangePrinter)
+    libsvn_printer2.add_printer('svn_merge_range_t *', r'^svn_merge_range_t \*$',
+                                SvnMergeRangePrinter)
+    libsvn_printer2.add_printer('svn_rangelist_t', r'^svn_rangelist_t$',
+                                SvnRangelistPrinter)
+    libsvn_printer2.add_printer('svn_rangelist_t *', r'^svn_rangelist_t \*$',
+                                SvnRangelistPrinter)
+    libsvn_printer2.add_printer('svn_mergeinfo_t', r'^svn_mergeinfo_t$',
+                                SvnMergeinfoPrinter)
     libsvn_printer2.add_printer('svn_mergeinfo_catalog_t', r'^svn_mergeinfo_catalog_t$',
                                 SvnMergeinfoCatalogPrinter)
 
